Coverage Report

Created: 2025-12-14 06:30

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
2
dns__db_initialize(void) {
77
2
  isc_rwlock_init(&implock);
78
79
2
  ISC_LIST_INIT(implementations);
80
81
2
  qpimp = (dns_dbimplementation_t){
82
2
    .name = "qpcache",
83
2
    .create = dns__qpcache_create,
84
2
    .link = ISC_LINK_INITIALIZER,
85
2
  };
86
87
2
  qpzoneimp = (dns_dbimplementation_t){
88
2
    .name = "qpzone",
89
2
    .create = dns__qpzone_create,
90
2
    .link = ISC_LINK_INITIALIZER,
91
2
  };
92
93
2
  ISC_LIST_APPEND(implementations, &qpimp, link);
94
2
  ISC_LIST_APPEND(implementations, &qpzoneimp, link);
95
2
}
96
97
void
98
0
dns__db_shutdown(void) {
99
0
  isc_rwlock_destroy(&implock);
100
0
}
101
102
static dns_dbimplementation_t *
103
0
impfind(const char *name) {
104
0
  ISC_LIST_FOREACH(implementations, imp, link) {
105
0
    if (strcasecmp(name, imp->name) == 0) {
106
0
      return imp;
107
0
    }
108
0
  }
109
0
  return NULL;
110
0
}
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
0
        char *argv[], dns_db_t **dbp) {
123
0
  dns_dbimplementation_t *impinfo = NULL;
124
125
  /*
126
   * Create a new database using implementation 'db_type'.
127
   */
128
129
0
  REQUIRE(dbp != NULL && *dbp == NULL);
130
0
  REQUIRE(dns_name_isabsolute(origin));
131
132
0
  RWLOCK(&implock, isc_rwlocktype_read);
133
0
  impinfo = impfind(db_type);
134
0
  if (impinfo != NULL) {
135
0
    isc_result_t result;
136
0
    result = ((impinfo->create)(mctx, origin, type, rdclass, argc,
137
0
              argv, impinfo->driverarg, dbp));
138
0
    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
0
    return result;
145
0
  }
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
0
dns__db_destroy(dns_db_t *db) {
157
0
  (db->methods->destroy)(db);
158
0
}
159
160
#if DNS_DB_TRACE
161
ISC_REFCOUNT_TRACE_IMPL(dns_db, dns__db_destroy);
162
#else
163
0
ISC_REFCOUNT_IMPL(dns_db, dns__db_destroy);
Unexecuted instantiation: dns_db_ref
Unexecuted instantiation: dns_db_unref
Unexecuted instantiation: dns_db_detach
164
0
#endif
165
0
166
0
bool
167
0
dns_db_iscache(dns_db_t *db) {
168
  /*
169
   * Does 'db' have cache semantics?
170
   */
171
172
0
  REQUIRE(DNS_DB_VALID(db));
173
174
0
  if ((db->attributes & DNS_DBATTR_CACHE) != 0) {
175
0
    return true;
176
0
  }
177
178
0
  return false;
179
0
}
180
181
bool
182
0
dns_db_iszone(dns_db_t *db) {
183
  /*
184
   * Does 'db' have zone semantics?
185
   */
186
187
0
  REQUIRE(DNS_DB_VALID(db));
188
189
0
  if ((db->attributes & (DNS_DBATTR_CACHE | DNS_DBATTR_STUB)) == 0) {
190
0
    return true;
191
0
  }
192
193
0
  return false;
194
0
}
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
0
dns_db_issecure(dns_db_t *db) {
213
  /*
214
   * Is 'db' secure?
215
   */
216
217
0
  REQUIRE(DNS_DB_VALID(db));
218
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
219
220
0
  if (db->methods->issecure != NULL) {
221
0
    return (db->methods->issecure)(db);
222
0
  }
223
0
  return false;
224
0
}
225
226
bool
227
0
dns_db_ispersistent(dns_db_t *db) {
228
  /*
229
   * Is 'db' persistent?
230
   */
231
232
0
  REQUIRE(DNS_DB_VALID(db));
233
234
0
  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
0
  return false;
240
0
}
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
0
dns_db_beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
266
  /*
267
   * Begin loading 'db'.
268
   */
269
270
0
  REQUIRE(DNS_DB_VALID(db));
271
0
  REQUIRE(DNS_CALLBACK_VALID(callbacks));
272
273
0
  if (db->methods->beginload != NULL) {
274
0
    return (db->methods->beginload)(db, callbacks);
275
0
  }
276
0
  return ISC_R_NOTIMPLEMENTED;
277
0
}
278
279
isc_result_t
280
0
dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
281
  /*
282
   * Finish loading 'db'.
283
   */
