Coverage Report

Created: 2026-08-13 07:07

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