284
285
0
  REQUIRE(DNS_DB_VALID(db));
286
0
  REQUIRE(DNS_CALLBACK_VALID(callbacks));
287
0
  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
0
  call_updatenotify(db);
295
296
0
  if (db->methods->endload != NULL) {
297
0
    return (db->methods->endload)(db, callbacks);
298
0
  }
299
300
0
  return ISC_R_NOTIMPLEMENTED;
301
0
}
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
0
dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
396
  /*
397
   * Open the current version for reading.
398
   */
399
400
0
  REQUIRE(DNS_DB_VALID(db));
401
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
402
0
  REQUIRE(versionp != NULL && *versionp == NULL);
403
404
0
  (db->methods->currentversion)(db, versionp);
405
0
}
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
0
         bool commit DNS__DB_FLARG) {
443
  /*
444
   * Close version '*versionp'.
445
   */
446
447
0
  REQUIRE(DNS_DB_VALID(db));
448
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
449
0
  REQUIRE(versionp != NULL && *versionp != NULL);
450
451
0
  (db->methods->closeversion)(db, versionp, commit DNS__DB_FLARG_PASS);
452
453
0
  if (commit) {
454
0
    call_updatenotify(db);
455
0
  }
456
457
0
  ENSURE(*versionp == NULL);
458
0
}
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
0
     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
0
  REQUIRE(DNS_DB_VALID(db));
474
0
  REQUIRE(nodep != NULL && *nodep == NULL);
475
476
0
  if (db->methods->findnode != NULL) {
477
0
    return (db->methods->findnode)(db, name, create, methods,
478
0
                 clientinfo,
479
0
                 nodep DNS__DB_FLARG_PASS);
480
0
  }
481
0
  return ISC_R_NOTIMPLEMENTED;
482
0
}
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
0
       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
0
  REQUIRE(DNS_DB_VALID(db));
511
0
  REQUIRE(type != dns_rdatatype_rrsig);
512
0
  REQUIRE(nodep == NULL || *nodep == NULL);
513
0
  REQUIRE(dns_name_hasbuffer(foundname));
514
0
  REQUIRE(rdataset == NULL || (DNS_RDATASET_VALID(rdataset) &&
515
0
             !dns_rdataset_isassociated(rdataset)));
516
0
  REQUIRE(sigrdataset == NULL ||
517
0
    (DNS_RDATASET_VALID(sigrdataset) &&
518
0
     !dns_rdataset_isassociated(sigrdataset)));
519
520
0
  if (db->methods->find != NULL) {
521
0
    return (db->methods->find)(db, name, version, type, options,
522
0
             now, nodep, foundname, methods,
523
0
             clientinfo, rdataset,
524
0
             sigrdataset DNS__DB_FLARG_PASS);
525
0
  }
526
0
  return ISC_R_NOTIMPLEMENTED;
527
0
}
528
529
isc_result_t
530
dns__db_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
531
        isc_stdtime_t now, dns_dbnode_t **nodep,
532
        dns_name_t *foundname, dns_name_t *dcname,
533
        dns_rdataset_t *rdataset,
534
0
        dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
535
  /*
536
   * Find the deepest known zonecut which encloses 'name' in 'db'.
537
   * foundname is the zonecut, dcname is the deepest name we have
538
   * in database that is part of queried name.
539
   */
540
541
0
  REQUIRE(DNS_DB_VALID(db));
542
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
543
0
  REQUIRE(nodep == NULL || *nodep == NULL);
544
0
  REQUIRE(dns_name_hasbuffer(foundname));
545
0
  REQUIRE(sigrdataset == NULL ||
546
0
    (DNS_RDATASET_VALID(sigrdataset) &&
547
0
     !dns_rdataset_isassociated(sigrdataset)));
548
549
0
  if (db->methods->findzonecut != NULL) {
550
0
    return (db->methods->findzonecut)(
551
0
      db, name, options, now, nodep, foundname, dcname,
552
0
      rdataset, sigrdataset DNS__DB_FLARG_PASS);
553
0
  }
554
0
  return ISC_R_NOTIMPLEMENTED;
555
0
}
556
557
void
558
0
dns__db_attachnode(dns_dbnode_t *source, dns_dbnode_t **targetp DNS__DB_FLARG) {
559
  /*
560
   * Attach *targetp to source.
561
   */
562
563
0
  REQUIRE(source != NULL);
564
0
  REQUIRE(targetp != NULL && *targetp == NULL);
565
0
  REQUIRE(source->methods != NULL && source->methods->attachnode != NULL);
566
567
0
  (source->methods->attachnode)(source, targetp DNS__DB_FLARG_PASS);
568
0
}
569
570
void
571
0
dns__db_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG) {
572
  /*
573
   * Detach *nodep from its node.
574
   */
575
576
0
  REQUIRE(nodep != NULL && *nodep != NULL);
577
0
  dns_dbnode_t *node = *nodep;
578
0
  REQUIRE(node->methods != NULL && node->methods->detachnode != NULL);
579
580
0
  (node->methods->detachnode)(nodep DNS__DB_FLARG_PASS);
581
582
0
  ENSURE(*nodep == NULL);
583
0
}
584
585
void
586
dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep,
587
0
        dns_dbnode_t **targetp) {
588
0
  REQUIRE(DNS_DB_VALID(db));
589
0
  REQUIRE(targetp != NULL && *targetp == NULL);
590
0
  REQUIRE(sourcep != NULL && *sourcep != NULL);
591
592
0
  *targetp = *sourcep;
593
0
  *sourcep = NULL;
594
0
}
595
596
/***
597
 *** DB Iterator Creation
598
 ***/
599
600
isc_result_t
601
dns_db_createiterator(dns_db_t *db, unsigned int flags,
602
0
          dns_dbiterator_t **iteratorp) {
603
  /*
604
   * Create an iterator for version 'version' of 'db'.
605
   */
606
607
0
  REQUIRE(DNS_DB_VALID(db));
608
0
  REQUIRE(iteratorp != NULL && *iteratorp == NULL);
609
0
  REQUIRE((flags & (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3)) !=
610
0
    (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3));
611
612
0
  if (db->methods->createiterator != NULL) {
613
0
    return db->methods->createiterator(db, flags, iteratorp);
614
0
  }
615
0
  return ISC_R_NOTIMPLEMENTED;
616
0
}
617
618
/***
619
 *** Rdataset Methods
620
 ***/
621
622
isc_result_t
623
dns__db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
624
         dns_rdatatype_t type, dns_rdatatype_t covers,
625
         isc_stdtime_t now, dns_rdataset_t *rdataset,
626
0
         dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
627
0
  REQUIRE(DNS_DB_VALID(db));
628
0
  REQUIRE(node != NULL);
629
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
630
0
  REQUIRE(!dns_rdataset_isassociated(rdataset));
631
0
  REQUIRE(covers == dns_rdatatype_none || type == dns_rdatatype_rrsig);
632
0
  REQUIRE(type != dns_rdatatype_any);
633
0
  REQUIRE(sigrdataset == NULL ||
634
0
    (DNS_RDATASET_VALID(sigrdataset) &&
635
0
     !dns_rdataset_isassociated(sigrdataset)));
636
637
0
  return (db->methods->findrdataset)(db, node, version, type, covers, now,
638
0
             rdataset,
639
0
             sigrdataset DNS__DB_FLARG_PASS);
640
0
}
641
642
isc_result_t
643
dns__db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
644
         unsigned int options, isc_stdtime_t now,
645
0
         dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
646
  /*
647
   * Make '*iteratorp' an rdataset iteratator for all rdatasets at
648
   * 'node' in version 'version' of 'db'.
649
   */
650
651
0
  REQUIRE(DNS_DB_VALID(db));
652
0
  REQUIRE(iteratorp != NULL && *iteratorp == NULL);
653
654
0
  return (db->methods->allrdatasets)(db, node, version, options, now,
655
0
             iteratorp DNS__DB_FLARG_PASS);
656
0
}
657
658
isc_result_t
659
dns__db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
660
        isc_stdtime_t now, dns_rdataset_t *rdataset,
661
        unsigned int options,
662
0
        dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
663
  /*
664
   * Add 'rdataset' to 'node' in version 'version' of 'db'.
665
   */
666
667
0
  REQUIRE(DNS_DB_VALID(db));
668
0
  REQUIRE(node != NULL);
669
0
  REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
670
0
    ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL &&
671
0
     (options & DNS_DBADD_MERGE) == 0));
672
0
  REQUIRE((options & DNS_DBADD_EXACT) == 0 ||
673
0
    (options & DNS_DBADD_MERGE) != 0);
674
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
675
0
  REQUIRE(dns_rdataset_isassociated(rdataset));
676
0
  REQUIRE(rdataset->rdclass == db->rdclass);
677
0
  REQUIRE(addedrdataset == NULL ||
678
0
    (DNS_RDATASET_VALID(addedrdataset) &&
679
0
     !dns_rdataset_isassociated(addedrdataset)));
680
681
0
  if (db->methods->addrdataset != NULL) {
682
0
    return (db->methods->addrdataset)(
683
0
      db, node, version, now, rdataset, options,
684
0
      addedrdataset DNS__DB_FLARG_PASS);
685
0
  }
686
0
  return ISC_R_NOTIMPLEMENTED;
687
0
}
688
689
isc_result_t
690
dns__db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
691
       dns_dbversion_t *version, dns_rdataset_t *rdataset,
692
       unsigned int options,
693
0
       dns_rdataset_t *newrdataset DNS__DB_FLARG) {
694
  /*
695
   * Remove any rdata in 'rdataset' from 'node' in version 'version' of
696
   * 'db'.
697
   */
698
699
0
  REQUIRE(DNS_DB_VALID(db));
700
0
  REQUIRE(node != NULL);
701
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL);
702
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
703
0
  REQUIRE(dns_rdataset_isassociated(rdataset));
704
0
  REQUIRE(rdataset->rdclass == db->rdclass);
705
0
  REQUIRE(newrdataset == NULL ||
706
0
    (DNS_RDATASET_VALID(newrdataset) &&
707
0
     !dns_rdataset_isassociated(newrdataset)));
708
709
0
  if (db->methods->subtractrdataset != NULL) {
710
0
    return (db->methods->subtractrdataset)(
711
0
      db, node, version, rdataset, options,
712
0
      newrdataset DNS__DB_FLARG_PASS);
713
0
  }
714
0
  return ISC_R_NOTIMPLEMENTED;
715
0
}
716
717
isc_result_t
718
dns__db_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
719
           dns_dbversion_t *version, dns_rdatatype_t type,
720
0
           dns_rdatatype_t covers DNS__DB_FLARG) {
721
  /*
722
   * Make it so that no rdataset of type 'type' exists at 'node' in
723
   * version version 'version' of 'db'.
724
   */
725
726
0
  REQUIRE(DNS_DB_VALID(db));
727
0
  REQUIRE(node != NULL);
728
0
  REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
729
0
    ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL));
730
731
0
  if (db->methods->deleterdataset != NULL) {
732
0
    return (db->methods->deleterdataset)(db, node, version, type,
733
0
                 covers DNS__DB_FLARG_PASS);
734
0
  }
735
0
  return ISC_R_NOTIMPLEMENTED;
736
0
}
737
738
isc_result_t
739
0
dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, uint32_t *serialp) {
740
0
  isc_result_t result;
741
0
  dns_dbnode_t *node = NULL;
742
0
  dns_rdataset_t rdataset;
743
0
  dns_rdata_t rdata = DNS_RDATA_INIT;
744
0
  isc_buffer_t buffer;
745
746
0
  REQUIRE(dns_db_iszone(db) || dns_db_isstub(db));
747
748
0
  RETERR(dns_db_findnode(db, dns_db_origin(db), false, &node));
749
750
0
  dns_rdataset_init(&rdataset);
751
0
  result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
752
0
             (isc_stdtime_t)0, &rdataset, NULL);
753
0
  if (result != ISC_R_SUCCESS) {
754
0
    goto freenode;
755
0
  }
756
757
0
  result = dns_rdataset_first(&rdataset);
758
0
  if (result != ISC_R_SUCCESS) {
759
0
    goto freerdataset;
760
0
  }
761
0
  dns_rdataset_current(&rdataset, &rdata);
762
0
  result = dns_rdataset_next(&rdataset);
763
0
  INSIST(result == ISC_R_NOMORE);
764
765
0
  INSIST(rdata.length > 20);
766
0
  isc_buffer_init(&buffer, rdata.data, rdata.length);
767
0
  isc_buffer_add(&buffer, rdata.length);
768
0
  isc_buffer_forward(&buffer, rdata.length - 20);
769
0
  *serialp = isc_buffer_getuint32(&buffer);
770
771
0
  result = ISC_R_SUCCESS;
772
773
0
freerdataset:
774
0
  dns_rdataset_disassociate(&rdataset);
775
776
0
freenode:
777
0
  dns_db_detachnode(&node);
778
0
  return result;
779
0
}
780
781
unsigned int
782
0
dns_db_nodecount(dns_db_t *db) {
783
0
  REQUIRE(DNS_DB_VALID(db));
784
785
0
  if (db->methods->nodecount != NULL) {
786
0
    return (db->methods->nodecount)(db);
787
0
  }
788
0
  return 0;
789
0
}
790
791
isc_result_t
792
dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg,
793
0
    isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
794
0
  dns_dbimplementation_t *imp;
795
796
0
  REQUIRE(name != NULL);
797
0
  REQUIRE(dbimp != NULL && *dbimp == NULL);
798
799
0
  RWLOCK(&implock, isc_rwlocktype_write);
800
0
  imp = impfind(name);
801
0
  if (imp != NULL) {
802
0
    RWUNLOCK(&implock, isc_rwlocktype_write);
803
0
    return ISC_R_EXISTS;
804
0
  }
805
806
0
  imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t));
807
0
  imp->name = name;
808
0
  imp->create = create;
809
0
  imp->mctx = NULL;
810
0
  imp->driverarg = driverarg;
811
0
  isc_mem_attach(mctx, &imp->mctx);
812
0
  ISC_LINK_INIT(imp, link);
813
0
  ISC_LIST_APPEND(implementations, imp, link);
814
0
  RWUNLOCK(&implock, isc_rwlocktype_write);
815
816
0
  *dbimp = imp;
817
818
0
  return ISC_R_SUCCESS;
819
0
}
820
821
void
822
0
dns_db_unregister(dns_dbimplementation_t **dbimp) {
823
0
  dns_dbimplementation_t *imp;
824
825
0
  REQUIRE(dbimp != NULL && *dbimp != NULL);
826
827
0
  imp = *dbimp;
828
0
  *dbimp = NULL;
829
0
  RWLOCK(&implock, isc_rwlocktype_write);
830
0
  ISC_LIST_UNLINK(implementations, imp, link);
831
0
  isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_dbimplementation_t));
832
0
  RWUNLOCK(&implock, isc_rwlocktype_write);
833
0
  ENSURE(*dbimp == NULL);
834
0
}
835
836
isc_result_t
837
0
dns__db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
838
0
  REQUIRE(DNS_DB_VALID(db));
839
0
  REQUIRE(dns_db_iszone(db));
840
0
  REQUIRE(nodep != NULL && *nodep == NULL);
841
842
0
  if (db->methods->getoriginnode != NULL) {
843
0
    return (db->methods->getoriginnode)(db,
844
0
                nodep DNS__DB_FLARG_PASS);
845
0
  } else if (db->methods->findnode != NULL) {
846
0
    return (db->methods->findnode)(db, &db->origin, false, NULL,
847
0
                 NULL, nodep DNS__DB_FLARG_PASS);
848
0
  }
849
850
0
  return ISC_R_NOTFOUND;
851
0
}
852
853
dns_stats_t *
854
0
dns_db_getrrsetstats(dns_db_t *db) {
855
0
  REQUIRE(DNS_DB_VALID(db));
856
857
0
  if (db->methods->getrrsetstats != NULL) {
858
0
    return (db->methods->getrrsetstats)(db);
859
0
  }
860
861
0
  return NULL;
862
0
}
863
864
isc_result_t
865
0
dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats) {
866
0
  REQUIRE(DNS_DB_VALID(db));
867
868
0
  if (db->methods->setcachestats != NULL) {
869
0
    return (db->methods->setcachestats)(db, stats);
870
0
  }
871
872
0
  return ISC_R_NOTIMPLEMENTED;
873
0
}
874
875
isc_result_t
876
dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
877
        dns_hash_t *hash, uint8_t *flags,
878
        uint16_t *iterations, unsigned char *salt,
879
0
        size_t *salt_length) {
880
0
  REQUIRE(DNS_DB_VALID(db));
881
0
  REQUIRE(dns_db_iszone(db));
882
883
0
  if (db->methods->getnsec3parameters != NULL) {
884
0
    return (db->methods->getnsec3parameters)(db, version, hash,
885
0
               flags, iterations,
886
0
               salt, salt_length);
887
0
  }
888
889
0
  return ISC_R_NOTFOUND;
890
0
}
891
892
isc_result_t
893
dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
894
0
         uint64_t *bytes) {
895
0
  REQUIRE(DNS_DB_VALID(db));
896
0
  REQUIRE(dns_db_iszone(db));
897
898
0
  if (db->methods->getsize != NULL) {
899
0
    return (db->methods->getsize)(db, version, records, bytes);
900
0
  }
901
902
0
  return ISC_R_NOTFOUND;
903
0
}
904
905
isc_result_t
906
dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
907
0
          isc_stdtime_t resign) {
908
0
  if (db->methods->setsigningtime != NULL) {
909
0
    return (db->methods->setsigningtime)(db, rdataset, resign);
910
0
  }
911
0
  return ISC_R_NOTIMPLEMENTED;
912
0
}
913
914
isc_result_t
915
dns_db_getsigningtime(dns_db_t *db, isc_stdtime_t *resign, dns_name_t *name,
916
0
          dns_typepair_t *typepair) {
917
0
  if (db->methods->getsigningtime != NULL) {
918
0
    return (db->methods->getsigningtime)(db, resign, name,
919
0
                 typepair);
920
0
  }
921
0
  return ISC_R_NOTFOUND;
922
0
}
923
924
static void
925
0
call_updatenotify(dns_db_t *db) {
926
0
  rcu_read_lock();
927
0
  struct cds_lfht *update_listeners =
928
0
    rcu_dereference(db->update_listeners);
929
0
  if (update_listeners != NULL) {
930
0
    struct cds_lfht_iter iter;
931
0
    dns_dbonupdatelistener_t *listener;
932
0
    cds_lfht_for_each_entry(update_listeners, &iter, listener,
933
0
          ht_node) {
934
0
      if (!cds_lfht_is_node_deleted(&listener->ht_node)) {
935
0
        listener->onupdate(db, listener->onupdate_arg);
936
0
      }
937
0
    }
938
0
  }
939
0
  rcu_read_unlock();
940
0
}
941
942
static void
943
0
updatenotify_free(struct rcu_head *rcu_head) {
944
0
  dns_dbonupdatelistener_t *listener =
945
0
    caa_container_of(rcu_head, dns_dbonupdatelistener_t, rcu_head);
946
0
  isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
947
0
}
948
949
static int
950
0
updatenotify_match(struct cds_lfht_node *ht_node, const void *_key) {
951
0
  const dns_dbonupdatelistener_t *listener =
952
0
    caa_container_of(ht_node, dns_dbonupdatelistener_t, ht_node);
953
0
  const dns_dbonupdatelistener_t *key = _key;
954
955
0
  return listener->onupdate == key->onupdate &&
956
0
         listener->onupdate_arg == key->onupdate_arg;
957
0
}
958
959
/*
960
 * Attach a notify-on-update function the database
961
 */
962
void
963
dns_db_updatenotify_register(dns_db_t *db, dns_dbupdate_callback_t fn,
964
0
           void *fn_arg) {
965
0
  REQUIRE(db != NULL);
966
0
  REQUIRE(fn != NULL);
967
968
0
  dns_dbonupdatelistener_t key = { .onupdate = fn,
969
0
           .onupdate_arg = fn_arg };
970
0
  uint32_t hash = isc_hash32(&key, sizeof(key), true);
971
0
  dns_dbonupdatelistener_t *listener = isc_mem_get(db->mctx,
972
0
               sizeof(*listener));
973
0
  *listener = key;
974
975
0
  isc_mem_attach(db->mctx, &listener->mctx);
976
977
0
  rcu_read_lock();
978
0
  struct cds_lfht *update_listeners =
979
0
    rcu_dereference(db->update_listeners);
980
0
  INSIST(update_listeners != NULL);
981
0
  struct cds_lfht_node *ht_node =
982
0
    cds_lfht_add_unique(update_listeners, hash, updatenotify_match,
983
0
            &key, &listener->ht_node);
984
0
  rcu_read_unlock();
985
986
0
  if (ht_node != &listener->ht_node) {
987
0
    updatenotify_free(&listener->rcu_head);
988
0
  }
989
0
}
990
991
void
992
dns_db_updatenotify_unregister(dns_db_t *db, dns_dbupdate_callback_t fn,
993
0
             void *fn_arg) {
994
0
  REQUIRE(db != NULL);
995
996
0
  dns_dbonupdatelistener_t key = { .onupdate = fn,
997
0
           .onupdate_arg = fn_arg };
998
0
  uint32_t hash = isc_hash32(&key, sizeof(key), true);
999
0
  struct cds_lfht_iter iter;
1000
1001
0
  rcu_read_lock();
1002
0
  struct cds_lfht *update_listeners =
1003
0
    rcu_dereference(db->update_listeners);
1004
0
  INSIST(update_listeners != NULL);
1005
0
  cds_lfht_lookup(update_listeners, hash, updatenotify_match, &key,
1006
0
      &iter);
1007
1008
0
  struct cds_lfht_node *ht_node = cds_lfht_iter_get_node(&iter);
1009
0
  if (ht_node != NULL && !cds_lfht_del(update_listeners, ht_node)) {
1010
0
    dns_dbonupdatelistener_t *listener = caa_container_of(
1011
0
      ht_node, dns_dbonupdatelistener_t, ht_node);
1012
0
    call_rcu(&listener->rcu_head, updatenotify_free);
1013
0
  }
1014
0
  rcu_read_unlock();
1015
0
}
1016
1017
isc_result_t
1018
0
dns_db_setservestalettl(dns_db_t *db, dns_ttl_t ttl) {
1019
0
  REQUIRE(DNS_DB_VALID(db));
1020
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1021
1022
0
  if (db->methods->setservestalettl != NULL) {
1023
0
    return (db->methods->setservestalettl)(db, ttl);
1024
0
  }
1025
0
  return ISC_R_NOTIMPLEMENTED;
1026
0
}
1027
1028
isc_result_t
1029
0
dns_db_getservestalettl(dns_db_t *db, dns_ttl_t *ttl) {
1030
0
  REQUIRE(DNS_DB_VALID(db));
1031
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1032
1033
0
  if (db->methods->getservestalettl != NULL) {
1034
0
    return (db->methods->getservestalettl)(db, ttl);
1035
0
  }
1036
0
  return ISC_R_NOTIMPLEMENTED;
1037
0
}
1038
1039
isc_result_t
1040
0
dns_db_setservestalerefresh(dns_db_t *db, uint32_t interval) {
1041
0
  REQUIRE(DNS_DB_VALID(db));
1042
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1043
1044
0
  if (db->methods->setservestalerefresh != NULL) {
1045
0
    return (db->methods->setservestalerefresh)(db, interval);
1046
0
  }
1047
0
  return ISC_R_NOTIMPLEMENTED;
1048
0
}
1049
1050
isc_result_t
1051
0
dns_db_getservestalerefresh(dns_db_t *db, uint32_t *interval) {
1052
0
  REQUIRE(DNS_DB_VALID(db));
1053
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1054
1055
0
  if (db->methods->getservestalerefresh != NULL) {
1056
0
    return (db->methods->getservestalerefresh)(db, interval);
1057
0
  }
1058
0
  return ISC_R_NOTIMPLEMENTED;
1059
0
}
1060
1061
isc_result_t
1062
0
dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
1063
0
  REQUIRE(dns_db_iszone(db));
1064
0
  REQUIRE(stats != NULL);
1065
1066
0
  if (db->methods->setgluecachestats != NULL) {
1067
0
    return (db->methods->setgluecachestats)(db, stats);
1068
0
  }
1069
1070
0
  return ISC_R_NOTIMPLEMENTED;
1071
0
}
1072
1073
isc_result_t
1074
dns_db_addglue(dns_db_t *db, dns_dbversion_t *version, dns_rdataset_t *rdataset,
1075
0
         dns_message_t *msg) {
1076
0
  REQUIRE(DNS_DB_VALID(db));
1077
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
1078
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
1079
0
  REQUIRE(rdataset->methods != NULL);
1080
0
  REQUIRE(rdataset->type == dns_rdatatype_ns);
1081
1082
0
  if (db->methods->addglue != NULL) {
1083
0
    (db->methods->addglue)(db, version, rdataset, msg);
1084
1085
0
    return ISC_R_SUCCESS;
1086
0
  }
1087
1088
0
  return ISC_R_NOTIMPLEMENTED;
1089
0
}
1090
1091
void
1092
0
dns_db_expiredata(dns_dbnode_t *node, void *data) {
1093
0
  REQUIRE(node != NULL && node->methods != NULL);
1094
0
  if (node->methods->expiredata != NULL) {
1095
0
    (node->methods->expiredata)(node, data);
1096
0
  }
1097
0
}
1098
1099
void
1100
0
dns_db_deletedata(dns_dbnode_t *node, void *data) {
1101
0
  REQUIRE(node != NULL && node->methods != NULL);
1102
0
  if (node->methods->deletedata != NULL) {
1103
0
    (node->methods->deletedata)(node, data);
1104
0
  }
1105
0
}
1106
1107
void
1108
0
dns_db_setmaxrrperset(dns_db_t *db, uint32_t value) {
1109
0
  REQUIRE(DNS_DB_VALID(db));
1110
1111
0
  if (db->methods->setmaxrrperset != NULL) {
1112
0
    (db->methods->setmaxrrperset)(db, value);
1113
0
  }
1114
0
}
1115
1116
void
1117
0
dns_db_setmaxtypepername(dns_db_t *db, uint32_t value) {
1118
0
  REQUIRE(DNS_DB_VALID(db));
1119
1120
0
  if (db->methods->setmaxtypepername != NULL) {
1121
0
    (db->methods->setmaxtypepername)(db, value);
1122
0
  }
1123
0
}
1124
1125
void
1126
dns__db_logtoomanyrecords(dns_db_t *db, const dns_name_t *name,
1127
        dns_rdatatype_t type, const char *op,
1128
0
        uint32_t limit) {
1129
0
  char namebuf[DNS_NAME_FORMATSIZE];
1130
0
  char originbuf[DNS_NAME_FORMATSIZE];
1131
0
  char typebuf[DNS_RDATATYPE_FORMATSIZE];
1132
0
  char clsbuf[DNS_RDATACLASS_FORMATSIZE];
1133
1134
0
  dns_name_format(name, namebuf, sizeof(namebuf));
1135
0
  dns_name_format(&db->origin, originbuf, sizeof(originbuf));
1136
0
  dns_rdatatype_format(type, typebuf, sizeof(typebuf));
1137
0
  dns_rdataclass_format(db->rdclass, clsbuf, sizeof(clsbuf));
1138
1139
0
  isc_log_write(
1140
0
    DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB, ISC_LOG_ERROR,
1141
0
    "error %s '%s/%s' in '%s/%s' (%s): %s (must not exceed %u)", op,
1142
0
    namebuf, typebuf, originbuf, clsbuf,
1143
0
    (db->attributes & DNS_DBATTR_CACHE) != 0 ? "cache" : "zone",
1144
0
    isc_result_totext(DNS_R_TOOMANYRECORDS), limit);
1145
0
}
1146
1147
isc_result_t
1148
0
dns_db_getzoneversion(dns_db_t *db, isc_buffer_t *b) {
1149
0
  REQUIRE(db != NULL);
1150
0
  REQUIRE(b != NULL);
1151
1152
0
  if (db->methods->getzoneversion != NULL) {
1153
0
    return (db->methods->getzoneversion)(db, b);
1154
0
  }
1155
0
  return ISC_R_NOTIMPLEMENTED;
1156
0
}