Coverage Report

Created: 2025-11-09 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/qpzone.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
#include <inttypes.h>
17
#include <stdalign.h>
18
#include <stdbool.h>
19
#include <sys/mman.h>
20
21
#include <isc/ascii.h>
22
#include <isc/async.h>
23
#include <isc/atomic.h>
24
#include <isc/file.h>
25
#include <isc/heap.h>
26
#include <isc/hex.h>
27
#include <isc/log.h>
28
#include <isc/mem.h>
29
#include <isc/mutex.h>
30
#include <isc/os.h>
31
#include <isc/random.h>
32
#include <isc/refcount.h>
33
#include <isc/result.h>
34
#include <isc/rwlock.h>
35
#include <isc/serial.h>
36
#include <isc/stdio.h>
37
#include <isc/string.h>
38
#include <isc/time.h>
39
#include <isc/urcu.h>
40
#include <isc/util.h>
41
42
#include <dns/callbacks.h>
43
#include <dns/db.h>
44
#include <dns/dbiterator.h>
45
#include <dns/dnssec.h>
46
#include <dns/fixedname.h>
47
#include <dns/masterdump.h>
48
#include <dns/name.h>
49
#include <dns/nsec.h>
50
#include <dns/nsec3.h>
51
#include <dns/qp.h>
52
#include <dns/rdata.h>
53
#include <dns/rdataset.h>
54
#include <dns/rdatasetiter.h>
55
#include <dns/rdataslab.h>
56
#include <dns/rdatastruct.h>
57
#include <dns/stats.h>
58
#include <dns/time.h>
59
#include <dns/types.h>
60
#include <dns/view.h>
61
#include <dns/zone.h>
62
63
#include "db_p.h"
64
#include "qpzone_p.h"
65
#include "rdataslab_p.h"
66
67
#define CHECK(op)                              \
68
  {                                      \
69
    result = (op);                 \
70
    if (result != ISC_R_SUCCESS) { \
71
      goto failure;          \
72
    }                              \
73
  }
74
75
0
#define HEADERNODE(h) ((qpznode_t *)((h)->node))
76
77
18.8k
#define QPDB_ATTR_LOADED  0x01
78
37.7k
#define QPDB_ATTR_LOADING 0x02
79
80
#define QPDBITER_ORIGIN_NODE(qpdb, iterator) \
81
  ((iterator)->node == (qpdb)->origin)
82
#define QPDBITER_NSEC_ORIGIN_NODE(qpdb, iterator) \
83
  ((iterator)->node == (qpdb)->nsec_origin)
84
#define QPDBITER_NSEC3_ORIGIN_NODE(qpdb, iterator) \
85
0
  ((iterator)->node == (qpdb)->nsec3_origin)
86
87
/*%
88
 * Note that "impmagic" is not the first four bytes of the struct, so
89
 * ISC_MAGIC_VALID cannot be used.
90
 */
91
18.8k
#define QPZONE_DB_MAGIC ISC_MAGIC('Q', 'Z', 'D', 'B')
92
#define VALID_QPZONE(qpdb) \
93
  ((qpdb) != NULL && (qpdb)->common.impmagic == QPZONE_DB_MAGIC)
94
95
typedef struct qpzonedb qpzonedb_t;
96
typedef struct qpznode qpznode_t;
97
98
typedef struct qpzone_bucket {
99
  /* Per-bucket lock. */
100
  isc_rwlock_t lock;
101
102
  /* Padding to prevent false sharing between locks. */
103
  uint8_t __padding[ISC_OS_CACHELINE_SIZE -
104
        (sizeof(isc_rwlock_t)) % ISC_OS_CACHELINE_SIZE];
105
} qpzone_bucket_t;
106
107
static qpzone_bucket_t qpzone_buckets_g[1024];
108
109
typedef struct qpz_changed {
110
  qpznode_t *node;
111
  bool dirty;
112
  ISC_LINK(struct qpz_changed) link;
113
} qpz_changed_t;
114
115
typedef ISC_LIST(qpz_changed_t) qpz_changedlist_t;
116
117
typedef struct qpz_resigned {
118
  dns_slabheader_t *header;
119
  ISC_LINK(struct qpz_resigned) link;
120
} qpz_resigned_t;
121
122
typedef ISC_LIST(qpz_resigned_t) qpz_resignedlist_t;
123
124
typedef struct qpz_version qpz_version_t;
125
struct qpz_version {
126
  /* Not locked */
127
  uint32_t serial;
128
  qpzonedb_t *qpdb;
129
  isc_refcount_t references;
130
  /* Locked by database lock. */
131
  bool writer;
132
  qpz_changedlist_t changed_list;
133
  qpz_resignedlist_t resigned_list;
134
  ISC_LINK(qpz_version_t) link;
135
  bool secure;
136
  bool havensec3;
137
  /* NSEC3 parameters */
138
  dns_hash_t hash;
139
  uint8_t flags;
140
  uint16_t iterations;
141
  uint8_t salt_length;
142
  unsigned char salt[DNS_NSEC3_SALTSIZE];
143
144
  /*
145
   * records and xfrsize are covered by rwlock.
146
   */
147
  isc_rwlock_t rwlock;
148
  uint64_t records;
149
  uint64_t xfrsize;
150
151
  struct cds_wfs_stack glue_stack;
152
};
153
154
typedef ISC_LIST(qpz_version_t) qpz_versionlist_t;
155
156
/* Resigning heap indirection to allow ref counting */
157
typedef struct qpz_heap {
158
  isc_mem_t *mctx;
159
  isc_refcount_t references;
160
  /* Locks the data in this struct */
161
  isc_mutex_t lock;
162
  isc_heap_t *heap;
163
} qpz_heap_t;
164
165
ISC_REFCOUNT_STATIC_DECL(qpz_heap);
166
167
struct qpznode {
168
  DBNODE_FIELDS;
169
170
  qpz_heap_t *heap;
171
  /*
172
   * 'erefs' counts external references held by a caller: for
173
   * example, it could be incremented by dns_db_findnode(),
174
   * and decremented by dns_db_detachnode().
175
   *
176
   * 'references' counts internal references to the node object,
177
   * including the one held by the QP trie so the node won't be
178
   * deleted while it's quiescently stored in the database - even
179
   * though 'erefs' may be zero because no external caller is
180
   * using it at the time.
181
   *
182
   * Generally when 'erefs' is incremented or decremented,
183
   * 'references' is too. When both go to zero (meaning callers
184
   * and the database have both released the object) the object
185
   * is freed.
186
   *
187
   * Whenever 'erefs' is incremented from zero, we also aquire a
188
   * node use reference (see 'qpzonedb->references' below), and
189
   * release it when 'erefs' goes back to zero. This prevents the
190
   * database from being shut down until every caller has released
191
   * all nodes.
192
   */
193
  isc_refcount_t references;
194
  isc_refcount_t erefs;
195
196
  _Atomic(dns_namespace_t) nspace;
197
  atomic_bool havensec;
198
  atomic_bool wild;
199
  atomic_bool delegating;
200
  atomic_bool dirty;
201
202
  struct cds_list_head types_list;
203
  struct cds_list_head *data;
204
};
205
206
struct qpzonedb {
207
  /* Unlocked. */
208
  dns_db_t common;
209
  /* Locks the data in this struct */
210
  isc_rwlock_t lock;
211
212
  /*
213
   * NOTE: 'references' is NOT the global reference counter for
214
   * the database object handled by dns_db_attach() and _detach();
215
   * that one is 'common.references'.
216
   *
217
   * Instead, 'references' counts the number of nodes being used by
218
   * at least one external caller. (It's called 'references' to
219
   * leverage the ISC_REFCOUNT_STATIC macros, but 'nodes_in_use'
220
   * might be a clearer name.)
221
   *
222
   * One additional reference to this counter is held by the database
223
   * object itself. When 'common.references' goes to zero, that
224
   * reference is released. When in turn 'references' goes to zero,
225
   * the database is shut down and freed.
226
   */
227
228
  qpznode_t *origin;
229
  qpznode_t *nsec_origin;
230
  qpznode_t *nsec3_origin;
231
  isc_stats_t *gluecachestats;
232
  /* Locked by lock. */
233
  unsigned int attributes;
234
  uint32_t current_serial;
235
  uint32_t least_serial;
236
  uint32_t next_serial;
237
  uint32_t maxrrperset;  /* Maximum RRs per RRset */
238
  uint32_t maxtypepername; /* Maximum number of RR types per owner */
239
  qpz_version_t *current_version;
240
  qpz_version_t *future_version;
241
  qpz_versionlist_t open_versions;
242
  struct rcu_head rcu_head;
243
244
  qpz_heap_t *heap; /* Resigning heap */
245
246
  dns_qpmulti_t *tree; /* QP trie for data storage */
247
};
248
249
/*%
250
 * Search Context
251
 */
252
typedef struct {
253
  qpzonedb_t *qpdb;
254
  qpz_version_t *version;
255
  dns_qpread_t qpr;
256
  uint32_t serial;
257
  unsigned int options;
258
  dns_qpchain_t chain;
259
  dns_qpiter_t iter;
260
  bool copy_name;
261
  bool need_cleanup;
262
  bool wild;
263
  qpznode_t *zonecut;
264
  dns_slabheader_t *zonecut_header;
265
  dns_slabheader_t *zonecut_sigheader;
266
  dns_fixedname_t zonecut_name;
267
} qpz_search_t;
268
269
/*%
270
 * Load Context
271
 */
272
typedef struct {
273
  dns_db_t *db;
274
  dns_qp_t *tree;
275
} qpz_load_t;
276
277
static dns_dbmethods_t qpdb_zonemethods;
278
static dns_dbnode_methods_t qpznode_methods;
279
280
#if DNS_DB_NODETRACE
281
#define qpznode_ref(ptr)   qpznode__ref(ptr, __func__, __FILE__, __LINE__)
282
#define qpznode_unref(ptr) qpznode__unref(ptr, __func__, __FILE__, __LINE__)
283
#define qpznode_attach(ptr, ptrp) \
284
  qpznode__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
285
#define qpznode_detach(ptrp) qpznode__detach(ptrp, __func__, __FILE__, __LINE__)
286
ISC_REFCOUNT_STATIC_TRACE_DECL(qpznode);
287
#else
288
ISC_REFCOUNT_STATIC_DECL(qpznode);
289
#endif
290
291
/* QP trie methods */
292
static void
293
qp_attach(void *uctx, void *pval, uint32_t ival);
294
static void
295
qp_detach(void *uctx, void *pval, uint32_t ival);
296
static size_t
297
qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
298
static void
299
qp_triename(void *uctx, char *buf, size_t size);
300
301
static dns_qpmethods_t qpmethods = {
302
  qp_attach,
303
  qp_detach,
304
  qp_makekey,
305
  qp_triename,
306
};
307
308
static void
309
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG);
310
static isc_result_t
311
rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG);
312
static isc_result_t
313
rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG);
314
static void
315
rdatasetiter_current(dns_rdatasetiter_t *iterator,
316
         dns_rdataset_t *rdataset DNS__DB_FLARG);
317
318
static dns_rdatasetitermethods_t rdatasetiter_methods = {
319
  rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next,
320
  rdatasetiter_current
321
};
322
323
typedef struct qpdb_rdatasetiter {
324
  dns_rdatasetiter_t common;
325
  dns_slabtop_t *currenttop;
326
  dns_slabheader_t *current;
327
} qpdb_rdatasetiter_t;
328
329
/*
330
 * Note that these iterators, unless created with either DNS_DB_NSEC3ONLY
331
 * or DNS_DB_NONSEC3, will transparently move between the last node of the
332
 * "regular" QP trie and the root node of the NSEC3 QP trie of the database
333
 * in question, as if the latter was a successor to the former in lexical
334
 * order.  The "current" field always holds the address of either "iter".
335
 */
336
static void
337
dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG);
338
static isc_result_t
339
dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG);
340
static isc_result_t
341
dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG);
342
static isc_result_t
343
dbiterator_seek(dns_dbiterator_t *iterator,
344
    const dns_name_t *name DNS__DB_FLARG);
345
static isc_result_t
346
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG);
347
static isc_result_t
348
dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG);
349
static isc_result_t
350
dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
351
       dns_name_t *name DNS__DB_FLARG);
352
static isc_result_t
353
dbiterator_pause(dns_dbiterator_t *iterator);
354
static isc_result_t
355
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
356
357
static dns_dbiteratormethods_t dbiterator_methods = {
358
  dbiterator_destroy, dbiterator_first, dbiterator_last,
359
  dbiterator_seek,    dbiterator_prev,  dbiterator_next,
360
  dbiterator_current, dbiterator_pause, dbiterator_origin
361
};
362
363
typedef struct qpdb_dbiterator {
364
  dns_dbiterator_t common;
365
  isc_result_t result;
366
  dns_qpsnap_t *snap; /* tree snapshot */
367
  dns_qpiter_t iter;  /* tree iterator */
368
  qpznode_t *node;
369
  enum { full, nonsec3, nsec3only } nsec3mode;
370
} qpdb_dbiterator_t;
371
372
/*
373
 * Locking
374
 *
375
 * If a routine is going to lock more than one lock in this module, then
376
 * the locking must be done in the following order:
377
 *
378
 *      Node Lock       (Only one from the set may be locked at one time by
379
 *                       any caller)
380
 *
381
 *      Database Lock
382
 *
383
 * Failure to follow this hierarchy can result in deadlock.
384
 */
385
386
void
387
22
dns__qpzone_initialize(void) {
388
22.5k
  for (size_t idx = 0; idx < ARRAY_SIZE(qpzone_buckets_g); ++idx) {
389
22.5k
    NODE_INITLOCK(&qpzone_buckets_g[idx].lock);
390
22.5k
  }
391
22
}
392
393
void
394
0
dns__qpzone_shutdown(void) {
395
0
  for (size_t idx = 0; idx < ARRAY_SIZE(qpzone_buckets_g); ++idx) {
396
0
    NODE_DESTROYLOCK(&qpzone_buckets_g[idx].lock);
397
0
  }
398
0
}
399
400
static isc_rwlock_t *
401
6.24M
qpzone_get_lock(qpznode_t *node) {
402
6.24M
  return &qpzone_buckets_g[node->locknum].lock;
403
6.24M
}
404
405
static uint16_t
406
6.39M
qpzone_get_locknum(void) {
407
6.39M
  return isc_random_uniform(ARRAY_SIZE(qpzone_buckets_g));
408
6.39M
}
409
410
/*%
411
 * Return which RRset should be resigned sooner.  If the RRsets have the
412
 * same signing time, prefer the other RRset over the SOA RRset.
413
 */
414
static bool
415
0
resign_sooner(void *v1, void *v2) {
416
0
  dns_slabheader_t *h1 = v1;
417
0
  dns_slabheader_t *h2 = v2;
418
419
0
  return h1->resign < h2->resign ||
420
0
         (h1->resign == h2->resign && h1->resign_lsb < h2->resign_lsb) ||
421
0
         (h1->resign == h2->resign && h1->resign_lsb == h2->resign_lsb &&
422
0
    h2->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_soa));
423
0
}
424
425
/*%
426
 * This function sets the heap index into the header.
427
 */
428
static void
429
0
set_index(void *what, unsigned int idx) {
430
0
  dns_slabheader_t *h = what;
431
432
0
  h->heap_index = idx;
433
0
}
434
435
static void
436
0
free_glue(isc_mem_t *mctx, dns_glue_t *glue) {
437
0
  while (glue != NULL) {
438
0
    dns_glue_t *next = glue->next;
439
440
0
    if (dns_rdataset_isassociated(&glue->rdataset_a)) {
441
0
      dns_rdataset_disassociate(&glue->rdataset_a);
442
0
    }
443
0
    if (dns_rdataset_isassociated(&glue->sigrdataset_a)) {
444
0
      dns_rdataset_disassociate(&glue->sigrdataset_a);
445
0
    }
446
447
0
    if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) {
448
0
      dns_rdataset_disassociate(&glue->rdataset_aaaa);
449
0
    }
450
0
    if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) {
451
0
      dns_rdataset_disassociate(&glue->sigrdataset_aaaa);
452
0
    }
453
454
0
    dns_rdataset_invalidate(&glue->rdataset_a);
455
0
    dns_rdataset_invalidate(&glue->sigrdataset_a);
456
0
    dns_rdataset_invalidate(&glue->rdataset_aaaa);
457
0
    dns_rdataset_invalidate(&glue->sigrdataset_aaaa);
458
459
0
    dns_name_free(&glue->name, mctx);
460
461
0
    isc_mem_put(mctx, glue, sizeof(*glue));
462
463
0
    glue = next;
464
0
  }
465
0
}
466
467
static void
468
0
destroy_gluelist(dns_gluelist_t **gluelistp) {
469
0
  REQUIRE(gluelistp != NULL);
470
0
  if (*gluelistp == NULL) {
471
0
    return;
472
0
  }
473
474
0
  dns_gluelist_t *gluelist = *gluelistp;
475
476
0
  free_glue(gluelist->mctx, gluelist->glue);
477
478
0
  isc_mem_putanddetach(&gluelist->mctx, gluelist, sizeof(*gluelist));
479
0
}
480
481
static void
482
0
free_gluelist_rcu(struct rcu_head *rcu_head) {
483
0
  dns_gluelist_t *gluelist = caa_container_of(rcu_head, dns_gluelist_t,
484
0
                rcu_head);
485
0
  destroy_gluelist(&gluelist);
486
0
}
487
488
static void
489
18.8k
cleanup_gluelists(struct cds_wfs_stack *glue_stack) {
490
18.8k
  struct cds_wfs_head *head = __cds_wfs_pop_all(glue_stack);
491
18.8k
  struct cds_wfs_node *node = NULL, *next = NULL;
492
493
18.8k
  rcu_read_lock();
494
18.8k
  cds_wfs_for_each_blocking_safe(head, node, next) {
495
0
    dns_gluelist_t *gluelist =
496
0
      caa_container_of(node, dns_gluelist_t, wfs_node);
497
0
    dns_slabheader_t *header = rcu_xchg_pointer(&gluelist->header,
498
0
                  NULL);
499
0
    (void)rcu_cmpxchg_pointer(&header->gluelist, gluelist, NULL);
500
501
0
    call_rcu(&gluelist->rcu_head, free_gluelist_rcu);
502
0
  }
503
18.8k
  rcu_read_unlock();
504
18.8k
}
505
506
static void
507
18.8k
free_db_rcu(struct rcu_head *rcu_head) {
508
18.8k
  qpzonedb_t *qpdb = caa_container_of(rcu_head, qpzonedb_t, rcu_head);
509
510
18.8k
  if (dns_name_dynamic(&qpdb->common.origin)) {
511
18.8k
    dns_name_free(&qpdb->common.origin, qpdb->common.mctx);
512
18.8k
  }
513
514
18.8k
  qpz_heap_detach(&qpdb->heap);
515
516
18.8k
  if (qpdb->gluecachestats != NULL) {
517
0
    isc_stats_detach(&qpdb->gluecachestats);
518
0
  }
519
520
18.8k
  isc_rwlock_destroy(&qpdb->lock);
521
18.8k
  isc_refcount_destroy(&qpdb->common.references);
522
523
18.8k
  qpdb->common.magic = 0;
524
18.8k
  qpdb->common.impmagic = 0;
525
526
18.8k
  if (qpdb->common.update_listeners != NULL) {
527
18.8k
    INSIST(!cds_lfht_destroy(qpdb->common.update_listeners, NULL));
528
18.8k
  }
529
530
18.8k
  isc_mem_putanddetach(&qpdb->common.mctx, qpdb, sizeof(*qpdb));
531
18.8k
}
532
533
static void
534
18.8k
qpzone_destroy(qpzonedb_t *qpdb) {
535
18.8k
  REQUIRE(qpdb->future_version == NULL);
536
537
18.8k
  isc_refcount_decrementz(&qpdb->current_version->references);
538
539
18.8k
  isc_refcount_destroy(&qpdb->current_version->references);
540
18.8k
  ISC_LIST_UNLINK(qpdb->open_versions, qpdb->current_version, link);
541
18.8k
  cds_wfs_destroy(&qpdb->current_version->glue_stack);
542
18.8k
  isc_rwlock_destroy(&qpdb->current_version->rwlock);
543
18.8k
  isc_mem_put(qpdb->common.mctx, qpdb->current_version,
544
18.8k
        sizeof(*qpdb->current_version));
545
546
18.8k
  dns_qpmulti_destroy(&qpdb->tree);
547
548
18.8k
  char buf[DNS_NAME_FORMATSIZE];
549
18.8k
  if (dns_name_dynamic(&qpdb->common.origin)) {
550
18.8k
    dns_name_format(&qpdb->common.origin, buf, sizeof(buf));
551
18.8k
  } else {
552
0
    strlcpy(buf, "<UNKNOWN>", sizeof(buf));
553
0
  }
554
18.8k
  isc_log_write(DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB,
555
18.8k
          ISC_LOG_DEBUG(1), "called %s(%s)", __func__, buf);
556
557
18.8k
  call_rcu(&qpdb->rcu_head, free_db_rcu);
558
18.8k
}
559
560
static void
561
18.8k
qpdb_destroy(dns_db_t *arg) {
562
18.8k
  qpzonedb_t *qpdb = (qpzonedb_t *)arg;
563
564
18.8k
  if (qpdb->origin != NULL) {
565
18.8k
    qpznode_detach(&qpdb->origin);
566
18.8k
  }
567
18.8k
  if (qpdb->nsec_origin != NULL) {
568
18.8k
    qpznode_detach(&qpdb->nsec_origin);
569
18.8k
  }
570
18.8k
  if (qpdb->nsec3_origin != NULL) {
571
18.8k
    qpznode_detach(&qpdb->nsec3_origin);
572
18.8k
  }
573
574
  /*
575
   * The current version's glue table needs to be freed early
576
   * so the nodes are dereferenced before we check the active
577
   * node count below.
578
   */
579
18.8k
  if (qpdb->current_version != NULL) {
580
18.8k
    cleanup_gluelists(&qpdb->current_version->glue_stack);
581
18.8k
  }
582
583
18.8k
  qpzone_destroy(qpdb);
584
18.8k
}
585
586
static qpz_heap_t *
587
18.8k
new_qpz_heap(isc_mem_t *mctx) {
588
18.8k
  qpz_heap_t *new_heap = isc_mem_get(mctx, sizeof(*new_heap));
589
18.8k
  *new_heap = (qpz_heap_t){
590
18.8k
    .references = ISC_REFCOUNT_INITIALIZER(1),
591
18.8k
  };
592
593
18.8k
  isc_mutex_init(&new_heap->lock);
594
18.8k
  isc_heap_create(mctx, resign_sooner, set_index, 0, &new_heap->heap);
595
18.8k
  isc_mem_attach(mctx, &new_heap->mctx);
596
597
18.8k
  return new_heap;
598
18.8k
}
599
600
/*
601
 * This function accesses the heap lock through the header and node rather than
602
 * directly through &qpdb->heap->lock to handle a critical race condition.
603
 *
604
 * Consider this scenario:
605
 * 1. A reference is taken to a qpznode
606
 * 2. The database containing that node is freed
607
 * 3. The qpznode reference is finally released
608
 *
609
 * When the qpznode reference is released, it needs to unregister all its
610
 * slabheaders from the resigning heap. The heap is a separate refcounted
611
 * object with references from both the database and every qpznode. This
612
 * design ensures that even after the database is destroyed, if nodes are
613
 * still alive, the heap remains accessible for safe cleanup.
614
 *
615
 * Accessing the heap lock through the database (&qpdb->heap->lock) would
616
 * cause a segfault in this scenario, even though the heap itself is still
617
 * alive. By going through the node's heap reference, we maintain safe access
618
 * to the heap lock regardless of the database's lifecycle.
619
 */
620
static isc_mutex_t *
621
0
get_heap_lock(dns_slabheader_t *header) {
622
0
  return &HEADERNODE(header)->heap->lock;
623
0
}
624
625
static void
626
18.8k
qpz_heap_destroy(qpz_heap_t *qpheap) {
627
18.8k
  isc_mutex_destroy(&qpheap->lock);
628
18.8k
  isc_heap_destroy(&qpheap->heap);
629
18.8k
  isc_mem_putanddetach(&qpheap->mctx, qpheap, sizeof(*qpheap));
630
18.8k
}
631
632
static qpznode_t *
633
6.39M
new_qpznode(qpzonedb_t *qpdb, const dns_name_t *name, dns_namespace_t nspace) {
634
6.39M
  qpznode_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata));
635
6.39M
  *newdata = (qpznode_t){
636
6.39M
    .types_list = CDS_LIST_HEAD_INIT(newdata->types_list),
637
6.39M
    .data = &newdata->types_list,
638
6.39M
    .methods = &qpznode_methods,
639
6.39M
    .name = DNS_NAME_INITEMPTY,
640
6.39M
    .nspace = nspace,
641
6.39M
    .heap = qpdb->heap,
642
6.39M
    .references = ISC_REFCOUNT_INITIALIZER(1),
643
6.39M
    .locknum = qpzone_get_locknum(),
644
6.39M
  };
645
646
6.39M
  isc_mem_attach(qpdb->common.mctx, &newdata->mctx);
647
6.39M
  dns_name_dup(name, qpdb->common.mctx, &newdata->name);
648
6.39M
  qpz_heap_ref(newdata->heap);
649
650
#if DNS_DB_NODETRACE
651
  fprintf(stderr, "new_qpznode:%s:%s:%d:%p->references = 1\n", __func__,
652
    __FILE__, __LINE__ + 1, name);
653
#endif
654
6.39M
  return newdata;
655
6.39M
}
656
657
static qpz_version_t *
658
allocate_version(isc_mem_t *mctx, uint32_t serial, unsigned int references,
659
18.8k
     bool writer) {
660
18.8k
  qpz_version_t *version = isc_mem_get(mctx, sizeof(*version));
661
18.8k
  *version = (qpz_version_t){
662
18.8k
    .serial = serial,
663
18.8k
    .writer = writer,
664
18.8k
    .changed_list = ISC_LIST_INITIALIZER,
665
18.8k
    .resigned_list = ISC_LIST_INITIALIZER,
666
18.8k
    .link = ISC_LINK_INITIALIZER,
667
18.8k
    .references = ISC_REFCOUNT_INITIALIZER(references),
668
18.8k
  };
669
670
18.8k
  cds_wfs_init(&version->glue_stack);
671
18.8k
  isc_rwlock_init(&version->rwlock);
672
673
18.8k
  return version;
674
18.8k
}
675
676
isc_result_t
677
dns__qpzone_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
678
       dns_rdataclass_t rdclass, unsigned int argc ISC_ATTR_UNUSED,
679
       char **argv ISC_ATTR_UNUSED, void *driverarg ISC_ATTR_UNUSED,
680
18.8k
       dns_db_t **dbp) {
681
18.8k
  qpzonedb_t *qpdb = NULL;
682
18.8k
  isc_result_t result;
683
18.8k
  dns_qp_t *qp = NULL;
684
685
18.8k
  qpdb = isc_mem_get(mctx, sizeof(*qpdb));
686
18.8k
  *qpdb = (qpzonedb_t){
687
18.8k
    .common.origin = DNS_NAME_INITEMPTY,
688
18.8k
    .common.rdclass = rdclass,
689
18.8k
    .common.references = ISC_REFCOUNT_INITIALIZER(1),
690
18.8k
    .current_serial = 1,
691
18.8k
    .least_serial = 1,
692
18.8k
    .next_serial = 2,
693
18.8k
    .open_versions = ISC_LIST_INITIALIZER,
694
18.8k
  };
695
696
18.8k
  qpdb->common.methods = &qpdb_zonemethods;
697
18.8k
  if (type == dns_dbtype_stub) {
698
0
    qpdb->common.attributes |= DNS_DBATTR_STUB;
699
0
  }
700
701
18.8k
  isc_rwlock_init(&qpdb->lock);
702
703
18.8k
  qpdb->common.update_listeners = cds_lfht_new(16, 16, 0, 0, NULL);
704
705
18.8k
  qpdb->heap = new_qpz_heap(mctx);
706
707
  /*
708
   * Attach to the mctx.  The database will persist so long as there
709
   * are references to it, and attaching to the mctx ensures that our
710
   * mctx won't disappear out from under us.
711
   */
712
18.8k
  isc_mem_attach(mctx, &qpdb->common.mctx);
713
714
  /*
715
   * Make a copy of the origin name.
716
   */
717
18.8k
  dns_name_dup(origin, mctx, &qpdb->common.origin);
718
719
18.8k
  dns_qpmulti_create(mctx, &qpmethods, qpdb, &qpdb->tree);
720
721
  /*
722
   * Version initialization.
723
   */
724
18.8k
  qpdb->current_version = allocate_version(mctx, 1, 1, false);
725
18.8k
  qpdb->current_version->qpdb = qpdb;
726
727
18.8k
  dns_qpmulti_write(qpdb->tree, &qp);
728
729
  /*
730
   * In order to set the node callback bit correctly in zone databases,
731
   * we need to know if the node has the origin name of the zone.
732
   * In loading_addrdataset() we could simply compare the new name
733
   * to the origin name, but this is expensive.  Also, we don't know the
734
   * node name in addrdataset(), so we need another way of knowing the
735
   * zone's top.
736
   *
737
   * We now explicitly create a node for the zone's origin, and then
738
   * we simply remember the node data's address.
739
   */
740
18.8k
  qpdb->origin = new_qpznode(qpdb, &qpdb->common.origin,
741
18.8k
           DNS_DBNAMESPACE_NORMAL);
742
743
18.8k
  result = dns_qp_insert(qp, qpdb->origin, 0);
744
18.8k
  INSIST(result == ISC_R_SUCCESS);
745
746
  /*
747
   * Add an apex node to the NSEC tree so that we can quickly skip over
748
   * the NSEC nodes while iterating over the full tree.
749
   */
750
18.8k
  qpdb->nsec_origin = new_qpznode(qpdb, &qpdb->common.origin,
751
18.8k
          DNS_DBNAMESPACE_NSEC);
752
18.8k
  result = dns_qp_insert(qp, qpdb->nsec_origin, 0);
753
18.8k
  INSIST(result == ISC_R_SUCCESS);
754
755
  /*
756
   * Add an apex node to the NSEC3 tree so that NSEC3 searches
757
   * return partial matches when there is only a single NSEC3
758
   * record in the tree.
759
   */
760
18.8k
  qpdb->nsec3_origin = new_qpznode(qpdb, &qpdb->common.origin,
761
18.8k
           DNS_DBNAMESPACE_NSEC3);
762
18.8k
  result = dns_qp_insert(qp, qpdb->nsec3_origin, 0);
763
18.8k
  INSIST(result == ISC_R_SUCCESS);
764
765
18.8k
  dns_qpmulti_commit(qpdb->tree, &qp);
766
767
  /*
768
   * Keep the current version in the open list so that list operation
769
   * won't happen in normal lookup operations.
770
   */
771
18.8k
  ISC_LIST_PREPEND(qpdb->open_versions, qpdb->current_version, link);
772
773
18.8k
  qpdb->common.magic = DNS_DB_MAGIC;
774
18.8k
  qpdb->common.impmagic = QPZONE_DB_MAGIC;
775
776
18.8k
  *dbp = (dns_db_t *)qpdb;
777
778
18.8k
  return ISC_R_SUCCESS;
779
18.8k
}
780
781
/*
782
 * If incrementing erefs from zero, we also increment the node use counter
783
 * in the qpzonedb object.
784
 *
785
 * This function is called from qpznode_acquire(), so that internal
786
 * and external references are acquired at the same time, and from
787
 * qpznode_release() when we only need to increase the internal references.
788
 */
789
static void
790
307
qpznode_erefs_increment(qpznode_t *node DNS__DB_FLARG) {
791
307
  uint_fast32_t refs = isc_refcount_increment0(&node->erefs);
792
#if DNS_DB_NODETRACE
793
  fprintf(stderr, "incr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
794
    func, file, line, node, refs + 1);
795
#endif
796
797
307
  if (refs > 0) {
798
126
    return;
799
126
  }
800
307
}
801
802
static void
803
307
qpznode_acquire(qpznode_t *node DNS__DB_FLARG) {
804
307
  qpznode_ref(node);
805
307
  qpznode_erefs_increment(node DNS__DB_FLARG_PASS);
806
307
}
807
808
static dns_slabheader_t *
809
0
first_header(dns_slabtop_t *top) {
810
0
  dns_slabheader_t *header = NULL;
811
0
  cds_list_for_each_entry(header, &top->headers, headers_link) {
812
0
    return header;
813
0
  }
814
0
  return NULL;
815
0
}
816
817
static dns_slabheader_t *
818
0
next_header(dns_slabheader_t *header) {
819
0
  return cds_list_entry((header)->headers_link.next, dns_slabheader_t,
820
0
            headers_link);
821
0
}
822
823
static dns_slabheader_t *
824
5.46M
first_existing_header(dns_slabtop_t *top, uint32_t serial) {
825
5.46M
  dns_slabheader_t *header = NULL;
826
5.46M
  cds_list_for_each_entry(header, &top->headers, headers_link) {
827
5.46M
    if (header->serial <= serial && !IGNORE(header)) {
828
5.46M
      if (EXISTS(header)) {
829
5.46M
        return header;
830
5.46M
      }
831
0
      break;
832
5.46M
    }
833
5.46M
  }
834
0
  return NULL;
835
5.46M
}
836
837
static void
838
0
clean_multiple_headers(dns_slabtop_t *top) {
839
0
  dns_slabheader_t *parent = first_header(top);
840
0
  if (parent == NULL) {
841
0
    return;
842
0
  }
843
844
0
  dns_slabheader_t *header = next_header(parent), *header_next = NULL;
845
0
  cds_list_for_each_entry_safe_from(header, header_next, &top->headers,
846
0
            headers_link) {
847
0
    INSIST(header->serial <= parent->serial);
848
0
    if (header->serial == parent->serial || IGNORE(header)) {
849
0
      cds_list_del(&header->headers_link);
850
0
      dns_slabheader_destroy(&header);
851
0
    } else {
852
0
      parent = header;
853
0
    }
854
0
  }
855
0
}
856
857
static void
858
0
check_top_header(dns_slabtop_t *top) {
859
0
  dns_slabheader_t *header = first_header(top);
860
0
  if (header != NULL && IGNORE(header)) {
861
0
    cds_list_del(&header->headers_link);
862
0
    dns_slabheader_destroy(&header);
863
0
  }
864
0
}
865
866
static bool
867
0
clean_multiple_versions(dns_slabtop_t *top, uint32_t least_serial) {
868
0
  dns_slabheader_t *parent = first_header(top);
869
0
  if (parent == NULL) {
870
0
    return false;
871
0
  }
872
873
0
  bool multiple = false;
874
0
  dns_slabheader_t *header = next_header(parent), *header_next = NULL;
875
0
  cds_list_for_each_entry_safe_from(header, header_next, &top->headers,
876
0
            headers_link) {
877
0
    if (header->serial < least_serial) {
878
0
      cds_list_del(&header->headers_link);
879
0
      dns_slabheader_destroy(&header);
880
0
    } else {
881
0
      multiple = true;
882
0
      parent = header;
883
0
    }
884
0
  }
885
0
  return multiple;
886
0
}
887
888
static void
889
0
clean_zone_node(qpznode_t *node, uint32_t least_serial) {
890
0
  bool still_dirty = false;
891
892
  /*
893
   * Caller must be holding the node lock.
894
   */
895
0
  REQUIRE(least_serial != 0);
896
897
0
  DNS_SLABTOP_FOREACH(top, node->data) {
898
    /*
899
     * First, we clean up any instances of multiple rdatasets
900
     * with the same serial number, or that have the IGNORE
901
     * attribute.
902
     */
903
0
    clean_multiple_headers(top);
904
905
    /*
906
     * All IGNORE datasets have been eliminated with the possible
907
     * exception of the top header, which we now check.
908
     */
909
0
    check_top_header(top);
910
911
0
    if (first_header(top) == NULL) {
912
0
      cds_list_del(&top->types_link);
913
0
      dns_slabtop_destroy(node->mctx, &top);
914
0
    } else {
915
      /*
916
       * Try to find the first down node less than the least
917
       * serial, and if there are such rdatasets, delete it
918
       * and any older versions.
919
       *
920
       * Note: The serial number of the top header might be
921
       * less than least_serial too, but we cannot delete it
922
       * because it is the most recent version.
923
       */
924
0
      still_dirty = clean_multiple_versions(top,
925
0
                    least_serial);
926
0
    }
927
0
  }
928
0
  if (!still_dirty) {
929
0
    node->dirty = false;
930
0
  }
931
0
}
932
933
/*
934
 * Decrement the external references to a node. If the counter
935
 * goes to zero, decrement the node use counter in the qpzonedb object
936
 * as well, and return true. Otherwise return false.
937
 */
938
static bool
939
307
qpznode_erefs_decrement(qpznode_t *node DNS__DB_FLARG) {
940
307
  uint_fast32_t refs = isc_refcount_decrement(&node->erefs);
941
942
#if DNS_DB_NODETRACE
943
  fprintf(stderr, "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
944
    func, file, line, node, refs - 1);
945
#endif
946
307
  if (refs > 1) {
947
126
    return false;
948
126
  }
949
950
181
  return true;
951
307
}
952
953
/*
954
 * Caller must be holding the node lock; either the read or write lock.
955
 * Note that the lock must be held even when node references are
956
 * atomically modified; in that case the decrement operation itself does not
957
 * have to be protected, but we must avoid a race condition where multiple
958
 * threads are decreasing the reference to zero simultaneously and at least
959
 * one of them is going to free the node.
960
 *
961
 * This calls dec_erefs() to decrement the external node reference counter,
962
 * (and possibly the node use counter), cleans up and deletes the node
963
 * if necessary, then decrements the internal reference counter as well.
964
 */
965
static void
966
qpznode_release(qpznode_t *node, uint32_t least_serial,
967
307
    isc_rwlocktype_t *nlocktypep DNS__DB_FLARG) {
968
307
  REQUIRE(*nlocktypep != isc_rwlocktype_none);
969
970
307
  if (!qpznode_erefs_decrement(node DNS__DB_FLARG_PASS)) {
971
126
    goto unref;
972
126
  }
973
974
  /* Handle easy and typical case first. */
975
181
  if (!node->dirty && !cds_list_empty(node->data)) {
976
181
    goto unref;
977
181
  }
978
979
0
  if (node->dirty && least_serial > 0) {
980
    /*
981
     * Only do node cleanup when called from closeversion.
982
     * Closeversion, unlike other call sites, will provide the
983
     * least_serial, and will hold a write lock instead of a read
984
     * lock.
985
     *
986
     * This way we avoid having to protect the db by increasing
987
     * the db reference count, avoiding contention in single
988
     * zone workloads.
989
     */
990
0
    REQUIRE(*nlocktypep == isc_rwlocktype_write);
991
0
    clean_zone_node(node, least_serial);
992
0
  }
993
994
307
unref:
995
307
  qpznode_unref(node);
996
307
}
997
998
static void
999
bindrdataset(qpzonedb_t *qpdb, qpznode_t *node, dns_slabheader_t *header,
1000
5.46M
       dns_rdataset_t *rdataset DNS__DB_FLARG) {
1001
5.46M
  if (rdataset == NULL) {
1002
5.46M
    return;
1003
5.46M
  }
1004
1005
181
  qpznode_acquire(node DNS__DB_FLARG_PASS);
1006
1007
181
  INSIST(rdataset->methods == NULL); /* We must be disassociated. */
1008
1009
181
  rdataset->methods = &dns_rdataslab_rdatasetmethods;
1010
181
  rdataset->rdclass = qpdb->common.rdclass;
1011
181
  rdataset->type = DNS_TYPEPAIR_TYPE(header->typepair);
1012
181
  rdataset->covers = DNS_TYPEPAIR_COVERS(header->typepair);
1013
181
  rdataset->ttl = header->ttl;
1014
181
  rdataset->trust = atomic_load(&header->trust);
1015
1016
181
  if (OPTOUT(header)) {
1017
0
    rdataset->attributes.optout = true;
1018
0
  }
1019
1020
181
  rdataset->slab.db = (dns_db_t *)qpdb;
1021
181
  rdataset->slab.node = (dns_dbnode_t *)node;
1022
181
  rdataset->slab.raw = header->raw;
1023
181
  rdataset->slab.iter_pos = NULL;
1024
181
  rdataset->slab.iter_count = 0;
1025
1026
  /*
1027
   * Add noqname proof.
1028
   */
1029
181
  rdataset->slab.noqname = header->noqname;
1030
181
  if (header->noqname != NULL) {
1031
0
    rdataset->attributes.noqname = true;
1032
0
  }
1033
181
  rdataset->slab.closest = header->closest;
1034
181
  if (header->closest != NULL) {
1035
0
    rdataset->attributes.closest = true;
1036
0
  }
1037
1038
  /*
1039
   * Copy out re-signing information.
1040
   */
1041
181
  if (RESIGN(header)) {
1042
0
    rdataset->attributes.resign = true;
1043
0
    rdataset->resign = (header->resign << 1) | header->resign_lsb;
1044
181
  } else {
1045
181
    rdataset->resign = 0;
1046
181
  }
1047
181
}
1048
1049
static void
1050
28
setnsec3parameters(dns_db_t *db, qpz_version_t *version) {
1051
28
  qpznode_t *node = NULL;
1052
28
  dns_rdata_nsec3param_t nsec3param;
1053
28
  isc_region_t region;
1054
28
  isc_result_t result;
1055
28
  unsigned char *raw; /* RDATASLAB */
1056
28
  unsigned int count, length;
1057
28
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
1058
28
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1059
28
  isc_rwlock_t *nlock = NULL;
1060
28
  dns_slabheader_t *found = NULL;
1061
1062
28
  version->havensec3 = false;
1063
28
  node = qpdb->origin;
1064
28
  nlock = qpzone_get_lock(node);
1065
1066
28
  NODE_RDLOCK(nlock, &nlocktype);
1067
1068
134
  DNS_SLABTOP_FOREACH(top, node->data) {
1069
134
    if (top->typepair != dns_rdatatype_nsec3param) {
1070
129
      continue;
1071
129
    }
1072
5
    found = first_existing_header(top, version->serial);
1073
5
  }
1074
1075
28
  if (found != NULL) {
1076
    /*
1077
     * Find an NSEC3PARAM with a supported algorithm.
1078
     */
1079
5
    raw = found->raw;
1080
5
    count = get_uint16(raw);
1081
11
    while (count-- > 0U) {
1082
7
      dns_rdata_t rdata = DNS_RDATA_INIT;
1083
1084
7
      length = get_uint16(raw);
1085
7
      region.base = raw;
1086
7
      region.length = length;
1087
7
      raw += length;
1088
7
      dns_rdata_fromregion(&rdata, qpdb->common.rdclass,
1089
7
               dns_rdatatype_nsec3param, &region);
1090
7
      result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
1091
7
      INSIST(result == ISC_R_SUCCESS);
1092
1093
7
      if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG &&
1094
7
          !dns_nsec3_supportedhash(nsec3param.hash))
1095
5
      {
1096
5
        continue;
1097
5
      }
1098
1099
2
      if (nsec3param.flags != 0) {
1100
1
        continue;
1101
1
      }
1102
1103
1
      memmove(version->salt, nsec3param.salt,
1104
1
        nsec3param.salt_length);
1105
1
      version->hash = nsec3param.hash;
1106
1
      version->salt_length = nsec3param.salt_length;
1107
1
      version->iterations = nsec3param.iterations;
1108
1
      version->flags = nsec3param.flags;
1109
1
      version->havensec3 = true;
1110
      /*
1111
       * Look for a better algorithm than the
1112
       * unknown test algorithm.
1113
       */
1114
1
      if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG) {
1115
1
        goto unlock;
1116
1
      }
1117
1
    }
1118
5
  }
1119
28
unlock:
1120
28
  NODE_UNLOCK(nlock, &nlocktype);
1121
28
}
1122
1123
static void
1124
0
cleanup_nondirty(qpz_version_t *version, qpz_changedlist_t *cleanup_list) {
1125
  /*
1126
   * If the changed record is dirty, then an update created multiple
1127
   * versions of a given rdataset.  We keep this list until we're the
1128
   * least open version, at which point it's safe to get rid of any
1129
   * older versions.
1130
   *
1131
   * If the changed record isn't dirty, then we don't need it anymore
1132
   * since we're committing and not rolling back.
1133
   *
1134
   * The caller must be holding the database lock.
1135
   */
1136
0
  ISC_LIST_FOREACH(version->changed_list, changed, link) {
1137
0
    if (!changed->dirty) {
1138
0
      ISC_LIST_UNLINK(version->changed_list, changed, link);
1139
0
      ISC_LIST_APPEND(*cleanup_list, changed, link);
1140
0
    }
1141
0
  }
1142
0
}
1143
1144
static void
1145
18.8k
setsecure(dns_db_t *db, qpz_version_t *version, dns_dbnode_t *origin) {
1146
18.8k
  dns_rdataset_t keyset;
1147
18.8k
  dns_rdataset_t nsecset, signsecset;
1148
18.8k
  bool haszonekey = false;
1149
18.8k
  bool hasnsec = false;
1150
18.8k
  isc_result_t result;
1151
1152
18.8k
  version->secure = false;
1153
18.8k
  version->havensec3 = false;
1154
1155
18.8k
  dns_rdataset_init(&keyset);
1156
18.8k
  result = dns_db_findrdataset(db, origin, (dns_dbversion_t *)version,
1157
18.8k
             dns_rdatatype_dnskey, 0, 0, &keyset, NULL);
1158
18.8k
  if (result == ISC_R_SUCCESS) {
1159
47
    haszonekey = dns_dnssec_haszonekey(&keyset);
1160
47
    dns_rdataset_disassociate(&keyset);
1161
47
  }
1162
18.8k
  if (!haszonekey) {
1163
18.8k
    return;
1164
18.8k
  }
1165
1166
28
  dns_rdataset_init(&nsecset);
1167
28
  dns_rdataset_init(&signsecset);
1168
28
  result = dns_db_findrdataset(db, origin, (dns_dbversion_t *)version,
1169
28
             dns_rdatatype_nsec, 0, 0, &nsecset,
1170
28
             &signsecset);
1171
28
  if (result == ISC_R_SUCCESS) {
1172
8
    if (dns_rdataset_isassociated(&signsecset)) {
1173
4
      hasnsec = true;
1174
4
      dns_rdataset_disassociate(&signsecset);
1175
4
    }
1176
8
    dns_rdataset_disassociate(&nsecset);
1177
8
  }
1178
1179
28
  setnsec3parameters(db, version);
1180
1181
  /*
1182
   * If we don't have a valid NSEC/NSEC3 chain,
1183
   * clear the secure flag.
1184
   */
1185
28
  if (version->havensec3 || hasnsec) {
1186
5
    version->secure = true;
1187
5
  }
1188
28
}
1189
1190
static void
1191
181
currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
1192
181
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
1193
181
  qpz_version_t *version = NULL;
1194
1195
181
  REQUIRE(VALID_QPZONE(qpdb));
1196
1197
181
  RWLOCK(&qpdb->lock, isc_rwlocktype_read);
1198
181
  version = qpdb->current_version;
1199
181
  isc_refcount_increment(&version->references);
1200
181
  RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
1201
1202
181
  *versionp = (dns_dbversion_t *)version;
1203
181
}
1204
1205
static void
1206
attachversion(dns_db_t *db, dns_dbversion_t *source,
1207
0
        dns_dbversion_t **targetp) {
1208
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
1209
0
  qpz_version_t *version = (qpz_version_t *)source;
1210
1211
0
  REQUIRE(VALID_QPZONE(qpdb));
1212
0
  INSIST(version != NULL && version->qpdb == qpdb);
1213
1214
0
  isc_refcount_increment(&version->references);
1215
1216
0
  *targetp = source;
1217
0
}
1218
1219
static isc_result_t
1220
0
newversion(dns_db_t *db, dns_dbversion_t **versionp) {
1221
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
1222
0
  qpz_version_t *version = NULL;
1223
1224
0
  REQUIRE(VALID_QPZONE(qpdb));
1225
0
  REQUIRE(versionp != NULL && *versionp == NULL);
1226
0
  REQUIRE(qpdb->future_version == NULL);
1227
1228
0
  RWLOCK(&qpdb->lock, isc_rwlocktype_write);
1229
0
  INSIST(qpdb->next_serial != 0);
1230
0
  version = allocate_version(qpdb->common.mctx, qpdb->next_serial, 1,
1231
0
           true);
1232
0
  version->qpdb = qpdb;
1233
0
  version->secure = qpdb->current_version->secure;
1234
0
  version->havensec3 = qpdb->current_version->havensec3;
1235
0
  if (version->havensec3) {
1236
0
    version->flags = qpdb->current_version->flags;
1237
0
    version->iterations = qpdb->current_version->iterations;
1238
0
    version->hash = qpdb->current_version->hash;
1239
0
    version->salt_length = qpdb->current_version->salt_length;
1240
0
    memmove(version->salt, qpdb->current_version->salt,
1241
0
      version->salt_length);
1242
0
  }
1243
1244
0
  version->records = qpdb->current_version->records;
1245
0
  version->xfrsize = qpdb->current_version->xfrsize;
1246
1247
0
  qpdb->next_serial++;
1248
0
  qpdb->future_version = version;
1249
0
  RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
1250
1251
0
  *versionp = (dns_dbversion_t *)version;
1252
1253
0
  return ISC_R_SUCCESS;
1254
0
}
1255
1256
static void
1257
0
resigninsert(dns_slabheader_t *newheader) {
1258
0
  REQUIRE(newheader->heap_index == 0);
1259
1260
0
  LOCK(get_heap_lock(newheader));
1261
0
  isc_heap_insert(HEADERNODE(newheader)->heap->heap, newheader);
1262
0
  UNLOCK(get_heap_lock(newheader));
1263
0
}
1264
1265
static void
1266
resigndelete(qpzonedb_t *qpdb ISC_ATTR_UNUSED, qpz_version_t *version,
1267
0
       dns_slabheader_t *header DNS__DB_FLARG) {
1268
0
  if (header == NULL || header->heap_index == 0) {
1269
0
    return;
1270
0
  }
1271
1272
0
  LOCK(get_heap_lock(header));
1273
0
  isc_heap_delete(HEADERNODE(header)->heap->heap, header->heap_index);
1274
0
  UNLOCK(get_heap_lock(header));
1275
1276
0
  header->heap_index = 0;
1277
0
  qpznode_acquire(HEADERNODE(header) DNS__DB_FLARG_PASS);
1278
1279
0
  qpz_resigned_t *resigned = isc_mem_get(((dns_db_t *)qpdb)->mctx,
1280
0
                 sizeof(*resigned));
1281
0
  *resigned = (qpz_resigned_t){
1282
0
    .header = header,
1283
0
    .link = ISC_LINK_INITIALIZER,
1284
0
  };
1285
1286
0
  ISC_LIST_APPEND(version->resigned_list, resigned, link);
1287
0
}
1288
1289
static void
1290
make_least_version(qpzonedb_t *qpdb, qpz_version_t *version,
1291
0
       qpz_changedlist_t *cleanup_list) {
1292
0
  qpdb->least_serial = version->serial;
1293
0
  *cleanup_list = version->changed_list;
1294
0
  ISC_LIST_INIT(version->changed_list);
1295
0
}
1296
1297
static void
1298
0
rollback_node(qpznode_t *node, uint32_t serial) {
1299
0
  bool make_dirty = false;
1300
1301
  /*
1302
   * We set the IGNORE attribute on rdatasets with serial number
1303
   * 'serial'.  When the reference count goes to zero, these rdatasets
1304
   * will be cleaned up; until that time, they will be ignored.
1305
   */
1306
0
  DNS_SLABTOP_FOREACH(top, node->data) {
1307
0
    dns_slabheader_t *header = NULL;
1308
0
    cds_list_for_each_entry(header, &top->headers, headers_link) {
1309
0
      if (header->serial == serial) {
1310
0
        DNS_SLABHEADER_SETATTR(
1311
0
          header, DNS_SLABHEADERATTR_IGNORE);
1312
0
        make_dirty = true;
1313
0
      }
1314
0
    }
1315
0
  }
1316
0
  if (make_dirty) {
1317
0
    node->dirty = true;
1318
0
  }
1319
0
}
1320
1321
static void
1322
closeversion(dns_db_t *db, dns_dbversion_t **versionp,
1323
181
       bool commit DNS__DB_FLARG) {
1324
181
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
1325
181
  qpz_version_t *version = NULL, *cleanup_version = NULL;
1326
181
  qpz_version_t *least_greater = NULL;
1327
181
  qpznode_t *node = NULL;
1328
181
  bool rollback = false;
1329
181
  qpz_changedlist_t cleanup_list;
1330
181
  qpz_resignedlist_t resigned_list;
1331
181
  uint32_t serial, least_serial;
1332
1333
181
  REQUIRE(VALID_QPZONE(qpdb));
1334
181
  version = (qpz_version_t *)*versionp;
1335
181
  INSIST(version->qpdb == qpdb);
1336
1337
181
  if (isc_refcount_decrement(&version->references) > 1) {
1338
181
    *versionp = NULL;
1339
181
    return;
1340
181
  }
1341
1342
0
  ISC_LIST_INIT(cleanup_list);
1343
0
  ISC_LIST_INIT(resigned_list);
1344
1345
  /*
1346
   * Update the zone's secure status in version before making
1347
   * it the current version.
1348
   */
1349
0
  if (version->writer && commit) {
1350
0
    setsecure(db, version, (dns_dbnode_t *)qpdb->origin);
1351
0
  }
1352
1353
0
  RWLOCK(&qpdb->lock, isc_rwlocktype_write);
1354
0
  serial = version->serial;
1355
0
  if (version->writer) {
1356
0
    if (commit) {
1357
0
      unsigned int cur_ref;
1358
0
      qpz_version_t *cur_version = NULL;
1359
1360
0
      INSIST(version == qpdb->future_version);
1361
      /*
1362
       * The current version is going to be replaced.
1363
       * Release the (likely last) reference to it from the
1364
       * DB itself and unlink it from the open list.
1365
       */
1366
0
      cur_version = qpdb->current_version;
1367
0
      cur_ref = isc_refcount_decrement(
1368
0
        &cur_version->references);
1369
0
      if (cur_ref == 1) {
1370
0
        (void)isc_refcount_current(
1371
0
          &cur_version->references);
1372
0
        if (cur_version->serial == qpdb->least_serial) {
1373
0
          INSIST(ISC_LIST_EMPTY(
1374
0
            cur_version->changed_list));
1375
0
        }
1376
0
        ISC_LIST_UNLINK(qpdb->open_versions,
1377
0
            cur_version, link);
1378
0
      }
1379
0
      if (ISC_LIST_EMPTY(qpdb->open_versions)) {
1380
        /*
1381
         * We're going to become the least open
1382
         * version.
1383
         */
1384
0
        make_least_version(qpdb, version,
1385
0
               &cleanup_list);
1386
0
      } else {
1387
        /*
1388
         * Some other open version is the
1389
         * least version.  We can't cleanup
1390
         * records that were changed in this
1391
         * version because the older versions
1392
         * may still be in use by an open
1393
         * version.
1394
         *
1395
         * We can, however, discard the
1396
         * changed records for things that
1397
         * we've added that didn't exist in
1398
         * prior versions.
1399
         */
1400
0
        cleanup_nondirty(version, &cleanup_list);
1401
0
      }
1402
      /*
1403
       * If the (soon to be former) current version
1404
       * isn't being used by anyone, we can clean
1405
       * it up.
1406
       */
1407
0
      if (cur_ref == 1) {
1408
0
        cleanup_version = cur_version;
1409
0
        ISC_LIST_APPENDLIST(
1410
0
          version->changed_list,
1411
0
          cleanup_version->changed_list, link);
1412
0
      }
1413
      /*
1414
       * Become the current version.
1415
       */
1416
0
      version->writer = false;
1417
0
      qpdb->current_version = version;
1418
0
      qpdb->current_serial = version->serial;
1419
0
      qpdb->future_version = NULL;
1420
1421
      /*
1422
       * Keep the current version in the open list, and
1423
       * gain a reference for the DB itself (see the DB
1424
       * creation function below).  This must be the only
1425
       * case where we need to increment the counter from
1426
       * zero and need to use isc_refcount_increment0().
1427
       */
1428
0
      INSIST(isc_refcount_increment0(&version->references) ==
1429
0
             0);
1430
0
      ISC_LIST_PREPEND(qpdb->open_versions,
1431
0
           qpdb->current_version, link);
1432
0
      resigned_list = version->resigned_list;
1433
0
      ISC_LIST_INIT(version->resigned_list);
1434
0
    } else {
1435
      /*
1436
       * We're rolling back this transaction.
1437
       */
1438
0
      cleanup_list = version->changed_list;
1439
0
      ISC_LIST_INIT(version->changed_list);
1440
0
      resigned_list = version->resigned_list;
1441
0
      ISC_LIST_INIT(version->resigned_list);
1442
0
      rollback = true;
1443
0
      cleanup_version = version;
1444
0
      qpdb->future_version = NULL;
1445
0
    }
1446
0
  } else {
1447
0
    if (version != qpdb->current_version) {
1448
      /*
1449
       * There are no external or internal references
1450
       * to this version and it can be cleaned up.
1451
       */
1452
0
      cleanup_version = version;
1453
1454
      /*
1455
       * Find the version with the least serial
1456
       * number greater than ours.
1457
       */
1458
0
      least_greater = ISC_LIST_PREV(version, link);
1459
0
      if (least_greater == NULL) {
1460
0
        least_greater = qpdb->current_version;
1461
0
      }
1462
1463
0
      INSIST(version->serial < least_greater->serial);
1464
      /*
1465
       * Is this the least open version?
1466
       */
1467
0
      if (version->serial == qpdb->least_serial) {
1468
        /*
1469
         * Yes.  Install the new least open
1470
         * version.
1471
         */
1472
0
        make_least_version(qpdb, least_greater,
1473
0
               &cleanup_list);
1474
0
      } else {
1475
        /*
1476
         * Add any unexecuted cleanups to
1477
         * those of the least greater version.
1478
         */
1479
0
        ISC_LIST_APPENDLIST(least_greater->changed_list,
1480
0
                version->changed_list,
1481
0
                link);
1482
0
      }
1483
0
    } else if (version->serial == qpdb->least_serial) {
1484
0
      INSIST(ISC_LIST_EMPTY(version->changed_list));
1485
0
    }
1486
0
    ISC_LIST_UNLINK(qpdb->open_versions, version, link);
1487
0
  }
1488
0
  least_serial = qpdb->least_serial;
1489
0
  RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
1490
1491
0
  if (cleanup_version != NULL) {
1492
0
    isc_refcount_destroy(&cleanup_version->references);
1493
0
    INSIST(ISC_LIST_EMPTY(cleanup_version->changed_list));
1494
0
    cleanup_gluelists(&cleanup_version->glue_stack);
1495
0
    cds_wfs_destroy(&cleanup_version->glue_stack);
1496
0
    isc_rwlock_destroy(&cleanup_version->rwlock);
1497
0
    isc_mem_put(qpdb->common.mctx, cleanup_version,
1498
0
          sizeof(*cleanup_version));
1499
0
  }
1500
1501
  /*
1502
   * Commit/rollback re-signed headers.
1503
   */
1504
0
  ISC_LIST_FOREACH(resigned_list, resigned, link) {
1505
0
    isc_rwlock_t *nlock = NULL;
1506
0
    isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1507
0
    dns_slabheader_t *header = resigned->header;
1508
1509
0
    ISC_LIST_UNLINK(resigned_list, resigned, link);
1510
1511
0
    isc_mem_put(db->mctx, resigned, sizeof(*resigned));
1512
1513
0
    nlock = qpzone_get_lock(HEADERNODE(header));
1514
0
    NODE_WRLOCK(nlock, &nlocktype);
1515
0
    if (rollback && !IGNORE(header)) {
1516
0
      resigninsert(header);
1517
0
    }
1518
0
    qpznode_release(HEADERNODE(header), least_serial,
1519
0
        &nlocktype DNS__DB_FLARG_PASS);
1520
0
    NODE_UNLOCK(nlock, &nlocktype);
1521
0
  }
1522
1523
0
  if (ISC_LIST_EMPTY(cleanup_list)) {
1524
0
    *versionp = NULL;
1525
0
    return;
1526
0
  }
1527
1528
0
  ISC_LIST_FOREACH(cleanup_list, changed, link) {
1529
0
    isc_rwlock_t *nlock = NULL;
1530
0
    isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1531
1532
0
    node = changed->node;
1533
0
    nlock = qpzone_get_lock(node);
1534
1535
0
    NODE_WRLOCK(nlock, &nlocktype);
1536
0
    if (rollback) {
1537
0
      rollback_node(node, serial);
1538
0
    }
1539
0
    qpznode_release(node, least_serial,
1540
0
        &nlocktype DNS__DB_FILELINE);
1541
1542
0
    NODE_UNLOCK(nlock, &nlocktype);
1543
1544
0
    isc_mem_put(qpdb->common.mctx, changed, sizeof(*changed));
1545
0
  }
1546
1547
0
  *versionp = NULL;
1548
0
}
1549
1550
static isc_result_t
1551
qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
1552
        dns_dbversion_t *dbversion, dns_rdatatype_t type,
1553
        dns_rdatatype_t covers, isc_stdtime_t now ISC_ATTR_UNUSED,
1554
        dns_rdataset_t *rdataset,
1555
18.9k
        dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
1556
18.9k
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
1557
18.9k
  qpznode_t *node = (qpznode_t *)dbnode;
1558
18.9k
  dns_slabheader_t *found = NULL, *foundsig = NULL;
1559
18.9k
  uint32_t serial;
1560
18.9k
  qpz_version_t *version = (qpz_version_t *)dbversion;
1561
18.9k
  bool close_version = false;
1562
18.9k
  dns_typepair_t typepair, sigpair;
1563
18.9k
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1564
18.9k
  isc_rwlock_t *nlock = NULL;
1565
1566
18.9k
  REQUIRE(VALID_QPZONE(qpdb));
1567
18.9k
  REQUIRE(type != dns_rdatatype_any);
1568
18.9k
  INSIST(version == NULL || version->qpdb == qpdb);
1569
1570
18.9k
  if (type == dns_rdatatype_none && covers == dns_rdatatype_none) {
1571
0
    return ISC_R_NOTFOUND;
1572
0
  }
1573
1574
18.9k
  if (version == NULL) {
1575
4
    currentversion(db, (dns_dbversion_t **)&version);
1576
4
    close_version = true;
1577
4
  }
1578
18.9k
  serial = version->serial;
1579
1580
18.9k
  nlock = qpzone_get_lock(node);
1581
18.9k
  NODE_RDLOCK(nlock, &nlocktype);
1582
1583
18.9k
  typepair = DNS_TYPEPAIR_VALUE(type, covers);
1584
18.9k
  if (covers == dns_rdatatype_none) {
1585
18.9k
    sigpair = DNS_SIGTYPEPAIR(type);
1586
18.9k
  } else {
1587
0
    sigpair = dns_typepair_none;
1588
0
  }
1589
1590
18.9k
  DNS_SLABTOP_FOREACH(top, node->data) {
1591
800
    dns_slabheader_t *header = first_existing_header(top, serial);
1592
800
    if (header != NULL) {
1593
      /*
1594
       * We have an active, extant rdataset.  If it's a
1595
       * type we're looking for, remember it.
1596
       */
1597
800
      if (top->typepair == typepair) {
1598
59
        found = header;
1599
59
        if (foundsig != NULL) {
1600
5
          break;
1601
5
        }
1602
741
      } else if (top->typepair == sigpair) {
1603
13
        foundsig = header;
1604
13
        if (found != NULL) {
1605
5
          break;
1606
5
        }
1607
13
      }
1608
800
    }
1609
800
  }
1610
18.9k
  if (found != NULL) {
1611
59
    bindrdataset(qpdb, node, found, rdataset DNS__DB_FLARG_PASS);
1612
59
    if (foundsig != NULL) {
1613
10
      bindrdataset(qpdb, node, foundsig,
1614
10
             sigrdataset DNS__DB_FLARG_PASS);
1615
10
    }
1616
59
  }
1617
1618
18.9k
  NODE_UNLOCK(nlock, &nlocktype);
1619
1620
18.9k
  if (close_version) {
1621
4
    closeversion(db, (dns_dbversion_t **)&version,
1622
4
           false DNS__DB_FLARG_PASS);
1623
4
  }
1624
1625
18.9k
  if (found == NULL) {
1626
18.8k
    return ISC_R_NOTFOUND;
1627
18.8k
  }
1628
1629
59
  return ISC_R_SUCCESS;
1630
18.9k
}
1631
1632
static bool
1633
5.46M
delegating_type(qpzonedb_t *qpdb, qpznode_t *node, dns_typepair_t typepair) {
1634
5.46M
  return typepair == DNS_TYPEPAIR(dns_rdatatype_dname) ||
1635
5.46M
         (typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
1636
4.81M
    (node != qpdb->origin || IS_STUB(qpdb)));
1637
5.46M
}
1638
1639
static void
1640
loading_addnode(qpz_load_t *loadctx, const dns_name_t *name,
1641
    dns_rdatatype_t type, dns_rdatatype_t covers,
1642
6.22M
    qpznode_t **nodep) {
1643
6.22M
  qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db;
1644
6.22M
  isc_result_t result;
1645
6.22M
  qpznode_t *node = NULL, *nsecnode = NULL;
1646
1647
6.22M
  if (type == dns_rdatatype_nsec3 || covers == dns_rdatatype_nsec3) {
1648
2.40k
    result = dns_qp_getname(loadctx->tree, name,
1649
2.40k
          DNS_DBNAMESPACE_NSEC3, (void **)&node,
1650
2.40k
          NULL);
1651
2.40k
    if (result == ISC_R_SUCCESS) {
1652
1.60k
      *nodep = node;
1653
1.60k
    } else {
1654
800
      node = new_qpznode(qpdb, name, DNS_DBNAMESPACE_NSEC3);
1655
800
      result = dns_qp_insert(loadctx->tree, node, 0);
1656
800
      INSIST(result == ISC_R_SUCCESS);
1657
800
      *nodep = node;
1658
800
      qpznode_detach(&node);
1659
800
    }
1660
2.40k
    return;
1661
2.40k
  }
1662
1663
6.21M
  result = dns_qp_getname(loadctx->tree, name, DNS_DBNAMESPACE_NORMAL,
1664
6.21M
        (void **)&node, NULL);
1665
6.21M
  if (result == ISC_R_SUCCESS) {
1666
872k
    if (type == dns_rdatatype_nsec && node->havensec) {
1667
952
      goto done;
1668
952
    }
1669
5.34M
  } else {
1670
5.34M
    INSIST(node == NULL);
1671
5.34M
    node = new_qpznode(qpdb, name, DNS_DBNAMESPACE_NORMAL);
1672
5.34M
    result = dns_qp_insert(loadctx->tree, node, 0);
1673
5.34M
    INSIST(result == ISC_R_SUCCESS);
1674
5.34M
    qpznode_unref(node);
1675
5.34M
  }
1676
6.21M
  if (type != dns_rdatatype_nsec) {
1677
6.21M
    goto done;
1678
6.21M
  }
1679
1680
  /*
1681
   * We're adding an NSEC record, so create a node in the nsec tree
1682
   * too. This tree speeds searches for closest NSECs that would
1683
   * otherwise need to examine many irrelevant nodes in large TLDs.
1684
   * If dns_qp_insert() fails, it means there's already an NSEC
1685
   * node there, so we can just detach the new one we created and
1686
   * move on.
1687
   */
1688
6.73k
  node->havensec = true;
1689
6.73k
  nsecnode = new_qpznode(qpdb, name, DNS_DBNAMESPACE_NSEC);
1690
6.73k
  (void)dns_qp_insert(loadctx->tree, nsecnode, 0);
1691
6.73k
  qpznode_detach(&nsecnode);
1692
1693
6.21M
done:
1694
6.21M
  *nodep = node;
1695
6.21M
}
1696
1697
static bool
1698
5.46M
cname_and_other(qpznode_t *node, uint32_t serial) {
1699
5.46M
  bool cname = false, other = false;
1700
1701
  /*
1702
   * Look for CNAME and "other data" rdatasets active in our version.
1703
   * ("Other data" is any rdataset whose type is not KEY, NSEC, SIG
1704
   * or RRSIG.
1705
   */
1706
5.50M
  DNS_SLABTOP_FOREACH(top, node->data) {
1707
5.50M
    dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(top->typepair);
1708
5.50M
    if (rdtype == dns_rdatatype_cname) {
1709
589
      if (first_existing_header(top, serial) != NULL) {
1710
589
        cname = true;
1711
589
      }
1712
5.50M
    } else if (rdtype != dns_rdatatype_key &&
1713
5.50M
         rdtype != dns_rdatatype_sig &&
1714
5.50M
         rdtype != dns_rdatatype_nsec &&
1715
5.49M
         rdtype != dns_rdatatype_rrsig)
1716
5.45M
    {
1717
5.45M
      if (first_existing_header(top, serial) != NULL) {
1718
5.45M
        if (!prio_type(rdtype)) {
1719
          /*
1720
           * CNAME is in the priority list, so if
1721
           * we are done with priority types, we
1722
           * know there will not be a CNAME, and
1723
           * are safe to skip the rest.
1724
           */
1725
596k
          return cname;
1726
596k
        }
1727
4.86M
        other = true;
1728
4.86M
      }
1729
5.45M
    }
1730
1731
4.91M
    if (cname && other) {
1732
8
      return true;
1733
8
    }
1734
4.91M
  }
1735
1736
4.86M
  return false;
1737
5.46M
}
1738
1739
static qpz_changed_t *
1740
add_changed(qpzonedb_t *qpdb, dns_slabheader_t *header,
1741
0
      qpz_version_t *version DNS__DB_FLARG) {
1742
0
  qpz_changed_t *changed = NULL;
1743
0
  qpznode_t *node = HEADERNODE(header);
1744
1745
0
  changed = isc_mem_get(qpdb->common.mctx, sizeof(*changed));
1746
1747
0
  RWLOCK(&qpdb->lock, isc_rwlocktype_write);
1748
0
  REQUIRE(version->writer);
1749
1750
0
  *changed = (qpz_changed_t){ .node = node };
1751
0
  ISC_LIST_INITANDAPPEND(version->changed_list, changed, link);
1752
0
  qpznode_acquire(node DNS__DB_FLARG_PASS);
1753
0
  RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
1754
1755
0
  return changed;
1756
0
}
1757
1758
static uint64_t
1759
5.57M
recordsize(dns_slabheader_t *header, unsigned int namelen) {
1760
5.57M
  return dns_rdataslab_size(header) + sizeof(dns_ttl_t) +
1761
5.57M
         sizeof(dns_rdatatype_t) + sizeof(dns_rdataclass_t) + namelen;
1762
5.57M
}
1763
1764
static void
1765
maybe_update_recordsandsize(bool add, qpz_version_t *version,
1766
5.57M
          dns_slabheader_t *header, unsigned int namelen) {
1767
5.57M
  if (!EXISTS(header)) {
1768
0
    return;
1769
0
  }
1770
1771
11.1M
  RWLOCK(&version->rwlock, isc_rwlocktype_write);
1772
11.1M
  if (add) {
1773
5.46M
    version->records += dns_rdataslab_count(header);
1774
5.46M
    version->xfrsize += recordsize(header, namelen);
1775
5.46M
  } else {
1776
109k
    version->records -= dns_rdataslab_count(header);
1777
109k
    version->xfrsize -= recordsize(header, namelen);
1778
109k
  }
1779
11.1M
  RWUNLOCK(&version->rwlock, isc_rwlocktype_write);
1780
5.57M
}
1781
1782
static isc_result_t
1783
add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
1784
    qpz_version_t *version, dns_slabheader_t *newheader, unsigned int options,
1785
    bool loading, dns_rdataset_t *addedrdataset,
1786
6.22M
    isc_stdtime_t now ISC_ATTR_UNUSED DNS__DB_FLARG) {
1787
6.22M
  qpz_changed_t *changed = NULL;
1788
6.22M
  dns_slabtop_t *foundtop = NULL;
1789
6.22M
  dns_slabtop_t *priotop = NULL;
1790
6.22M
  dns_slabheader_t *merged = NULL;
1791
6.22M
  isc_result_t result;
1792
6.22M
  bool merge = false;
1793
6.22M
  uint32_t ntypes;
1794
1795
6.22M
  if ((options & DNS_DBADD_MERGE) != 0) {
1796
6.22M
    REQUIRE(version != NULL);
1797
6.22M
    merge = true;
1798
6.22M
  }
1799
1800
6.22M
  if (!loading) {
1801
    /*
1802
     * We always add a changed record, even if no changes end up
1803
     * being made to this node, because it's harmless and
1804
     * simplifies the code.
1805
     */
1806
0
    changed = add_changed(qpdb, newheader,
1807
0
              version DNS__DB_FLARG_PASS);
1808
0
  }
1809
1810
6.22M
  ntypes = 0;
1811
6.22M
  DNS_SLABTOP_FOREACH(top, node->data) {
1812
1.02M
    ++ntypes;
1813
1.02M
    if (prio_type(top->typepair)) {
1814
427k
      priotop = top;
1815
427k
    }
1816
1.02M
    if (top->typepair == newheader->typepair) {
1817
869k
      foundtop = top;
1818
869k
      break;
1819
869k
    }
1820
1.02M
  }
1821
1822
  /*
1823
   * If topheader isn't NULL, we've found the right type.  There may be
1824
   * IGNORE rdatasets between the top of the chain and the first real
1825
   * data.  We skip over them.
1826
   */
1827
6.22M
  dns_slabheader_t *header = NULL;
1828
6.22M
  if (foundtop != NULL) {
1829
869k
    dns_slabheader_t *tmp = NULL;
1830
869k
    cds_list_for_each_entry(tmp, &top->headers, headers_link) {
1831
869k
      if (!IGNORE(tmp)) {
1832
869k
        header = tmp;
1833
869k
        break;
1834
869k
      }
1835
869k
    }
1836
869k
  }
1837
1838
6.22M
  if (header != NULL) {
1839
    /*
1840
     * If 'merge' is true and header isn't empty/nonexistent,
1841
     * we'll try to create a new rdataset that is the union
1842
     * of 'newheader' and 'header'.
1843
     */
1844
869k
    if (merge && EXISTS(header)) {
1845
869k
      unsigned int flags = 0;
1846
869k
      INSIST(version->serial >= header->serial);
1847
869k
      merged = NULL;
1848
869k
      result = ISC_R_SUCCESS;
1849
1850
869k
      if ((options & DNS_DBADD_EXACT) != 0) {
1851
0
        flags |= DNS_RDATASLAB_EXACT;
1852
0
      }
1853
869k
      if ((options & DNS_DBADD_EXACTTTL) != 0 &&
1854
0
          newheader->ttl != header->ttl)
1855
0
      {
1856
0
        result = DNS_R_NOTEXACT;
1857
869k
      } else if (newheader->ttl != header->ttl) {
1858
5.56k
        flags |= DNS_RDATASLAB_FORCE;
1859
5.56k
      }
1860
869k
      if (result == ISC_R_SUCCESS) {
1861
869k
        result = dns_rdataslab_merge(
1862
869k
          header, newheader, qpdb->common.mctx,
1863
869k
          qpdb->common.rdclass,
1864
869k
          DNS_TYPEPAIR_TYPE(header->typepair),
1865
869k
          flags, qpdb->maxrrperset, &merged);
1866
869k
      }
1867
869k
      if (result == ISC_R_SUCCESS) {
1868
        /*
1869
         * If 'header' has the same serial number as
1870
         * we do, we could clean it up now if we knew
1871
         * that our caller had no references to it.
1872
         * We don't know this, however, so we leave it
1873
         * alone.  It will get cleaned up when
1874
         * clean_zone_node() runs.
1875
         */
1876
109k
        dns_slabheader_destroy(&newheader);
1877
109k
        newheader = merged;
1878
109k
        dns_slabheader_reset(newheader,
1879
109k
                 (dns_dbnode_t *)node);
1880
109k
        dns_slabheader_copycase(newheader, header);
1881
109k
        if (loading && RESIGN(newheader) &&
1882
0
            RESIGN(header) &&
1883
0
            resign_sooner(header, newheader))
1884
0
        {
1885
0
          newheader->resign = header->resign;
1886
0
          newheader->resign_lsb =
1887
0
            header->resign_lsb;
1888
0
        }
1889
760k
      } else {
1890
760k
        if (result == DNS_R_TOOMANYRECORDS) {
1891
0
          dns__db_logtoomanyrecords(
1892
0
            (dns_db_t *)qpdb, nodename,
1893
0
            DNS_TYPEPAIR_TYPE(
1894
0
              header->typepair),
1895
0
            "updating", qpdb->maxrrperset);
1896
0
        }
1897
760k
        dns_slabheader_destroy(&newheader);
1898
760k
        return result;
1899
760k
      }
1900
869k
    }
1901
1902
109k
    INSIST(version->serial >= header->serial);
1903
109k
    INSIST(foundtop->typepair == newheader->typepair);
1904
1905
109k
    if (loading) {
1906
109k
      if (RESIGN(newheader)) {
1907
0
        resigninsert(newheader);
1908
        /* resigndelete not needed here */
1909
0
      }
1910
1911
      /*
1912
       * There are no other references to 'header' when
1913
       * loading, so we MAY clean up 'header' now.
1914
       * Since we don't generate changed records when
1915
       * loading, we MUST clean up 'header' now.
1916
       */
1917
109k
      newheader->top = foundtop;
1918
109k
      cds_list_del(&header->headers_link);
1919
109k
      cds_list_add(&newheader->headers_link,
1920
109k
             &foundtop->headers);
1921
109k
      maybe_update_recordsandsize(false, version, header,
1922
109k
                nodename->length);
1923
1924
109k
      dns_slabheader_destroy(&header);
1925
109k
    } else {
1926
0
      if (RESIGN(newheader)) {
1927
0
        resigninsert(newheader);
1928
0
        resigndelete(qpdb, version,
1929
0
               header DNS__DB_FLARG_PASS);
1930
0
      }
1931
1932
0
      newheader->top = foundtop;
1933
0
      cds_list_add(&newheader->headers_link,
1934
0
             &foundtop->headers);
1935
1936
0
      node->dirty = true;
1937
0
      if (changed != NULL) {
1938
0
        changed->dirty = true;
1939
0
      }
1940
0
      maybe_update_recordsandsize(false, version, header,
1941
0
                nodename->length);
1942
0
    }
1943
5.35M
  } else {
1944
    /*
1945
     * No non-IGNORED rdatasets of the given type exist at
1946
     * this node.
1947
     *
1948
     * If we're trying to delete the type, don't bother.
1949
     */
1950
5.35M
    if (!EXISTS(newheader)) {
1951
0
      dns_slabheader_destroy(&newheader);
1952
0
      return DNS_R_UNCHANGED;
1953
0
    }
1954
1955
5.35M
    if (RESIGN(newheader)) {
1956
0
      resigninsert(newheader);
1957
0
      resigndelete(qpdb, version, header DNS__DB_FLARG_PASS);
1958
0
    }
1959
1960
5.35M
    if (foundtop != NULL) {
1961
      /*
1962
       * We have a list of rdatasets of the given type,
1963
       * but they're all marked IGNORE.  We simply insert
1964
       * the new rdataset at the head of the list.
1965
       *
1966
       * Ignored rdatasets cannot occur during loading, so
1967
       * we INSIST on it.
1968
       */
1969
0
      INSIST(!loading);
1970
1971
0
      newheader->top = foundtop;
1972
0
      cds_list_add(&newheader->headers_link,
1973
0
             &foundtop->headers);
1974
1975
0
      if (changed != NULL) {
1976
0
        changed->dirty = true;
1977
0
      }
1978
0
      node->dirty = true;
1979
5.35M
    } else {
1980
      /*
1981
       * No rdatasets of the given type exist at the node.
1982
       */
1983
1984
5.35M
      if (qpdb->maxtypepername > 0 &&
1985
0
          ntypes >= qpdb->maxtypepername)
1986
0
      {
1987
0
        dns_slabheader_destroy(&newheader);
1988
0
        return DNS_R_TOOMANYRECORDS;
1989
0
      }
1990
1991
5.35M
      dns_slabtop_t *newtop = dns_slabtop_new(
1992
5.35M
        node->mctx, newheader->typepair);
1993
1994
5.35M
      newheader->top = newtop;
1995
5.35M
      cds_list_add(&newheader->headers_link,
1996
5.35M
             &newtop->headers);
1997
1998
5.35M
      if (prio_type(newheader->typepair)) {
1999
        /* This is a priority type, prepend it */
2000
4.83M
        cds_list_add(&newtop->types_link, node->data);
2001
4.83M
      } else if (priotop != NULL) {
2002
        /* Append after the priority headers */
2003
1.39k
        cds_list_add(&newtop->types_link,
2004
1.39k
               &priotop->types_link);
2005
518k
      } else {
2006
        /* There were no priority headers */
2007
518k
        cds_list_add(&newtop->types_link, node->data);
2008
518k
      }
2009
5.35M
    }
2010
5.35M
  }
2011
2012
5.46M
  maybe_update_recordsandsize(true, version, newheader, nodename->length);
2013
2014
  /*
2015
   * Check if the node now contains CNAME and other data.
2016
   */
2017
5.46M
  if (cname_and_other(node, version->serial)) {
2018
19
    return DNS_R_CNAMEANDOTHER;
2019
19
  }
2020
2021
5.46M
  bindrdataset(qpdb, node, newheader, addedrdataset DNS__DB_FLARG_PASS);
2022
2023
5.46M
  return ISC_R_SUCCESS;
2024
5.46M
}
2025
2026
static void
2027
wildcardmagic(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name,
2028
2.51M
        dns_namespace_t nspace) {
2029
2.51M
  isc_result_t result;
2030
2.51M
  dns_name_t foundname;
2031
2.51M
  unsigned int n;
2032
2.51M
  qpznode_t *node = NULL;
2033
2034
2.51M
  dns_name_init(&foundname);
2035
2.51M
  n = dns_name_countlabels(name);
2036
2.51M
  INSIST(n >= 2);
2037
2.51M
  n--;
2038
2.51M
  dns_name_getlabelsequence(name, 1, n, &foundname);
2039
2040
  /* insert an empty node, if needed, to hold the wildcard bit */
2041
2.51M
  result = dns_qp_getname(qp, &foundname, nspace, (void **)&node, NULL);
2042
2.51M
  if (result != ISC_R_SUCCESS) {
2043
979k
    INSIST(node == NULL);
2044
979k
    node = new_qpznode(qpdb, &foundname, nspace);
2045
979k
    result = dns_qp_insert(qp, node, 0);
2046
979k
    INSIST(result == ISC_R_SUCCESS);
2047
979k
    qpznode_unref(node);
2048
979k
  }
2049
2050
2.51M
  node->wild = true;
2051
2.51M
}
2052
2053
static void
2054
addwildcards(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name,
2055
6.21M
       dns_namespace_t nspace) {
2056
6.21M
  dns_name_t foundname;
2057
6.21M
  unsigned int n, l, i;
2058
2059
6.21M
  dns_name_init(&foundname);
2060
6.21M
  n = dns_name_countlabels(name);
2061
6.21M
  l = dns_name_countlabels(&qpdb->common.origin);
2062
6.21M
  i = l + 1;
2063
19.9M
  while (i < n) {
2064
13.7M
    dns_name_getlabelsequence(name, n - i, i, &foundname);
2065
13.7M
    if (dns_name_iswildcard(&foundname)) {
2066
2.05M
      wildcardmagic(qpdb, qp, &foundname, nspace);
2067
2.05M
    }
2068
2069
13.7M
    i++;
2070
13.7M
  }
2071
6.21M
}
2072
2073
static isc_result_t
2074
loading_addrdataset(void *arg, const dns_name_t *name,
2075
6.22M
        dns_rdataset_t *rdataset DNS__DB_FLARG) {
2076
6.22M
  qpz_load_t *loadctx = arg;
2077
6.22M
  qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db;
2078
6.22M
  qpznode_t *node = NULL;
2079
6.22M
  isc_result_t result = ISC_R_SUCCESS;
2080
6.22M
  isc_region_t region;
2081
6.22M
  dns_slabheader_t *newheader = NULL;
2082
6.22M
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2083
6.22M
  isc_rwlock_t *nlock = NULL;
2084
2085
6.22M
  REQUIRE(rdataset->rdclass == qpdb->common.rdclass);
2086
2087
  /*
2088
   * SOA records are only allowed at top of zone.
2089
   */
2090
6.22M
  if (rdataset->type == dns_rdatatype_soa &&
2091
252
      !dns_name_equal(name, &qpdb->common.origin))
2092
1
  {
2093
1
    return DNS_R_NOTZONETOP;
2094
1
  }
2095
2096
6.22M
  if (rdataset->type != dns_rdatatype_nsec3 &&
2097
6.21M
      rdataset->covers != dns_rdatatype_nsec3)
2098
6.21M
  {
2099
6.21M
    addwildcards(qpdb, loadctx->tree, name, DNS_DBNAMESPACE_NORMAL);
2100
6.21M
  }
2101
2102
6.22M
  if (dns_name_iswildcard(name)) {
2103
459k
    if (rdataset->type == dns_rdatatype_ns) {
2104
      /*
2105
       * NS owners cannot legally be wild cards.
2106
       */
2107
120
      return DNS_R_INVALIDNS;
2108
120
    }
2109
2110
459k
    if (rdataset->type == dns_rdatatype_nsec3) {
2111
      /*
2112
       * NSEC3 owners cannot legally be wild cards.
2113
       */
2114
1
      return DNS_R_INVALIDNSEC3;
2115
1
    }
2116
2117
459k
    wildcardmagic(qpdb, loadctx->tree, name,
2118
459k
            DNS_DBNAMESPACE_NORMAL);
2119
459k
  }
2120
2121
6.22M
  loading_addnode(loadctx, name, rdataset->type, rdataset->covers, &node);
2122
6.22M
  result = dns_rdataslab_fromrdataset(rdataset, node->mctx, &region,
2123
6.22M
              qpdb->maxrrperset);
2124
6.22M
  if (result != ISC_R_SUCCESS) {
2125
48
    if (result == DNS_R_TOOMANYRECORDS) {
2126
0
      dns__db_logtoomanyrecords((dns_db_t *)qpdb, name,
2127
0
              rdataset->type, "adding",
2128
0
              qpdb->maxrrperset);
2129
0
    }
2130
48
    return result;
2131
48
  }
2132
2133
6.22M
  newheader = (dns_slabheader_t *)region.base;
2134
6.22M
  dns_slabheader_reset(newheader, (dns_dbnode_t *)node);
2135
6.22M
  newheader->ttl = rdataset->ttl;
2136
6.22M
  atomic_store(&newheader->trust, rdataset->trust);
2137
6.22M
  newheader->serial = 1;
2138
2139
6.22M
  dns_slabheader_setownercase(newheader, name);
2140
2141
6.22M
  if (rdataset->attributes.resign) {
2142
0
    DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN);
2143
0
    newheader->resign =
2144
0
      (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >>
2145
0
          1);
2146
0
    newheader->resign_lsb = rdataset->resign & 0x1;
2147
0
  }
2148
2149
6.22M
  nlock = qpzone_get_lock(node);
2150
6.22M
  NODE_WRLOCK(nlock, &nlocktype);
2151
6.22M
  result = add(qpdb, node, name, qpdb->current_version, newheader,
2152
6.22M
         DNS_DBADD_MERGE, true, NULL, 0 DNS__DB_FLARG_PASS);
2153
6.22M
  NODE_UNLOCK(nlock, &nlocktype);
2154
2155
6.22M
  if (result == ISC_R_SUCCESS &&
2156
5.46M
      delegating_type(qpdb, node, rdataset->type))
2157
4.81M
  {
2158
4.81M
    node->delegating = true;
2159
4.81M
  } else if (result == DNS_R_UNCHANGED) {
2160
760k
    result = ISC_R_SUCCESS;
2161
760k
  }
2162
2163
6.22M
  return result;
2164
6.22M
}
2165
2166
static void
2167
18.8k
loading_setup(void *arg) {
2168
18.8k
  qpz_load_t *loadctx = arg;
2169
18.8k
  qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db;
2170
2171
18.8k
  dns_qpmulti_write(qpdb->tree, &loadctx->tree);
2172
18.8k
}
2173
2174
static void
2175
18.8k
loading_commit(void *arg) {
2176
18.8k
  qpz_load_t *loadctx = arg;
2177
18.8k
  qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db;
2178
2179
18.8k
  if (loadctx->tree != NULL) {
2180
18.8k
    dns_qp_compact(loadctx->tree, DNS_QPGC_MAYBE);
2181
18.8k
    dns_qpmulti_commit(qpdb->tree, &loadctx->tree);
2182
18.8k
  }
2183
18.8k
}
2184
2185
static isc_result_t
2186
18.8k
beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
2187
18.8k
  qpz_load_t *loadctx = NULL;
2188
18.8k
  qpzonedb_t *qpdb = NULL;
2189
18.8k
  qpdb = (qpzonedb_t *)db;
2190
2191
18.8k
  REQUIRE(DNS_CALLBACK_VALID(callbacks));
2192
18.8k
  REQUIRE(VALID_QPZONE(qpdb));
2193
2194
18.8k
  loadctx = isc_mem_get(qpdb->common.mctx, sizeof(*loadctx));
2195
18.8k
  *loadctx = (qpz_load_t){ .db = db };
2196
2197
18.8k
  RWLOCK(&qpdb->lock, isc_rwlocktype_write);
2198
2199
18.8k
  REQUIRE((qpdb->attributes & (QPDB_ATTR_LOADED | QPDB_ATTR_LOADING)) ==
2200
18.8k
    0);
2201
18.8k
  qpdb->attributes |= QPDB_ATTR_LOADING;
2202
2203
18.8k
  RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
2204
2205
18.8k
  callbacks->add = loading_addrdataset;
2206
18.8k
  callbacks->setup = loading_setup;
2207
18.8k
  callbacks->commit = loading_commit;
2208
18.8k
  callbacks->add_private = loadctx;
2209
2210
18.8k
  return ISC_R_SUCCESS;
2211
18.8k
}
2212
2213
static isc_result_t
2214
18.8k
endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
2215
18.8k
  qpz_load_t *loadctx = NULL;
2216
18.8k
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
2217
2218
18.8k
  REQUIRE(VALID_QPZONE(qpdb));
2219
18.8k
  REQUIRE(DNS_CALLBACK_VALID(callbacks));
2220
18.8k
  loadctx = callbacks->add_private;
2221
18.8k
  REQUIRE(loadctx != NULL);
2222
18.8k
  REQUIRE(loadctx->db == db);
2223
2224
18.8k
  RWLOCK(&qpdb->lock, isc_rwlocktype_write);
2225
2226
18.8k
  REQUIRE((qpdb->attributes & QPDB_ATTR_LOADING) != 0);
2227
18.8k
  REQUIRE((qpdb->attributes & QPDB_ATTR_LOADED) == 0);
2228
2229
18.8k
  qpdb->attributes &= ~QPDB_ATTR_LOADING;
2230
18.8k
  qpdb->attributes |= QPDB_ATTR_LOADED;
2231
2232
18.8k
  if (qpdb->origin != NULL) {
2233
18.8k
    qpz_version_t *version = qpdb->current_version;
2234
18.8k
    RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
2235
18.8k
    setsecure(db, version, (dns_dbnode_t *)qpdb->origin);
2236
18.8k
  } else {
2237
0
    RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
2238
0
  }
2239
2240
18.8k
  callbacks->add = NULL;
2241
18.8k
  callbacks->setup = NULL;
2242
18.8k
  callbacks->commit = NULL;
2243
18.8k
  callbacks->add_private = NULL;
2244
2245
18.8k
  isc_mem_put(qpdb->common.mctx, loadctx, sizeof(*loadctx));
2246
2247
18.8k
  return ISC_R_SUCCESS;
2248
18.8k
}
2249
2250
static bool
2251
2
issecure(dns_db_t *db) {
2252
2
  qpzonedb_t *qpdb = NULL;
2253
2
  bool secure;
2254
2255
2
  qpdb = (qpzonedb_t *)db;
2256
2257
2
  REQUIRE(VALID_QPZONE(qpdb));
2258
2259
2
  RWLOCK(&qpdb->lock, isc_rwlocktype_read);
2260
2
  secure = qpdb->current_version->secure;
2261
2
  RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
2262
2263
2
  return secure;
2264
2
}
2265
2266
static isc_result_t
2267
getnsec3parameters(dns_db_t *db, dns_dbversion_t *dbversion, dns_hash_t *hash,
2268
       uint8_t *flags, uint16_t *iterations, unsigned char *salt,
2269
0
       size_t *salt_length) {
2270
0
  qpzonedb_t *qpdb = NULL;
2271
0
  isc_result_t result = ISC_R_NOTFOUND;
2272
0
  qpz_version_t *version = (qpz_version_t *)dbversion;
2273
2274
0
  qpdb = (qpzonedb_t *)db;
2275
2276
0
  REQUIRE(VALID_QPZONE(qpdb));
2277
0
  INSIST(version == NULL || version->qpdb == qpdb);
2278
2279
0
  RWLOCK(&qpdb->lock, isc_rwlocktype_read);
2280
0
  if (version == NULL) {
2281
0
    version = qpdb->current_version;
2282
0
  }
2283
2284
0
  if (version->havensec3) {
2285
0
    SET_IF_NOT_NULL(hash, version->hash);
2286
0
    if (salt != NULL && salt_length != NULL) {
2287
0
      REQUIRE(*salt_length >= version->salt_length);
2288
0
      memmove(salt, version->salt, version->salt_length);
2289
0
    }
2290
0
    SET_IF_NOT_NULL(salt_length, version->salt_length);
2291
0
    SET_IF_NOT_NULL(iterations, version->iterations);
2292
0
    SET_IF_NOT_NULL(flags, version->flags);
2293
0
    result = ISC_R_SUCCESS;
2294
0
  }
2295
0
  RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
2296
2297
0
  return result;
2298
0
}
2299
2300
static isc_result_t
2301
getsize(dns_db_t *db, dns_dbversion_t *dbversion, uint64_t *records,
2302
0
  uint64_t *xfrsize) {
2303
0
  qpzonedb_t *qpdb = NULL;
2304
0
  qpz_version_t *version = (qpz_version_t *)dbversion;
2305
0
  isc_result_t result = ISC_R_SUCCESS;
2306
2307
0
  qpdb = (qpzonedb_t *)db;
2308
2309
0
  REQUIRE(VALID_QPZONE(qpdb));
2310
0
  INSIST(version == NULL || version->qpdb == qpdb);
2311
2312
0
  RWLOCK(&qpdb->lock, isc_rwlocktype_read);
2313
0
  if (version == NULL) {
2314
0
    version = qpdb->current_version;
2315
0
  }
2316
2317
0
  RWLOCK(&version->rwlock, isc_rwlocktype_read);
2318
0
  SET_IF_NOT_NULL(records, version->records);
2319
2320
0
  SET_IF_NOT_NULL(xfrsize, version->xfrsize);
2321
0
  RWUNLOCK(&version->rwlock, isc_rwlocktype_read);
2322
0
  RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
2323
2324
0
  return result;
2325
0
}
2326
2327
static isc_result_t
2328
0
setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) {
2329
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
2330
0
  dns_slabheader_t *header = NULL, oldheader;
2331
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2332
0
  isc_rwlock_t *nlock = NULL;
2333
2334
0
  REQUIRE(VALID_QPZONE(qpdb));
2335
0
  REQUIRE(rdataset != NULL);
2336
0
  REQUIRE(rdataset->methods == &dns_rdataslab_rdatasetmethods);
2337
2338
0
  header = dns_rdataset_getheader(rdataset);
2339
2340
0
  nlock = qpzone_get_lock(HEADERNODE(header));
2341
0
  NODE_WRLOCK(nlock, &nlocktype);
2342
2343
0
  oldheader = *header;
2344
2345
  /*
2346
   * Only break the heap invariant (by adjusting resign and resign_lsb)
2347
   * if we are going to be restoring it by calling isc_heap_increased
2348
   * or isc_heap_decreased.
2349
   */
2350
0
  if (resign != 0) {
2351
0
    header->resign = (isc_stdtime_t)(dns_time64_from32(resign) >>
2352
0
             1);
2353
0
    header->resign_lsb = resign & 0x1;
2354
0
  }
2355
0
  if (header->heap_index != 0) {
2356
0
    INSIST(RESIGN(header));
2357
0
    LOCK(get_heap_lock(header));
2358
0
    if (resign == 0) {
2359
0
      isc_heap_delete(HEADERNODE(header)->heap->heap,
2360
0
          header->heap_index);
2361
0
      header->heap_index = 0;
2362
0
    } else if (resign_sooner(header, &oldheader)) {
2363
0
      isc_heap_increased(HEADERNODE(header)->heap->heap,
2364
0
             header->heap_index);
2365
0
    } else if (resign_sooner(&oldheader, header)) {
2366
0
      isc_heap_decreased(HEADERNODE(header)->heap->heap,
2367
0
             header->heap_index);
2368
0
    }
2369
0
    UNLOCK(get_heap_lock(header));
2370
0
  } else if (resign != 0) {
2371
0
    DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_RESIGN);
2372
0
    resigninsert(header);
2373
0
  }
2374
0
  NODE_UNLOCK(nlock, &nlocktype);
2375
0
  return ISC_R_SUCCESS;
2376
0
}
2377
2378
static isc_result_t
2379
getsigningtime(dns_db_t *db, isc_stdtime_t *resign, dns_name_t *foundname,
2380
0
         dns_typepair_t *typepair) {
2381
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
2382
0
  dns_slabheader_t *header = NULL;
2383
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2384
0
  isc_rwlock_t *nlock = NULL;
2385
0
  isc_result_t result = ISC_R_NOTFOUND;
2386
2387
0
  REQUIRE(VALID_QPZONE(qpdb));
2388
0
  REQUIRE(resign != NULL);
2389
0
  REQUIRE(foundname != NULL);
2390
0
  REQUIRE(typepair != NULL);
2391
2392
0
  LOCK(&qpdb->heap->lock);
2393
0
  header = isc_heap_element(qpdb->heap->heap, 1);
2394
0
  if (header == NULL) {
2395
0
    UNLOCK(&qpdb->heap->lock);
2396
0
    return ISC_R_NOTFOUND;
2397
0
  }
2398
0
  nlock = qpzone_get_lock(HEADERNODE(header));
2399
0
  UNLOCK(&qpdb->heap->lock);
2400
2401
0
again:
2402
0
  NODE_RDLOCK(nlock, &nlocktype);
2403
2404
0
  LOCK(&qpdb->heap->lock);
2405
0
  header = isc_heap_element(qpdb->heap->heap, 1);
2406
2407
0
  if (header != NULL && qpzone_get_lock(HEADERNODE(header)) != nlock) {
2408
0
    UNLOCK(&qpdb->heap->lock);
2409
0
    NODE_UNLOCK(nlock, &nlocktype);
2410
2411
0
    nlock = qpzone_get_lock(HEADERNODE(header));
2412
0
    goto again;
2413
0
  }
2414
2415
0
  if (header != NULL) {
2416
0
    *resign = RESIGN(header)
2417
0
          ? (header->resign << 1) | header->resign_lsb
2418
0
          : 0;
2419
0
    dns_name_copy(&HEADERNODE(header)->name, foundname);
2420
0
    *typepair = header->typepair;
2421
0
    result = ISC_R_SUCCESS;
2422
0
  }
2423
0
  UNLOCK(&qpdb->heap->lock);
2424
0
  NODE_UNLOCK(nlock, &nlocktype);
2425
2426
0
  return result;
2427
0
}
2428
2429
static isc_result_t
2430
2
setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
2431
2
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
2432
2433
2
  REQUIRE(VALID_QPZONE(qpdb));
2434
2
  REQUIRE(!IS_STUB(qpdb));
2435
2
  REQUIRE(stats != NULL);
2436
2437
2
  isc_stats_attach(stats, &qpdb->gluecachestats);
2438
2
  return ISC_R_SUCCESS;
2439
2
}
2440
2441
static isc_result_t
2442
findnodeintree(qpzonedb_t *qpdb, const dns_name_t *name, bool create,
2443
6
         bool nsec3, dns_dbnode_t **nodep DNS__DB_FLARG) {
2444
6
  isc_result_t result;
2445
6
  qpznode_t *node = NULL;
2446
6
  dns_namespace_t nspace = nsec3 ? DNS_DBNAMESPACE_NSEC3
2447
6
               : DNS_DBNAMESPACE_NORMAL;
2448
6
  dns_qpread_t qpr = { 0 };
2449
6
  dns_qp_t *qp = NULL;
2450
2451
6
  if (create) {
2452
0
    dns_qpmulti_write(qpdb->tree, &qp);
2453
6
  } else {
2454
6
    dns_qpmulti_query(qpdb->tree, &qpr);
2455
6
    qp = (dns_qp_t *)&qpr;
2456
6
  }
2457
2458
6
  result = dns_qp_getname(qp, name, nspace, (void **)&node, NULL);
2459
6
  if (result != ISC_R_SUCCESS) {
2460
0
    if (!create) {
2461
0
      dns_qpread_destroy(qpdb->tree, &qpr);
2462
0
      return result;
2463
0
    }
2464
2465
0
    node = new_qpznode(qpdb, name, nspace);
2466
0
    result = dns_qp_insert(qp, node, 0);
2467
0
    INSIST(result == ISC_R_SUCCESS);
2468
0
    qpznode_unref(node);
2469
2470
0
    if (!nsec3) {
2471
0
      addwildcards(qpdb, qp, name, nspace);
2472
0
      if (dns_name_iswildcard(name)) {
2473
0
        wildcardmagic(qpdb, qp, name, nspace);
2474
0
      }
2475
0
    }
2476
0
  }
2477
2478
6
  INSIST(node->nspace == DNS_DBNAMESPACE_NSEC3 || !nsec3);
2479
2480
6
  qpznode_acquire(node DNS__DB_FLARG_PASS);
2481
2482
6
  if (create) {
2483
0
    dns_qp_compact(qp, DNS_QPGC_MAYBE);
2484
0
    dns_qpmulti_commit(qpdb->tree, &qp);
2485
6
  } else {
2486
6
    dns_qpread_destroy(qpdb->tree, &qpr);
2487
6
  }
2488
2489
6
  *nodep = (dns_dbnode_t *)node;
2490
2491
6
  return ISC_R_SUCCESS;
2492
6
}
2493
2494
static isc_result_t
2495
qpzone_findnode(dns_db_t *db, const dns_name_t *name, bool create,
2496
    dns_clientinfomethods_t *methods ISC_ATTR_UNUSED,
2497
    dns_clientinfo_t *clientinfo ISC_ATTR_UNUSED,
2498
6
    dns_dbnode_t **nodep DNS__DB_FLARG) {
2499
6
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
2500
2501
6
  REQUIRE(VALID_QPZONE(qpdb));
2502
2503
6
  return findnodeintree(qpdb, name, create, false,
2504
6
            nodep DNS__DB_FLARG_PASS);
2505
6
}
2506
2507
static isc_result_t
2508
qpzone_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
2509
0
         dns_dbnode_t **nodep DNS__DB_FLARG) {
2510
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
2511
2512
0
  REQUIRE(VALID_QPZONE(qpdb));
2513
2514
0
  return findnodeintree(qpdb, name, create, true,
2515
0
            nodep DNS__DB_FLARG_PASS);
2516
0
}
2517
2518
static bool
2519
0
matchparams(dns_slabheader_t *header, qpz_search_t *search) {
2520
0
  dns_rdata_nsec3_t nsec3;
2521
0
  unsigned char *raw = NULL;
2522
0
  unsigned int rdlen, count;
2523
0
  isc_region_t region;
2524
0
  isc_result_t result;
2525
2526
0
  REQUIRE(header->typepair == DNS_TYPEPAIR(dns_rdatatype_nsec3));
2527
2528
0
  raw = (unsigned char *)header + sizeof(*header);
2529
0
  count = get_uint16(raw);
2530
2531
0
  while (count-- > 0) {
2532
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
2533
2534
0
    rdlen = get_uint16(raw);
2535
0
    region.base = raw;
2536
0
    region.length = rdlen;
2537
0
    dns_rdata_fromregion(&rdata, search->qpdb->common.rdclass,
2538
0
             dns_rdatatype_nsec3, &region);
2539
0
    raw += rdlen;
2540
0
    result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
2541
0
    INSIST(result == ISC_R_SUCCESS);
2542
0
    if (nsec3.hash == search->version->hash &&
2543
0
        nsec3.iterations == search->version->iterations &&
2544
0
        nsec3.salt_length == search->version->salt_length &&
2545
0
        memcmp(nsec3.salt, search->version->salt,
2546
0
         nsec3.salt_length) == 0)
2547
0
    {
2548
0
      return true;
2549
0
    }
2550
0
  }
2551
0
  return false;
2552
0
}
2553
2554
static isc_result_t
2555
qpzone_setup_delegation(qpz_search_t *search, dns_dbnode_t **nodep,
2556
      dns_name_t *foundname, dns_rdataset_t *rdataset,
2557
0
      dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
2558
0
  dns_name_t *zcname = NULL;
2559
0
  dns_typepair_t typepair;
2560
0
  qpznode_t *node = NULL;
2561
2562
0
  REQUIRE(search != NULL);
2563
0
  REQUIRE(search->zonecut != NULL);
2564
0
  REQUIRE(search->zonecut_header != NULL);
2565
2566
  /*
2567
   * The caller MUST NOT be holding any node locks.
2568
   */
2569
2570
0
  node = search->zonecut;
2571
0
  typepair = search->zonecut_header->typepair;
2572
2573
  /*
2574
   * If we have to set foundname, we do it before anything else.
2575
   * If we were to set foundname after we had set nodep or bound the
2576
   * rdataset, then we'd have to undo that work if dns_name_copy()
2577
   * failed.  By setting foundname first, there's nothing to undo if
2578
   * we have trouble.
2579
   */
2580
0
  if (foundname != NULL && search->copy_name) {
2581
0
    zcname = dns_fixedname_name(&search->zonecut_name);
2582
0
    dns_name_copy(zcname, foundname);
2583
0
  }
2584
0
  if (nodep != NULL) {
2585
    /*
2586
     * Note that we don't have to increment the node's reference
2587
     * count here because we're going to use the reference we
2588
     * already have in the search block.
2589
     */
2590
0
    *nodep = (dns_dbnode_t *)node;
2591
0
    search->need_cleanup = false;
2592
0
  }
2593
0
  if (rdataset != NULL) {
2594
0
    isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2595
0
    isc_rwlock_t *nlock = qpzone_get_lock(node);
2596
0
    NODE_RDLOCK(nlock, &nlocktype);
2597
0
    bindrdataset(search->qpdb, node, search->zonecut_header,
2598
0
           rdataset DNS__DB_FLARG_PASS);
2599
0
    if (sigrdataset != NULL && search->zonecut_sigheader != NULL) {
2600
0
      bindrdataset(search->qpdb, node,
2601
0
             search->zonecut_sigheader,
2602
0
             sigrdataset DNS__DB_FLARG_PASS);
2603
0
    }
2604
0
    NODE_UNLOCK(nlock, &nlocktype);
2605
0
  }
2606
2607
0
  if (typepair == DNS_TYPEPAIR(dns_rdatatype_dname)) {
2608
0
    return DNS_R_DNAME;
2609
0
  }
2610
0
  return DNS_R_DELEGATION;
2611
0
}
2612
2613
typedef enum { FORWARD, BACK } direction_t;
2614
2615
/*
2616
 * Step backwards or forwards through the database until we find a
2617
 * node with data in it for the desired version. If 'nextname' is not NULL,
2618
 * and we found a predecessor or successor, save the name we found in it.
2619
 * Return true if we found a predecessor or successor.
2620
 */
2621
static bool
2622
step(qpz_search_t *search, dns_qpiter_t *it, direction_t direction,
2623
53
     dns_name_t *nextname) {
2624
53
  dns_fixedname_t fnodename;
2625
53
  dns_name_t *nodename = dns_fixedname_initname(&fnodename);
2626
53
  qpznode_t *node = NULL;
2627
53
  isc_result_t result = ISC_R_SUCCESS;
2628
2629
53
  result = dns_qpiter_current(it, nodename, (void **)&node, NULL);
2630
159
  while (result == ISC_R_SUCCESS) {
2631
106
    isc_rwlock_t *nlock = qpzone_get_lock(node);
2632
106
    isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2633
106
    dns_slabheader_t *found = NULL;
2634
2635
106
    NODE_RDLOCK(nlock, &nlocktype);
2636
106
    DNS_SLABTOP_FOREACH(top, node->data) {
2637
0
      found = first_existing_header(top, search->serial);
2638
0
    }
2639
106
    NODE_UNLOCK(nlock, &nlocktype);
2640
106
    if (found != NULL) {
2641
0
      break;
2642
0
    }
2643
2644
106
    if (direction == FORWARD) {
2645
106
      result = dns_qpiter_next(it, nodename, (void **)&node,
2646
106
             NULL);
2647
106
    } else {
2648
0
      result = dns_qpiter_prev(it, nodename, (void **)&node,
2649
0
             NULL);
2650
0
    }
2651
106
  };
2652
53
  if (result == ISC_R_SUCCESS) {
2653
0
    if (nextname != NULL) {
2654
0
      dns_name_copy(nodename, nextname);
2655
0
    }
2656
0
    return true;
2657
0
  }
2658
2659
53
  return false;
2660
53
}
2661
2662
static bool
2663
53
activeempty(qpz_search_t *search, dns_qpiter_t *it, const dns_name_t *current) {
2664
53
  dns_fixedname_t fnext;
2665
53
  dns_name_t *next = dns_fixedname_initname(&fnext);
2666
2667
  /*
2668
   * The iterator is currently pointed at the predecessor
2669
   * of the name we were searching for. Step the iterator
2670
   * forward, then step() will continue forward until it
2671
   * finds a node with active data. If that node is a
2672
   * subdomain of the one we were looking for, then we're
2673
   * at an active empty nonterminal node.
2674
   */
2675
53
  isc_result_t result = dns_qpiter_next(it, NULL, NULL, NULL);
2676
53
  if (result != ISC_R_SUCCESS) {
2677
    /* An ENT at the end of the zone is impossible */
2678
0
    return false;
2679
0
  }
2680
53
  return step(search, it, FORWARD, next) &&
2681
0
         dns_name_issubdomain(next, current);
2682
53
}
2683
2684
static bool
2685
wildcard_blocked(qpz_search_t *search, const dns_name_t *qname,
2686
0
     dns_name_t *wname) {
2687
0
  isc_result_t result;
2688
0
  dns_fixedname_t fnext;
2689
0
  dns_fixedname_t fprev;
2690
0
  dns_name_t *next = NULL, *prev = NULL;
2691
0
  dns_name_t name;
2692
0
  dns_name_t rname;
2693
0
  dns_name_t tname;
2694
0
  dns_qpiter_t it;
2695
0
  bool check_next = false;
2696
0
  bool check_prev = false;
2697
0
  unsigned int n;
2698
2699
0
  dns_name_init(&name);
2700
0
  dns_name_init(&tname);
2701
0
  dns_name_init(&rname);
2702
0
  next = dns_fixedname_initname(&fnext);
2703
0
  prev = dns_fixedname_initname(&fprev);
2704
2705
  /*
2706
   * The qname seems to have matched a wildcard, but we
2707
   * need to find out if there's an empty nonterminal node
2708
   * between the wildcard level and the qname.
2709
   *
2710
   * search->iter should now be pointing at the predecessor
2711
   * of the searched-for name. We are using a local copy of the
2712
   * iterator so as not to change the state of search->iter.
2713
   * step() will walk backward until we find a predecessor with
2714
   * data.
2715
   */
2716
0
  it = search->iter;
2717
0
  check_prev = step(search, &it, BACK, prev);
2718
2719
  /* Now reset the iterator and look for a successor with data. */
2720
0
  it = search->iter;
2721
0
  result = dns_qpiter_next(&it, NULL, NULL, NULL);
2722
0
  if (result == ISC_R_SUCCESS) {
2723
0
    check_next = step(search, &it, FORWARD, next);
2724
0
  }
2725
2726
0
  if (!check_prev && !check_next) {
2727
    /* No predecessor or successor was found at all? */
2728
0
    return false;
2729
0
  }
2730
2731
0
  dns_name_clone(qname, &rname);
2732
2733
  /*
2734
   * Remove the wildcard label to find the terminal name.
2735
   */
2736
0
  n = dns_name_countlabels(wname);
2737
0
  dns_name_getlabelsequence(wname, 1, n - 1, &tname);
2738
2739
0
  do {
2740
0
    if ((check_prev && dns_name_issubdomain(prev, &rname)) ||
2741
0
        (check_next && dns_name_issubdomain(next, &rname)))
2742
0
    {
2743
0
      return true;
2744
0
    }
2745
2746
    /*
2747
     * Remove the leftmost label from the qname and check again.
2748
     */
2749
0
    n = dns_name_countlabels(&rname);
2750
0
    dns_name_getlabelsequence(&rname, 1, n - 1, &rname);
2751
0
  } while (!dns_name_equal(&rname, &tname));
2752
2753
0
  return false;
2754
0
}
2755
2756
static bool
2757
0
node_active(qpz_search_t *search, qpznode_t *node) {
2758
0
  DNS_SLABTOP_FOREACH(top, node->data) {
2759
0
    if (first_existing_header(top, search->serial) != NULL) {
2760
0
      return true;
2761
0
    }
2762
0
  }
2763
0
  return false;
2764
0
}
2765
2766
static isc_result_t
2767
find_wildcard(qpz_search_t *search, qpznode_t **nodep, const dns_name_t *qname,
2768
0
        dns_namespace_t nspace) {
2769
0
  isc_result_t result = ISC_R_NOTFOUND;
2770
2771
  /*
2772
   * Examine each ancestor level.  If the level's wild bit
2773
   * is set, then construct the corresponding wildcard name and
2774
   * search for it.  If the wildcard node exists, and is active in
2775
   * this version, we're done.  If not, then we next check to see
2776
   * if the ancestor is active in this version.  If so, then there
2777
   * can be no possible wildcard match and again we're done.  If not,
2778
   * continue the search.
2779
   */
2780
0
  for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) {
2781
0
    qpznode_t *node = NULL;
2782
0
    isc_rwlock_t *nlock = NULL;
2783
0
    isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2784
0
    bool wild, active;
2785
2786
0
    dns_qpchain_node(&search->chain, i, NULL, (void **)&node, NULL);
2787
2788
0
    nlock = qpzone_get_lock(node);
2789
0
    NODE_RDLOCK(nlock, &nlocktype);
2790
    /*
2791
     * First we try to figure out if this node is active in
2792
     * the search's version.  We do this now, even though we
2793
     * may not need the information, because it simplifies the
2794
     * locking and code flow.
2795
     */
2796
0
    active = node_active(search, node);
2797
0
    wild = node->wild;
2798
0
    NODE_UNLOCK(nlock, &nlocktype);
2799
2800
0
    if (wild) {
2801
0
      qpznode_t *wnode = NULL;
2802
0
      dns_fixedname_t fwname;
2803
0
      dns_name_t *wname = dns_fixedname_initname(&fwname);
2804
0
      dns_qpiter_t wit;
2805
0
      bool wactive;
2806
2807
      /*
2808
       * Construct the wildcard name for this level.
2809
       */
2810
0
      result = dns_name_concatenate(dns_wildcardname,
2811
0
                  &node->name, wname);
2812
0
      if (result != ISC_R_SUCCESS) {
2813
0
        break;
2814
0
      }
2815
2816
0
      result = dns_qp_lookup(&search->qpr, wname, nspace,
2817
0
                 NULL, &wit, NULL,
2818
0
                 (void **)&wnode, NULL);
2819
0
      if (result == ISC_R_SUCCESS) {
2820
        /*
2821
         * We have found the wildcard node.  If it
2822
         * is active in the search's version, we're
2823
         * done.
2824
         */
2825
0
        nlock = qpzone_get_lock(wnode);
2826
0
        NODE_RDLOCK(nlock, &nlocktype);
2827
0
        wactive = node_active(search, wnode);
2828
0
        NODE_UNLOCK(nlock, &nlocktype);
2829
0
        if (wactive || activeempty(search, &wit, wname))
2830
0
        {
2831
0
          if (wildcard_blocked(search, qname,
2832
0
                   wname))
2833
0
          {
2834
0
            return ISC_R_NOTFOUND;
2835
0
          }
2836
2837
          /*
2838
           * The wildcard node is active!
2839
           *
2840
           * Note: result is still ISC_R_SUCCESS
2841
           * so we don't have to set it.
2842
           */
2843
0
          *nodep = wnode;
2844
0
          break;
2845
0
        }
2846
0
      } else if (result != ISC_R_NOTFOUND &&
2847
0
           result != DNS_R_PARTIALMATCH)
2848
0
      {
2849
        /*
2850
         * An error has occurred.  Bail out.
2851
         */
2852
0
        break;
2853
0
      }
2854
0
    }
2855
2856
0
    if (active) {
2857
      /*
2858
       * The level node is active.  Any wildcarding
2859
       * present at higher levels has no
2860
       * effect and we're done.
2861
       */
2862
0
      result = ISC_R_NOTFOUND;
2863
0
      break;
2864
0
    }
2865
0
  }
2866
2867
0
  return result;
2868
0
}
2869
2870
/*
2871
 * Find node of the NSEC/NSEC3 record preceding 'name'.
2872
 */
2873
static isc_result_t
2874
previous_closest_nsec(dns_rdatatype_t type, qpz_search_t *search,
2875
          dns_name_t *name, qpznode_t **nodep, dns_qpiter_t *nit,
2876
0
          bool *firstp) {
2877
0
  isc_result_t result;
2878
0
  dns_qpread_t qpr;
2879
2880
0
  REQUIRE(nodep != NULL && *nodep == NULL);
2881
0
  REQUIRE(type == dns_rdatatype_nsec3 || firstp != NULL);
2882
2883
0
  if (type == dns_rdatatype_nsec3) {
2884
0
    result = dns_qpiter_prev(&search->iter, name, (void **)nodep,
2885
0
           NULL);
2886
0
    return result;
2887
0
  }
2888
2889
0
  dns_qpmulti_query(search->qpdb->tree, &qpr);
2890
2891
0
  for (;;) {
2892
0
    if (*firstp) {
2893
      /*
2894
       * This is the first attempt to find 'name' in the
2895
       * NSEC namespace.
2896
       */
2897
0
      *firstp = false;
2898
0
      result = dns_qp_lookup(&qpr, name, DNS_DBNAMESPACE_NSEC,
2899
0
                 NULL, nit, NULL, NULL, NULL);
2900
0
      INSIST(result != ISC_R_NOTFOUND);
2901
0
      if (result == ISC_R_SUCCESS) {
2902
        /*
2903
         * If we find an exact match in the NSEC
2904
         * namespace on our first attempt, it
2905
         * implies that the corresponding node in
2906
         * the normal namespace had an unacceptable
2907
         * NSEC record; we want the previous node
2908
         * in the NSEC tree.
2909
         */
2910
0
        result = dns_qpiter_prev(nit, name, NULL, NULL);
2911
0
      } else if (result == DNS_R_PARTIALMATCH) {
2912
        /*
2913
         * This was a partial match, so the
2914
         * iterator is already at the previous
2915
         * node in the NSEC namespace, which is
2916
         * what we want.
2917
         */
2918
0
        dns_qpiter_current(nit, name, NULL, NULL);
2919
0
        result = ISC_R_SUCCESS;
2920
0
      }
2921
0
    } else {
2922
      /*
2923
       * We've taken at least two steps back through the
2924
       * NSEC namespace. The previous steps must have
2925
       * found nodes with NSEC records, but they didn't
2926
       * work; perhaps they lacked signature records.
2927
       * Keep searching.
2928
       */
2929
0
      result = dns_qpiter_prev(nit, name, NULL, NULL);
2930
0
    }
2931
0
    if (result != ISC_R_SUCCESS) {
2932
0
      break;
2933
0
    }
2934
2935
0
    *nodep = NULL;
2936
0
    result = dns_qp_lookup(
2937
0
      &search->qpr, name, DNS_DBNAMESPACE_NORMAL, NULL,
2938
0
      &search->iter, &search->chain, (void **)nodep, NULL);
2939
0
    if (result == ISC_R_SUCCESS) {
2940
0
      break;
2941
0
    }
2942
2943
    /*
2944
     * There should always be a node in the normal namespace
2945
     * with the same name as the node in the NSEC namespace,
2946
     * except when nodes in the NSEC namespace are awaiting
2947
     * deletion.
2948
     */
2949
0
    if (result != DNS_R_PARTIALMATCH && result != ISC_R_NOTFOUND) {
2950
0
      isc_log_write(DNS_LOGCATEGORY_DATABASE,
2951
0
              DNS_LOGMODULE_DB, ISC_LOG_ERROR,
2952
0
              "previous_closest_nsec(): %s",
2953
0
              isc_result_totext(result));
2954
0
      result = DNS_R_BADDB;
2955
0
      break;
2956
0
    }
2957
0
  }
2958
2959
0
  dns_qpread_destroy(search->qpdb->tree, &qpr);
2960
0
  return result;
2961
0
}
2962
2963
/*
2964
 * Find the NSEC/NSEC3 which is at or before the name being sought.
2965
 * For NSEC3 records only NSEC3 records that match the
2966
 * current NSEC3PARAM record are considered.
2967
 */
2968
static isc_result_t
2969
find_closest_nsec(qpz_search_t *search, dns_dbnode_t **nodep,
2970
      dns_name_t *foundname, dns_rdataset_t *rdataset,
2971
      dns_rdataset_t *sigrdataset, bool nsec3,
2972
0
      bool secure DNS__DB_FLARG) {
2973
0
  qpznode_t *node = NULL, *prevnode = NULL;
2974
0
  dns_qpiter_t nseciter;
2975
0
  bool empty_node;
2976
0
  isc_result_t result;
2977
0
  dns_fixedname_t fname;
2978
0
  dns_name_t *name = dns_fixedname_initname(&fname);
2979
0
  dns_rdatatype_t matchtype = nsec3 ? dns_rdatatype_nsec3
2980
0
            : dns_rdatatype_nsec;
2981
0
  dns_typepair_t typepair = DNS_TYPEPAIR(matchtype);
2982
0
  dns_typepair_t sigpair = DNS_SIGTYPEPAIR(matchtype);
2983
0
  bool wraps = nsec3;
2984
0
  bool first = true;
2985
0
  bool need_sig = secure;
2986
2987
  /*
2988
   * When a lookup is unsuccessful, the QP iterator will already
2989
   * be pointing at the node preceding the searched-for name in
2990
   * the normal namespace. We'll check there first, assuming it will
2991
   * be right much of the time. If we don't find an NSEC there,
2992
   * then we start using the auxiliary NSEC namespace to find
2993
   * the next predecessor.
2994
   */
2995
0
  result = dns_qpiter_current(&search->iter, name, (void **)&node, NULL);
2996
0
  if (result != ISC_R_SUCCESS) {
2997
0
    return result;
2998
0
  }
2999
0
again:
3000
0
  do {
3001
0
    dns_slabheader_t *found = NULL, *foundsig = NULL;
3002
0
    isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3003
0
    isc_rwlock_t *nlock = qpzone_get_lock(node);
3004
0
    NODE_RDLOCK(nlock, &nlocktype);
3005
0
    empty_node = true;
3006
0
    DNS_SLABTOP_FOREACH(top, node->data) {
3007
      /*
3008
       * Look for an active, extant NSEC or RRSIG NSEC.
3009
       */
3010
0
      dns_slabheader_t *header =
3011
0
        first_existing_header(top, search->serial);
3012
0
      if (header != NULL) {
3013
        /*
3014
         * We now know that there is at least one
3015
         * active rdataset at this node.
3016
         */
3017
0
        empty_node = false;
3018
0
        if (top->typepair == typepair) {
3019
0
          found = header;
3020
0
          if (foundsig != NULL) {
3021
0
            break;
3022
0
          }
3023
0
        } else if (top->typepair == sigpair) {
3024
0
          foundsig = header;
3025
0
          if (found != NULL) {
3026
0
            break;
3027
0
          }
3028
0
        }
3029
0
      }
3030
0
    }
3031
0
    if (!empty_node) {
3032
0
      if (found != NULL && search->version->havensec3 &&
3033
0
          found->typepair ==
3034
0
            DNS_TYPEPAIR(dns_rdatatype_nsec3) &&
3035
0
          !matchparams(found, search))
3036
0
      {
3037
0
        empty_node = true;
3038
0
        found = NULL;
3039
0
        foundsig = NULL;
3040
0
        result = previous_closest_nsec(typepair, search,
3041
0
                     name, &prevnode,
3042
0
                     NULL, NULL);
3043
0
      } else if (found != NULL &&
3044
0
           (foundsig != NULL || !need_sig))
3045
0
      {
3046
        /*
3047
         * We've found the right NSEC/NSEC3 record.
3048
         *
3049
         * Note: for this to really be the right
3050
         * NSEC record, it's essential that the NSEC
3051
         * records of any nodes obscured by a zone
3052
         * cut have been removed; we assume this is
3053
         * the case.
3054
         */
3055
0
        dns_name_copy(name, foundname);
3056
0
        if (nodep != NULL) {
3057
0
          qpznode_acquire(
3058
0
            node DNS__DB_FLARG_PASS);
3059
0
          *nodep = (dns_dbnode_t *)node;
3060
0
        }
3061
0
        bindrdataset(search->qpdb, node, found,
3062
0
               rdataset DNS__DB_FLARG_PASS);
3063
0
        if (foundsig != NULL) {
3064
0
          bindrdataset(
3065
0
            search->qpdb, node, foundsig,
3066
0
            sigrdataset DNS__DB_FLARG_PASS);
3067
0
        }
3068
0
      } else if (found == NULL && foundsig == NULL) {
3069
        /*
3070
         * This node is active, but has no NSEC or
3071
         * RRSIG NSEC.  That means it's glue or
3072
         * other obscured zone data that isn't
3073
         * relevant for our search.  Treat the
3074
         * node as if it were empty and keep looking.
3075
         */
3076
0
        empty_node = true;
3077
0
        result = previous_closest_nsec(
3078
0
          typepair, search, name, &prevnode,
3079
0
          &nseciter, &first);
3080
0
      } else {
3081
        /*
3082
         * We found an active node, but either the
3083
         * NSEC or the RRSIG NSEC is missing.  This
3084
         * shouldn't happen.
3085
         */
3086
0
        result = DNS_R_BADDB;
3087
0
      }
3088
0
    } else {
3089
      /*
3090
       * This node isn't active.  We've got to keep
3091
       * looking.
3092
       */
3093
0
      result = previous_closest_nsec(typepair, search, name,
3094
0
                   &prevnode, &nseciter,
3095
0
                   &first);
3096
0
    }
3097
0
    NODE_UNLOCK(nlock, &nlocktype);
3098
0
    node = prevnode;
3099
0
    prevnode = NULL;
3100
0
  } while (empty_node && result == ISC_R_SUCCESS);
3101
3102
0
  if (result == ISC_R_NOMORE && wraps) {
3103
0
    result = dns_qpiter_prev(&search->iter, name, (void **)&node,
3104
0
           NULL);
3105
0
    if (result == ISC_R_SUCCESS) {
3106
0
      wraps = false;
3107
0
      goto again;
3108
0
    }
3109
0
  }
3110
3111
  /*
3112
   * If the result is ISC_R_NOMORE, then we got to the beginning of
3113
   * the database and didn't find a NSEC record.  This shouldn't
3114
   * happen.
3115
   */
3116
0
  if (result == ISC_R_NOMORE) {
3117
0
    result = DNS_R_BADDB;
3118
0
  }
3119
3120
0
  return result;
3121
0
}
3122
3123
static isc_result_t
3124
53
qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
3125
53
  qpz_search_t *search = arg;
3126
53
  dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL;
3127
53
  dns_slabheader_t *ns_header = NULL;
3128
53
  dns_slabheader_t *found = NULL;
3129
53
  isc_result_t result = DNS_R_CONTINUE;
3130
53
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3131
53
  isc_rwlock_t *nlock = qpzone_get_lock(node);
3132
3133
53
  NODE_RDLOCK(nlock, &nlocktype);
3134
3135
  /*
3136
   * Look for an NS or DNAME rdataset active in our version.
3137
   */
3138
159
  DNS_SLABTOP_FOREACH(top, node->data) {
3139
159
    if (top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) ||
3140
159
        top->typepair == DNS_TYPEPAIR(dns_rdatatype_dname) ||
3141
106
        top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_dname))
3142
53
    {
3143
53
      dns_slabheader_t *header =
3144
53
        first_existing_header(top, search->serial);
3145
53
      if (header != NULL) {
3146
53
        if (top->typepair ==
3147
53
            DNS_TYPEPAIR(dns_rdatatype_dname))
3148
0
        {
3149
0
          dname_header = header;
3150
53
        } else if (top->typepair ==
3151
53
             DNS_SIGTYPEPAIR(dns_rdatatype_dname))
3152
0
        {
3153
0
          sigdname_header = header;
3154
53
        } else if (node != search->qpdb->origin ||
3155
53
             IS_STUB(search->qpdb))
3156
0
        {
3157
          /*
3158
           * We've found an NS rdataset that
3159
           * isn't at the origin node.
3160
           */
3161
0
          ns_header = header;
3162
0
        }
3163
53
      }
3164
53
    }
3165
159
  }
3166
3167
  /*
3168
   * Did we find anything?
3169
   */
3170
53
  if (!IS_STUB(search->qpdb) && ns_header != NULL) {
3171
    /*
3172
     * Note that NS has precedence over DNAME if both exist
3173
     * in a zone.  Otherwise DNAME take precedence over NS.
3174
     */
3175
0
    found = ns_header;
3176
0
    search->zonecut_sigheader = NULL;
3177
53
  } else if (dname_header != NULL) {
3178
0
    found = dname_header;
3179
0
    search->zonecut_sigheader = sigdname_header;
3180
53
  } else if (ns_header != NULL) {
3181
0
    found = ns_header;
3182
0
    search->zonecut_sigheader = NULL;
3183
0
  }
3184
3185
53
  if (found != NULL) {
3186
    /*
3187
     * We increment the reference count on node to ensure that
3188
     * search->zonecut_header will still be valid later.
3189
     */
3190
0
    qpznode_acquire(node DNS__DB_FLARG_PASS);
3191
0
    search->zonecut = node;
3192
0
    search->zonecut_header = found;
3193
0
    search->need_cleanup = true;
3194
    /*
3195
     * Since we've found a zonecut, anything beneath it is
3196
     * glue and is not subject to wildcard matching, so we
3197
     * may clear search->wild.
3198
     */
3199
0
    search->wild = false;
3200
0
    if ((search->options & DNS_DBFIND_GLUEOK) == 0) {
3201
      /*
3202
       * If the caller does not want to find glue, then
3203
       * this is the best answer and the search should
3204
       * stop now.
3205
       */
3206
0
      result = DNS_R_PARTIALMATCH;
3207
0
    } else {
3208
0
      dns_name_t *zcname = NULL;
3209
3210
      /*
3211
       * The search will continue beneath the zone cut.
3212
       * This may or may not be the best match.  In case it
3213
       * is, we need to remember the node name.
3214
       */
3215
0
      zcname = dns_fixedname_name(&search->zonecut_name);
3216
0
      dns_name_copy(&node->name, zcname);
3217
0
      search->copy_name = true;
3218
0
    }
3219
53
  } else {
3220
    /*
3221
     * There is no zonecut at this node which is active in this
3222
     * version.
3223
     *
3224
     * If this is a "wild" node and the caller hasn't disabled
3225
     * wildcard matching, remember that we've seen a wild node
3226
     * in case we need to go searching for wildcard matches
3227
     * later on.
3228
     */
3229
53
    if (node->wild && (search->options & DNS_DBFIND_NOWILD) == 0) {
3230
0
      search->wild = true;
3231
0
    }
3232
53
  }
3233
3234
53
  NODE_UNLOCK(nlock, &nlocktype);
3235
3236
53
  return result;
3237
53
}
3238
3239
static void
3240
qpz_search_init(qpz_search_t *search, qpzonedb_t *db, qpz_version_t *version,
3241
171
    unsigned int options) {
3242
  /*
3243
   * qpz_search_t contains two structures with large buffers (dns_qpiter_t
3244
   * and dns_qpchain_t). Those two structures will be initialized later by
3245
   * dns_qp_lookup anyway.
3246
   * To avoid the overhead of zero initialization, we avoid designated
3247
   * initializers and initialize all "small" fields manually.
3248
   */
3249
171
  search->qpdb = db;
3250
171
  search->version = version;
3251
171
  search->qpr = (dns_qpread_t){};
3252
171
  search->serial = version->serial;
3253
171
  search->options = options;
3254
  /*
3255
   * qpch->in -- init in dns_qp_lookup
3256
   * qpiter -- init in dns_qp_lookup
3257
   */
3258
171
  search->copy_name = false;
3259
171
  search->need_cleanup = false;
3260
171
  search->wild = false;
3261
171
  search->zonecut = NULL;
3262
171
  search->zonecut_header = NULL;
3263
171
  search->zonecut_sigheader = NULL;
3264
171
  dns_fixedname_init(&search->zonecut_name);
3265
171
}
3266
3267
static isc_result_t
3268
qpzone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
3269
      dns_rdatatype_t type, unsigned int options,
3270
      isc_stdtime_t now ISC_ATTR_UNUSED, dns_dbnode_t **nodep,
3271
      dns_name_t *foundname,
3272
      dns_clientinfomethods_t *methods ISC_ATTR_UNUSED,
3273
      dns_clientinfo_t *clientinfo ISC_ATTR_UNUSED,
3274
      dns_rdataset_t *rdataset,
3275
171
      dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
3276
171
  isc_result_t result;
3277
171
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
3278
171
  qpznode_t *node = NULL;
3279
171
  bool cname_ok = true, close_version = false;
3280
171
  bool maybe_zonecut = false, at_zonecut = false;
3281
171
  bool wild = false, empty_node = false;
3282
171
  bool nsec3 = false;
3283
171
  dns_slabheader_t *found = NULL, *nsecheader = NULL;
3284
171
  dns_slabheader_t *foundsig = NULL, *cnamesig = NULL, *nsecsig = NULL;
3285
171
  dns_typepair_t sigpair;
3286
171
  bool active;
3287
171
  isc_rwlock_t *nlock = NULL;
3288
171
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3289
3290
171
  REQUIRE(VALID_QPZONE((qpzonedb_t *)db));
3291
171
  INSIST(version == NULL ||
3292
171
         ((qpz_version_t *)version)->qpdb == (qpzonedb_t *)db);
3293
3294
  /*
3295
   * If the caller didn't supply a version, attach to the current
3296
   * version.
3297
   */
3298
171
  if (version == NULL) {
3299
171
    currentversion(db, &version);
3300
171
    close_version = true;
3301
171
  }
3302
3303
171
  dns_namespace_t nspace;
3304
171
  qpz_search_t search;
3305
171
  qpz_search_init(&search, (qpzonedb_t *)db, (qpz_version_t *)version,
3306
171
      options);
3307
3308
171
  if ((options & DNS_DBFIND_FORCENSEC3) != 0) {
3309
0
    nsec3 = true;
3310
0
    nspace = DNS_DBNAMESPACE_NSEC3;
3311
171
  } else {
3312
171
    nspace = DNS_DBNAMESPACE_NORMAL;
3313
171
  }
3314
171
  dns_qpmulti_query(qpdb->tree, &search.qpr);
3315
3316
  /*
3317
   * Search down from the root of the tree.
3318
   */
3319
171
  result = dns_qp_lookup(&search.qpr, name, nspace, NULL, &search.iter,
3320
171
             &search.chain, (void **)&node, NULL);
3321
171
  if (result != ISC_R_NOTFOUND) {
3322
171
    dns_name_copy(&node->name, foundname);
3323
171
  }
3324
3325
  /*
3326
   * Check the QP chain to see if there's a node above us with a
3327
   * active DNAME or NS rdatasets.
3328
   *
3329
   * We're only interested in nodes above QNAME, so if the result
3330
   * was success, then we skip the last item in the chain.
3331
   */
3332
171
  unsigned int clen = dns_qpchain_length(&search.chain);
3333
171
  if (result == ISC_R_SUCCESS) {
3334
118
    clen--;
3335
118
  }
3336
224
  for (unsigned int i = 0; i < clen && search.zonecut == NULL; i++) {
3337
53
    qpznode_t *n = NULL;
3338
53
    isc_result_t tresult;
3339
3340
53
    dns_qpchain_node(&search.chain, i, NULL, (void **)&n, NULL);
3341
53
    tresult = qpzone_check_zonecut(n, &search DNS__DB_FLARG_PASS);
3342
53
    if (tresult != DNS_R_CONTINUE) {
3343
0
      result = tresult;
3344
0
      search.chain.len = i - 1;
3345
0
      dns_name_copy(&n->name, foundname);
3346
0
      node = n;
3347
0
    }
3348
53
  }
3349
3350
171
  if (result == DNS_R_PARTIALMATCH) {
3351
53
  partial_match:
3352
53
    if (search.zonecut != NULL) {
3353
0
      result = qpzone_setup_delegation(
3354
0
        &search, nodep, foundname, rdataset,
3355
0
        sigrdataset DNS__DB_FLARG_PASS);
3356
0
      goto tree_exit;
3357
0
    }
3358
3359
53
    if (search.wild) {
3360
      /*
3361
       * At least one of the levels in the search chain
3362
       * potentially has a wildcard.  For each such level,
3363
       * we must see if there's a matching wildcard active
3364
       * in the current version.
3365
       */
3366
0
      result = find_wildcard(&search, &node, name, nspace);
3367
0
      if (result == ISC_R_SUCCESS) {
3368
0
        dns_name_copy(name, foundname);
3369
0
        wild = true;
3370
0
        goto found;
3371
0
      } else if (result != ISC_R_NOTFOUND) {
3372
0
        goto tree_exit;
3373
0
      }
3374
0
    }
3375
3376
53
    active = false;
3377
53
    if (!nsec3) {
3378
      /*
3379
       * The NSEC3 tree won't have empty nodes,
3380
       * so it isn't necessary to check for them.
3381
       */
3382
53
      dns_qpiter_t iter = search.iter;
3383
53
      active = activeempty(&search, &iter, name);
3384
53
    }
3385
3386
    /*
3387
     * If we're here, then the name does not exist, is not
3388
     * beneath a zonecut, and there's no matching wildcard.
3389
     */
3390
53
    if ((search.version->secure && !search.version->havensec3) ||
3391
53
        nsec3)
3392
0
    {
3393
0
      result = find_closest_nsec(
3394
0
        &search, nodep, foundname, rdataset,
3395
0
        sigrdataset, nsec3,
3396
0
        search.version->secure DNS__DB_FLARG_PASS);
3397
0
      if (result == ISC_R_SUCCESS) {
3398
0
        result = active ? DNS_R_EMPTYNAME
3399
0
            : DNS_R_NXDOMAIN;
3400
0
      }
3401
53
    } else {
3402
53
      result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN;
3403
53
    }
3404
53
    goto tree_exit;
3405
118
  } else if (result != ISC_R_SUCCESS) {
3406
0
    goto tree_exit;
3407
0
  }
3408
3409
118
found:
3410
  /*
3411
   * We have found a node whose name is the desired name, or we
3412
   * have matched a wildcard.
3413
   */
3414
3415
118
  nlock = qpzone_get_lock(node);
3416
118
  NODE_RDLOCK(nlock, &nlocktype);
3417
3418
118
  if (search.zonecut != NULL) {
3419
    /*
3420
     * If we're beneath a zone cut, we don't want to look for
3421
     * CNAMEs because they're not legitimate zone glue.
3422
     */
3423
0
    cname_ok = false;
3424
118
  } else {
3425
    /*
3426
     * The node may be a zone cut itself.  If it might be one,
3427
     * make sure we check for it later.
3428
     *
3429
     * DS records live above the zone cut in ordinary zone so
3430
     * we want to ignore any referral.
3431
     *
3432
     * Stub zones don't have anything "above" the delegation so
3433
     * we always return a referral.
3434
     */
3435
118
    if (node->delegating && ((node != search.qpdb->origin &&
3436
0
            !dns_rdatatype_atparent(type)) ||
3437
0
           IS_STUB(search.qpdb)))
3438
0
    {
3439
0
      maybe_zonecut = true;
3440
0
    }
3441
118
  }
3442
3443
  /*
3444
   * Certain DNSSEC types are not subject to CNAME matching
3445
   * (RFC4035, section 2.5 and RFC3007).
3446
   *
3447
   * We don't check for RRSIG, because we don't store RRSIG records
3448
   * directly.
3449
   */
3450
118
  if (type == dns_rdatatype_key || type == dns_rdatatype_nsec) {
3451
118
    cname_ok = false;
3452
118
  }
3453
3454
  /*
3455
   * We now go looking for rdata...
3456
   */
3457
3458
118
  sigpair = DNS_SIGTYPEPAIR(type);
3459
118
  empty_node = true;
3460
354
  DNS_SLABTOP_FOREACH(top, node->data) {
3461
    /*
3462
     * Look for an active, extant rdataset.
3463
     */
3464
354
    dns_slabheader_t *header = first_existing_header(top,
3465
354
                 search.serial);
3466
354
    if (header != NULL) {
3467
      /*
3468
       * We now know that there is at least one active
3469
       * rdataset at this node.
3470
       */
3471
354
      empty_node = false;
3472
3473
      /*
3474
       * Do special zone cut handling, if requested.
3475
       */
3476
354
      if (maybe_zonecut &&
3477
0
          top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns))
3478
0
      {
3479
        /*
3480
         * We increment the reference count on node to
3481
         * ensure that search->zonecut_header will
3482
         * still be valid later.
3483
         */
3484
0
        qpznode_acquire(node DNS__DB_FLARG_PASS);
3485
0
        search.zonecut = node;
3486
0
        search.zonecut_header = header;
3487
0
        search.zonecut_sigheader = NULL;
3488
0
        search.need_cleanup = true;
3489
0
        maybe_zonecut = false;
3490
0
        at_zonecut = true;
3491
        /*
3492
         * It is not clear if KEY should still be
3493
         * allowed at the parent side of the zone
3494
         * cut or not.  It is needed for RFC3007
3495
         * validated updates.
3496
         */
3497
0
        if ((search.options & DNS_DBFIND_GLUEOK) == 0 &&
3498
0
            type != dns_rdatatype_nsec &&
3499
0
            type != dns_rdatatype_key)
3500
0
        {
3501
          /*
3502
           * Glue is not OK, but any answer we
3503
           * could return would be glue.  Return
3504
           * the delegation.
3505
           */
3506
0
          found = NULL;
3507
0
          break;
3508
0
        }
3509
0
        if (found != NULL && foundsig != NULL) {
3510
0
          break;
3511
0
        }
3512
0
      }
3513
3514
      /*
3515
       * If the NSEC3 record doesn't match the chain
3516
       * we are using behave as if it isn't here.
3517
       */
3518
354
      if (top->typepair ==
3519
354
            DNS_TYPEPAIR(dns_rdatatype_nsec3) &&
3520
0
          !matchparams(header, &search))
3521
0
      {
3522
0
        NODE_UNLOCK(nlock, &nlocktype);
3523
0
        goto partial_match;
3524
0
      }
3525
      /*
3526
       * If we found a type we were looking for,
3527
       * remember it.
3528
       */
3529
354
      if (top->typepair == type ||
3530
236
          type == dns_rdatatype_any ||
3531
236
          (top->typepair ==
3532
236
             DNS_TYPEPAIR(dns_rdatatype_cname) &&
3533
0
           cname_ok))
3534
118
      {
3535
        /*
3536
         * We've found the answer!
3537
         */
3538
118
        found = header;
3539
118
        if (top->typepair ==
3540
118
              DNS_TYPEPAIR(dns_rdatatype_cname) &&
3541
0
            cname_ok)
3542
0
        {
3543
          /*
3544
           * We may be finding a CNAME instead
3545
           * of the desired type.
3546
           *
3547
           * If we've already got the CNAME RRSIG,
3548
           * use it, otherwise change sigtype
3549
           * so that we find it.
3550
           */
3551
0
          if (cnamesig != NULL) {
3552
0
            foundsig = cnamesig;
3553
0
          } else {
3554
0
            sigpair = DNS_SIGTYPEPAIR(
3555
0
              dns_rdatatype_cname);
3556
0
          }
3557
0
        }
3558
        /*
3559
         * If we've got all we need, end the search.
3560
         */
3561
118
        if (!maybe_zonecut && foundsig != NULL) {
3562
0
          break;
3563
0
        }
3564
236
      } else if (top->typepair == sigpair) {
3565
        /*
3566
         * We've found the RRSIG rdataset for our
3567
         * target type.  Remember it.
3568
         */
3569
0
        foundsig = header;
3570
        /*
3571
         * If we've got all we need, end the search.
3572
         */
3573
0
        if (!maybe_zonecut && found != NULL) {
3574
0
          break;
3575
0
        }
3576
236
      } else if (top->typepair ==
3577
236
             DNS_TYPEPAIR(dns_rdatatype_nsec) &&
3578
0
           !search.version->havensec3)
3579
0
      {
3580
        /*
3581
         * Remember a NSEC rdataset even if we're
3582
         * not specifically looking for it, because
3583
         * we might need it later.
3584
         */
3585
0
        nsecheader = header;
3586
236
      } else if (top->typepair ==
3587
236
             DNS_SIGTYPEPAIR(
3588
0
               dns_rdatatype_nsec) &&
3589
0
           !search.version->havensec3)
3590
0
      {
3591
        /*
3592
         * If we need the NSEC rdataset, we'll also
3593
         * need its signature.
3594
         */
3595
0
        nsecsig = header;
3596
236
      } else if (cname_ok &&
3597
0
           top->typepair ==
3598
0
             DNS_SIGTYPEPAIR(dns_rdatatype_cname))
3599
0
      {
3600
        /*
3601
         * If we get a CNAME match, we'll also need
3602
         * its signature.
3603
         */
3604
0
        cnamesig = header;
3605
0
      }
3606
354
    }
3607
354
  }
3608
3609
118
  if (empty_node) {
3610
    /*
3611
     * We have an exact match for the name, but there are no
3612
     * active rdatasets in the desired version.  That means that
3613
     * this node doesn't exist in the desired version.
3614
     * If there's a node above this one, reassign the
3615
     * foundname to the parent and treat this as a partial
3616
     * match.
3617
     */
3618
0
    if (!wild) {
3619
0
      unsigned int len = search.chain.len - 1;
3620
0
      if (len > 0) {
3621
0
        NODE_UNLOCK(nlock, &nlocktype);
3622
0
        dns_qpchain_node(&search.chain, len - 1, NULL,
3623
0
             (void **)&node, NULL);
3624
0
        dns_name_copy(&node->name, foundname);
3625
0
        goto partial_match;
3626
0
      }
3627
0
    }
3628
0
  }
3629
3630
  /*
3631
   * If we didn't find what we were looking for...
3632
   */
3633
118
  if (found == NULL) {
3634
0
    if (search.zonecut != NULL) {
3635
      /*
3636
       * We were trying to find glue at a node beneath a
3637
       * zone cut, but didn't.
3638
       *
3639
       * Return the delegation.
3640
       */
3641
0
      NODE_UNLOCK(nlock, &nlocktype);
3642
0
      result = qpzone_setup_delegation(
3643
0
        &search, nodep, foundname, rdataset,
3644
0
        sigrdataset DNS__DB_FLARG_PASS);
3645
0
      goto tree_exit;
3646
0
    }
3647
    /*
3648
     * The desired type doesn't exist.
3649
     */
3650
0
    result = DNS_R_NXRRSET;
3651
0
    if (search.version->secure && !search.version->havensec3 &&
3652
0
        (nsecheader == NULL || nsecsig == NULL))
3653
0
    {
3654
      /*
3655
       * The zone is secure but there's no NSEC,
3656
       * or the NSEC has no signature!
3657
       */
3658
0
      if (!wild) {
3659
0
        result = DNS_R_BADDB;
3660
0
        goto node_exit;
3661
0
      }
3662
3663
0
      NODE_UNLOCK(nlock, &nlocktype);
3664
0
      result = find_closest_nsec(
3665
0
        &search, nodep, foundname, rdataset,
3666
0
        sigrdataset, false,
3667
0
        search.version->secure DNS__DB_FLARG_PASS);
3668
0
      if (result == ISC_R_SUCCESS) {
3669
0
        result = DNS_R_EMPTYWILD;
3670
0
      }
3671
0
      goto tree_exit;
3672
0
    }
3673
0
    if (nodep != NULL) {
3674
0
      qpznode_acquire(node DNS__DB_FLARG_PASS);
3675
0
      *nodep = (dns_dbnode_t *)node;
3676
0
    }
3677
0
    if (search.version->secure && !search.version->havensec3) {
3678
0
      bindrdataset(search.qpdb, node, nsecheader,
3679
0
             rdataset DNS__DB_FLARG_PASS);
3680
0
      if (nsecsig != NULL) {
3681
0
        bindrdataset(search.qpdb, node, nsecsig,
3682
0
               sigrdataset DNS__DB_FLARG_PASS);
3683
0
      }
3684
0
    }
3685
0
    if (wild) {
3686
0
      foundname->attributes.wildcard = true;
3687
0
    }
3688
0
    goto node_exit;
3689
0
  }
3690
3691
  /*
3692
   * We found what we were looking for, or we found a CNAME.
3693
   */
3694
118
  if (type != found->typepair && type != dns_rdatatype_any &&
3695
0
      found->typepair == DNS_TYPEPAIR(dns_rdatatype_cname))
3696
0
  {
3697
    /*
3698
     * We weren't doing an ANY query and we found a CNAME instead
3699
     * of the type we were looking for, so we need to indicate
3700
     * that result to the caller.
3701
     */
3702
0
    result = DNS_R_CNAME;
3703
118
  } else if (search.zonecut != NULL) {
3704
    /*
3705
     * If we're beneath a zone cut, we must indicate that the
3706
     * result is glue, unless we're actually at the zone cut
3707
     * and the type is NSEC or KEY.
3708
     */
3709
0
    if (search.zonecut == node) {
3710
      /*
3711
       * It is not clear if KEY should still be
3712
       * allowed at the parent side of the zone
3713
       * cut or not.  It is needed for RFC3007
3714
       * validated updates.
3715
       */
3716
0
      if (dns_rdatatype_isnsec(type) ||
3717
0
          type == dns_rdatatype_key)
3718
0
      {
3719
0
        result = ISC_R_SUCCESS;
3720
0
      } else if (type == dns_rdatatype_any) {
3721
0
        result = DNS_R_ZONECUT;
3722
0
      } else {
3723
0
        result = DNS_R_GLUE;
3724
0
      }
3725
0
    } else {
3726
0
      result = DNS_R_GLUE;
3727
0
    }
3728
118
  } else {
3729
    /*
3730
     * An ordinary successful query!
3731
     */
3732
118
    result = ISC_R_SUCCESS;
3733
118
  }
3734
3735
118
  if (nodep != NULL) {
3736
118
    if (!at_zonecut) {
3737
118
      qpznode_acquire(node DNS__DB_FLARG_PASS);
3738
118
    } else {
3739
0
      search.need_cleanup = false;
3740
0
    }
3741
118
    *nodep = (dns_dbnode_t *)node;
3742
118
  }
3743
3744
118
  if (type != dns_rdatatype_any) {
3745
118
    bindrdataset(search.qpdb, node, found,
3746
118
           rdataset DNS__DB_FLARG_PASS);
3747
118
    if (foundsig != NULL) {
3748
0
      bindrdataset(search.qpdb, node, foundsig,
3749
0
             sigrdataset DNS__DB_FLARG_PASS);
3750
0
    }
3751
118
  }
3752
3753
118
  if (wild) {
3754
0
    foundname->attributes.wildcard = true;
3755
0
  }
3756
3757
118
node_exit:
3758
118
  NODE_UNLOCK(nlock, &nlocktype);
3759
3760
171
tree_exit:
3761
171
  dns_qpread_destroy(qpdb->tree, &search.qpr);
3762
3763
  /*
3764
   * If we found a zonecut but aren't going to use it, we have to
3765
   * let go of it.
3766
   */
3767
171
  if (search.need_cleanup) {
3768
0
    node = search.zonecut;
3769
0
    INSIST(node != NULL);
3770
0
    nlock = qpzone_get_lock(node);
3771
3772
0
    NODE_RDLOCK(nlock, &nlocktype);
3773
0
    qpznode_release(node, 0, &nlocktype DNS__DB_FLARG_PASS);
3774
0
    NODE_UNLOCK(nlock, &nlocktype);
3775
0
  }
3776
3777
171
  if (close_version) {
3778
171
    closeversion(db, &version, false DNS__DB_FLARG_PASS);
3779
171
  }
3780
3781
171
  return result;
3782
171
}
3783
3784
static isc_result_t
3785
qpzone_allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode,
3786
        dns_dbversion_t *dbversion, unsigned int options,
3787
        isc_stdtime_t now ISC_ATTR_UNUSED,
3788
0
        dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
3789
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
3790
0
  qpznode_t *node = (qpznode_t *)dbnode;
3791
0
  qpz_version_t *version = (qpz_version_t *)dbversion;
3792
0
  qpdb_rdatasetiter_t *iterator = NULL;
3793
3794
0
  REQUIRE(VALID_QPZONE(qpdb));
3795
3796
0
  if (version == NULL) {
3797
0
    currentversion(db, (dns_dbversion_t **)(void *)(&version));
3798
0
  } else {
3799
0
    INSIST(version->qpdb == qpdb);
3800
0
    isc_refcount_increment(&version->references);
3801
0
  }
3802
3803
0
  iterator = isc_mem_get(qpdb->common.mctx, sizeof(*iterator));
3804
0
  *iterator = (qpdb_rdatasetiter_t){
3805
0
    .common.methods = &rdatasetiter_methods,
3806
0
    .common.db = db,
3807
0
    .common.node = (dns_dbnode_t *)node,
3808
0
    .common.version = (dns_dbversion_t *)version,
3809
0
    .common.options = options,
3810
0
    .common.magic = DNS_RDATASETITER_MAGIC,
3811
0
  };
3812
3813
0
  qpznode_acquire(node DNS__DB_FLARG_PASS);
3814
3815
0
  *iteratorp = (dns_rdatasetiter_t *)iterator;
3816
0
  return ISC_R_SUCCESS;
3817
0
}
3818
3819
static void
3820
0
qpzone_attachnode(dns_dbnode_t *source, dns_dbnode_t **targetp DNS__DB_FLARG) {
3821
0
  qpznode_t *node = (qpznode_t *)source;
3822
3823
0
  REQUIRE(targetp != NULL && *targetp == NULL);
3824
3825
0
  qpznode_acquire(node DNS__DB_FLARG_PASS);
3826
3827
0
  *targetp = source;
3828
0
}
3829
3830
static void
3831
307
qpzone_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG) {
3832
307
  qpznode_t *node = NULL;
3833
307
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3834
307
  isc_rwlock_t *nlock = NULL;
3835
3836
307
  REQUIRE(nodep != NULL && *nodep != NULL);
3837
3838
307
  node = (qpznode_t *)(*nodep);
3839
3840
307
  *nodep = NULL;
3841
307
  nlock = qpzone_get_lock(node);
3842
3843
  /*
3844
   * qpzone_destroy() uses call_rcu() API to destroy the node locks, so it
3845
   * is safe to call it in the middle of NODE_LOCK, but we need to acquire
3846
   * the database reference to prevent destroying the database while the
3847
   * NODE_LOCK is locked.
3848
   */
3849
3850
307
  rcu_read_lock();
3851
307
  NODE_RDLOCK(nlock, &nlocktype);
3852
307
  qpznode_release(node, 0, &nlocktype DNS__DB_FLARG_PASS);
3853
307
  NODE_UNLOCK(nlock, &nlocktype);
3854
307
  rcu_read_unlock();
3855
307
}
3856
3857
static unsigned int
3858
2
nodecount(dns_db_t *db) {
3859
2
  qpzonedb_t *qpdb = qpdb = (qpzonedb_t *)db;
3860
2
  dns_qp_memusage_t mu;
3861
3862
2
  REQUIRE(VALID_QPZONE(qpdb));
3863
3864
2
  mu = dns_qpmulti_memusage(qpdb->tree);
3865
3866
2
  return mu.leaves;
3867
2
}
3868
3869
static isc_result_t
3870
2
getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
3871
2
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
3872
3873
2
  REQUIRE(VALID_QPZONE(qpdb));
3874
2
  REQUIRE(nodep != NULL && *nodep == NULL);
3875
3876
  /* Note that the access to the origin node doesn't require a DB lock */
3877
2
  INSIST(qpdb->origin != NULL);
3878
2
  qpznode_acquire(qpdb->origin DNS__DB_FLARG_PASS);
3879
2
  *nodep = (dns_dbnode_t *)qpdb->origin;
3880
3881
2
  return ISC_R_SUCCESS;
3882
2
}
3883
3884
static void
3885
6.31M
deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) {
3886
6.31M
  dns_slabheader_t *header = data;
3887
3888
6.31M
  if (header->heap_index != 0) {
3889
0
    LOCK(get_heap_lock(header));
3890
0
    isc_heap_delete(HEADERNODE(header)->heap->heap,
3891
0
        header->heap_index);
3892
0
    UNLOCK(get_heap_lock(header));
3893
0
  }
3894
6.31M
  header->heap_index = 0;
3895
6.31M
}
3896
3897
/*
3898
 * Rdataset Iterator Methods
3899
 */
3900
3901
static void
3902
0
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
3903
0
  qpdb_rdatasetiter_t *qrditer = NULL;
3904
3905
0
  qrditer = (qpdb_rdatasetiter_t *)(*iteratorp);
3906
3907
0
  if (qrditer->common.version != NULL) {
3908
0
    closeversion(qrditer->common.db, &qrditer->common.version,
3909
0
           false DNS__DB_FLARG_PASS);
3910
0
  }
3911
0
  dns__db_detachnode(&qrditer->common.node DNS__DB_FLARG_PASS);
3912
0
  isc_mem_put(qrditer->common.db->mctx, qrditer, sizeof(*qrditer));
3913
3914
0
  *iteratorp = NULL;
3915
0
}
3916
3917
static isc_result_t
3918
0
rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
3919
0
  qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator;
3920
0
  qpznode_t *node = (qpznode_t *)qrditer->common.node;
3921
0
  qpz_version_t *version = (qpz_version_t *)qrditer->common.version;
3922
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3923
0
  isc_rwlock_t *nlock = qpzone_get_lock(node);
3924
3925
0
  qrditer->currenttop = NULL;
3926
0
  qrditer->current = NULL;
3927
3928
0
  NODE_RDLOCK(nlock, &nlocktype);
3929
3930
0
  DNS_SLABTOP_FOREACH(top, node->data) {
3931
0
    qrditer->current = first_existing_header(top, version->serial);
3932
3933
0
    if (qrditer->current != NULL) {
3934
0
      qrditer->currenttop = top;
3935
0
      break;
3936
0
    }
3937
0
  }
3938
3939
0
  NODE_UNLOCK(nlock, &nlocktype);
3940
3941
0
  if (qrditer->currenttop == NULL) {
3942
0
    return ISC_R_NOMORE;
3943
0
  }
3944
3945
0
  return ISC_R_SUCCESS;
3946
0
}
3947
3948
static isc_result_t
3949
0
rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
3950
0
  qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator;
3951
0
  qpznode_t *node = (qpznode_t *)qrditer->common.node;
3952
0
  qpz_version_t *version = (qpz_version_t *)qrditer->common.version;
3953
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3954
0
  isc_rwlock_t *nlock = qpzone_get_lock(node);
3955
0
  dns_slabtop_t *from = NULL;
3956
3957
0
  if (qrditer->currenttop == NULL) {
3958
0
    return ISC_R_NOMORE;
3959
0
  }
3960
3961
0
  NODE_RDLOCK(nlock, &nlocktype);
3962
3963
0
  from = cds_list_entry(qrditer->currenttop->types_link.next,
3964
0
            dns_slabtop_t, types_link);
3965
0
  qrditer->currenttop = NULL;
3966
0
  qrditer->current = NULL;
3967
3968
  /*
3969
   * Find the start of the header chain for the next type.
3970
   */
3971
0
  if (from != NULL) {
3972
0
    DNS_SLABTOP_FOREACH_FROM(top, node->data, from) {
3973
0
      qrditer->current =
3974
0
        first_existing_header(top, version->serial);
3975
0
      if (qrditer->current != NULL) {
3976
0
        qrditer->currenttop = top;
3977
0
        break;
3978
0
      }
3979
0
    }
3980
0
  }
3981
3982
0
  NODE_UNLOCK(nlock, &nlocktype);
3983
3984
0
  if (qrditer->currenttop == NULL) {
3985
0
    return ISC_R_NOMORE;
3986
0
  }
3987
3988
0
  return ISC_R_SUCCESS;
3989
0
}
3990
3991
static void
3992
rdatasetiter_current(dns_rdatasetiter_t *iterator,
3993
0
         dns_rdataset_t *rdataset DNS__DB_FLARG) {
3994
0
  qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator;
3995
0
  qpzonedb_t *qpdb = (qpzonedb_t *)(qrditer->common.db);
3996
0
  qpznode_t *qpnode = (qpznode_t *)qrditer->common.node;
3997
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3998
0
  isc_rwlock_t *nlock = qpzone_get_lock(qpnode);
3999
0
  dns_slabheader_t *header = qrditer->current;
4000
4001
0
  REQUIRE(header != NULL);
4002
4003
0
  NODE_RDLOCK(nlock, &nlocktype);
4004
4005
0
  bindrdataset(qpdb, qpnode, header, rdataset DNS__DB_FLARG_PASS);
4006
4007
0
  NODE_UNLOCK(nlock, &nlocktype);
4008
0
}
4009
4010
/*
4011
 * Database Iterator Methods
4012
 */
4013
static void
4014
0
reference_iter_node(qpdb_dbiterator_t *iter DNS__DB_FLARG) {
4015
0
  qpznode_t *node = iter->node;
4016
4017
0
  if (node == NULL) {
4018
0
    return;
4019
0
  }
4020
4021
0
  qpznode_acquire(node DNS__DB_FLARG_PASS);
4022
0
}
4023
4024
static void
4025
0
dereference_iter_node(qpdb_dbiterator_t *iter DNS__DB_FLARG) {
4026
0
  qpznode_t *node = iter->node;
4027
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
4028
0
  isc_rwlock_t *nlock = NULL;
4029
4030
0
  if (node == NULL) {
4031
0
    return;
4032
0
  }
4033
4034
0
  iter->node = NULL;
4035
0
  nlock = qpzone_get_lock(node);
4036
4037
0
  NODE_RDLOCK(nlock, &nlocktype);
4038
0
  qpznode_release(node, 0, &nlocktype DNS__DB_FLARG_PASS);
4039
0
  NODE_UNLOCK(nlock, &nlocktype);
4040
0
}
4041
4042
static void
4043
0
dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG) {
4044
0
  qpdb_dbiterator_t *iter = (qpdb_dbiterator_t *)(*iteratorp);
4045
0
  dns_db_t *db = NULL;
4046
4047
0
  dereference_iter_node(iter DNS__DB_FLARG_PASS);
4048
4049
0
  dns_db_attach(iter->common.db, &db);
4050
0
  dns_db_detach(&iter->common.db);
4051
4052
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
4053
0
  dns_qpsnap_destroy(qpdb->tree, &iter->snap);
4054
4055
0
  isc_mem_put(db->mctx, iter, sizeof(*iter));
4056
0
  dns_db_detach(&db);
4057
4058
0
  *iteratorp = NULL;
4059
0
}
4060
4061
static isc_result_t
4062
0
dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG) {
4063
0
  isc_result_t result;
4064
0
  qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
4065
0
  qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
4066
4067
0
  if (qpdbiter->result != ISC_R_SUCCESS &&
4068
0
      qpdbiter->result != ISC_R_NOTFOUND &&
4069
0
      qpdbiter->result != DNS_R_PARTIALMATCH &&
4070
0
      qpdbiter->result != ISC_R_NOMORE)
4071
0
  {
4072
0
    return qpdbiter->result;
4073
0
  }
4074
4075
0
  dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4076
4077
0
  dns_qpiter_init(qpdbiter->snap, &qpdbiter->iter);
4078
0
  result = dns_qpiter_next(&qpdbiter->iter, NULL,
4079
0
         (void **)&qpdbiter->node, NULL);
4080
4081
0
  switch (qpdbiter->nsec3mode) {
4082
0
  case nonsec3:
4083
0
    if (result == ISC_R_SUCCESS) {
4084
      /*
4085
       * If we immediately hit an NSEC/NSEC3 node,
4086
       * we don't have any non-nsec nodes.
4087
       */
4088
0
      if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NORMAL) {
4089
0
        qpdbiter->node = NULL;
4090
0
        result = ISC_R_NOMORE;
4091
0
      }
4092
0
    }
4093
0
    break;
4094
0
  case full:
4095
    /* skip the NSEC3 origin node. */
4096
0
    if (result == ISC_R_SUCCESS &&
4097
0
        QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
4098
0
    {
4099
0
      result = dns_qpiter_next(&qpdbiter->iter, NULL,
4100
0
             (void **)&qpdbiter->node,
4101
0
             NULL);
4102
0
    }
4103
0
    if (result != ISC_R_SUCCESS) {
4104
0
      qpdbiter->node = NULL;
4105
0
      break;
4106
0
    }
4107
4108
    /*
4109
     * If we hit an NSEC node, we need to start at the NSEC3 part of
4110
     * the tree.
4111
     */
4112
0
    if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NSEC) {
4113
0
      break;
4114
0
    }
4115
0
    INSIST(qpdbiter->node->nspace == DNS_DBNAMESPACE_NSEC);
4116
4117
    /* FALLTHROUGH */
4118
0
  case nsec3only:
4119
    /*
4120
     * NSEC3 follows after all non-nsec3 nodes, seek the NSEC3
4121
     * origin node.
4122
     */
4123
0
    result = dns_qp_lookup(qpdbiter->snap, &qpdb->common.origin,
4124
0
               DNS_DBNAMESPACE_NSEC3, NULL,
4125
0
               &qpdbiter->iter, NULL,
4126
0
               (void **)&qpdbiter->node, NULL);
4127
0
    if (result != ISC_R_SUCCESS ||
4128
0
        QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
4129
0
    {
4130
      /* skip the NSEC3 origin node (or its predecessor) */
4131
0
      result = dns_qpiter_next(&qpdbiter->iter, NULL,
4132
0
             (void **)&qpdbiter->node,
4133
0
             NULL);
4134
0
    }
4135
0
    break;
4136
0
  default:
4137
0
    UNREACHABLE();
4138
0
  }
4139
4140
0
  if (result == ISC_R_SUCCESS) {
4141
0
    reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4142
0
  } else {
4143
0
    qpdbiter->node = NULL;
4144
0
  }
4145
0
  qpdbiter->result = result;
4146
0
  return result;
4147
0
}
4148
4149
static isc_result_t
4150
0
dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG) {
4151
0
  isc_result_t result;
4152
0
  qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
4153
0
  qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
4154
4155
0
  if (qpdbiter->result != ISC_R_SUCCESS &&
4156
0
      qpdbiter->result != ISC_R_NOTFOUND &&
4157
0
      qpdbiter->result != DNS_R_PARTIALMATCH &&
4158
0
      qpdbiter->result != ISC_R_NOMORE)
4159
0
  {
4160
0
    return qpdbiter->result;
4161
0
  }
4162
4163
0
  dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4164
4165
0
  dns_qpiter_init(qpdbiter->snap, &qpdbiter->iter);
4166
0
  result = dns_qpiter_prev(&qpdbiter->iter, NULL,
4167
0
         (void **)&qpdbiter->node, NULL);
4168
4169
0
  switch (qpdbiter->nsec3mode) {
4170
0
  case nsec3only:
4171
0
    if (result == ISC_R_SUCCESS) {
4172
0
      if (QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter)) {
4173
        /* tree only has NSEC3 origin node. */
4174
0
        qpdbiter->node = NULL;
4175
0
        result = ISC_R_NOMORE;
4176
0
      } else if (qpdbiter->node->nspace !=
4177
0
           DNS_DBNAMESPACE_NSEC3)
4178
0
      {
4179
        /* tree has no NSEC3 nodes at all. */
4180
0
        qpdbiter->node = NULL;
4181
0
        result = ISC_R_NOMORE;
4182
0
      }
4183
0
    }
4184
0
    break;
4185
0
  case full:
4186
    /* skip the NSEC3 origin node. */
4187
0
    if (result == ISC_R_SUCCESS &&
4188
0
        QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
4189
0
    {
4190
0
      result = dns_qpiter_prev(&qpdbiter->iter, NULL,
4191
0
             (void **)&qpdbiter->node,
4192
0
             NULL);
4193
0
    }
4194
0
    if (result != ISC_R_SUCCESS) {
4195
0
      qpdbiter->node = NULL;
4196
0
      break;
4197
0
    }
4198
4199
    /*
4200
     * If we hit an NSEC node, we need to seek the final normal node
4201
     * of the tree.
4202
     */
4203
0
    if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NSEC) {
4204
0
      break;
4205
0
    }
4206
0
    INSIST(qpdbiter->node->nspace == DNS_DBNAMESPACE_NSEC);
4207
4208
    /* FALLTHROUGH */
4209
0
  case nonsec3:
4210
    /*
4211
     * The final non-nsec node is before the the NSEC origin node.
4212
     */
4213
0
    result = dns_qp_lookup(qpdbiter->snap, &qpdb->common.origin,
4214
0
               DNS_DBNAMESPACE_NSEC, NULL,
4215
0
               &qpdbiter->iter, NULL,
4216
0
               (void **)&qpdbiter->node, NULL);
4217
0
    if (result == ISC_R_SUCCESS) {
4218
0
      INSIST(QPDBITER_NSEC_ORIGIN_NODE(qpdb, qpdbiter));
4219
      /* skip the NSEC origin node */
4220
0
      result = dns_qpiter_prev(&qpdbiter->iter, NULL,
4221
0
             (void **)&qpdbiter->node,
4222
0
             NULL);
4223
0
    } else {
4224
      /*
4225
       * The NSEC origin node was not found, but the iterator
4226
       * should point to its predecessor, which is the node we
4227
       * want.
4228
       */
4229
0
      result = dns_qpiter_current(&qpdbiter->iter, NULL,
4230
0
                (void **)&qpdbiter->node,
4231
0
                NULL);
4232
0
      INSIST(result == ISC_R_SUCCESS);
4233
0
      INSIST(qpdbiter->node->nspace ==
4234
0
             DNS_DBNAMESPACE_NORMAL);
4235
0
    }
4236
0
    break;
4237
0
  default:
4238
0
    UNREACHABLE();
4239
0
  }
4240
4241
0
  if (result == ISC_R_SUCCESS) {
4242
0
    reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4243
0
  } else {
4244
0
    qpdbiter->node = NULL;
4245
0
  }
4246
0
  qpdbiter->result = result;
4247
0
  return result;
4248
0
}
4249
4250
static isc_result_t
4251
dbiterator_seek(dns_dbiterator_t *iterator,
4252
0
    const dns_name_t *name DNS__DB_FLARG) {
4253
0
  isc_result_t result, tresult;
4254
0
  qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
4255
4256
0
  if (qpdbiter->result != ISC_R_SUCCESS &&
4257
0
      qpdbiter->result != ISC_R_NOTFOUND &&
4258
0
      qpdbiter->result != DNS_R_PARTIALMATCH &&
4259
0
      qpdbiter->result != ISC_R_NOMORE)
4260
0
  {
4261
0
    return qpdbiter->result;
4262
0
  }
4263
4264
0
  dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4265
4266
0
  switch (qpdbiter->nsec3mode) {
4267
0
  case nsec3only:
4268
0
    result = dns_qp_lookup(
4269
0
      qpdbiter->snap, name, DNS_DBNAMESPACE_NSEC3, NULL,
4270
0
      &qpdbiter->iter, NULL, (void **)&qpdbiter->node, NULL);
4271
0
    break;
4272
0
  case nonsec3:
4273
0
    result = dns_qp_lookup(
4274
0
      qpdbiter->snap, name, DNS_DBNAMESPACE_NORMAL, NULL,
4275
0
      &qpdbiter->iter, NULL, (void **)&qpdbiter->node, NULL);
4276
0
    break;
4277
0
  case full:
4278
0
    result = dns_qp_lookup(
4279
0
      qpdbiter->snap, name, DNS_DBNAMESPACE_NORMAL, NULL,
4280
0
      &qpdbiter->iter, NULL, (void **)&qpdbiter->node, NULL);
4281
0
    if (result != ISC_R_SUCCESS) {
4282
0
      tresult = dns_qp_lookup(qpdbiter->snap, name,
4283
0
            DNS_DBNAMESPACE_NSEC3, NULL,
4284
0
            &qpdbiter->iter, NULL,
4285
0
            (void **)&qpdbiter->node, NULL);
4286
0
      if (tresult == ISC_R_SUCCESS) {
4287
0
        result = tresult;
4288
0
      }
4289
0
    }
4290
0
    break;
4291
0
  default:
4292
0
    UNREACHABLE();
4293
0
  }
4294
4295
0
  if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
4296
0
    reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4297
0
  } else {
4298
0
    qpdbiter->node = NULL;
4299
0
  }
4300
4301
0
  qpdbiter->result = (result == DNS_R_PARTIALMATCH) ? ISC_R_SUCCESS
4302
0
                : result;
4303
0
  return result;
4304
0
}
4305
4306
static isc_result_t
4307
0
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
4308
0
  isc_result_t result;
4309
0
  qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
4310
0
  qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
4311
4312
0
  REQUIRE(qpdbiter->node != NULL);
4313
4314
0
  if (qpdbiter->result != ISC_R_SUCCESS) {
4315
0
    return qpdbiter->result;
4316
0
  }
4317
4318
0
  dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4319
4320
0
  result = dns_qpiter_prev(&qpdbiter->iter, NULL,
4321
0
         (void **)&qpdbiter->node, NULL);
4322
4323
0
  switch (qpdbiter->nsec3mode) {
4324
0
  case nsec3only:
4325
0
    if (result == ISC_R_SUCCESS) {
4326
0
      if (QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter)) {
4327
        /* we hit the NSEC3 origin node. */
4328
0
        qpdbiter->node = NULL;
4329
0
        result = ISC_R_NOMORE;
4330
0
      } else if (qpdbiter->node->nspace !=
4331
0
           DNS_DBNAMESPACE_NSEC3)
4332
0
      {
4333
        /* we hit a non-NSEC3 node. */
4334
0
        qpdbiter->node = NULL;
4335
0
        result = ISC_R_NOMORE;
4336
0
      }
4337
0
    }
4338
0
    break;
4339
0
  case full:
4340
    /* skip the NSEC3 origin node. */
4341
0
    if (result == ISC_R_SUCCESS &&
4342
0
        QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
4343
0
    {
4344
0
      result = dns_qpiter_prev(&qpdbiter->iter, NULL,
4345
0
             (void **)&qpdbiter->node,
4346
0
             NULL);
4347
0
    }
4348
0
    if (result != ISC_R_SUCCESS) {
4349
0
      qpdbiter->node = NULL;
4350
0
      break;
4351
0
    }
4352
4353
    /*
4354
     * If we hit an NSEC node, we need to seek the final normal node
4355
     * of the tree.
4356
     */
4357
0
    if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NSEC) {
4358
0
      break;
4359
0
    }
4360
4361
0
    INSIST(qpdbiter->node->nspace == DNS_DBNAMESPACE_NSEC);
4362
0
    result = dns_qp_lookup(qpdbiter->snap, &qpdb->common.origin,
4363
0
               DNS_DBNAMESPACE_NSEC, NULL,
4364
0
               &qpdbiter->iter, NULL,
4365
0
               (void **)&qpdbiter->node, NULL);
4366
4367
0
    if (result == ISC_R_SUCCESS) {
4368
0
      INSIST(QPDBITER_NSEC_ORIGIN_NODE(qpdb, qpdbiter));
4369
      /* skip the NSEC origin node */
4370
0
      result = dns_qpiter_prev(&qpdbiter->iter, NULL,
4371
0
             (void **)&qpdbiter->node,
4372
0
             NULL);
4373
0
    } else {
4374
      /*
4375
       * The NSEC origin node was not found, but the iterator
4376
       * should point to its predecessor, which is the node we
4377
       * want.
4378
       */
4379
0
      result = dns_qpiter_current(&qpdbiter->iter, NULL,
4380
0
                (void **)&qpdbiter->node,
4381
0
                NULL);
4382
0
      INSIST(result == ISC_R_SUCCESS);
4383
0
      INSIST(qpdbiter->node->nspace ==
4384
0
             DNS_DBNAMESPACE_NORMAL);
4385
0
    }
4386
0
    break;
4387
0
  case nonsec3:
4388
0
    break;
4389
0
  default:
4390
0
    UNREACHABLE();
4391
0
  }
4392
4393
0
  if (result == ISC_R_SUCCESS) {
4394
0
    reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4395
0
  } else {
4396
0
    qpdbiter->node = NULL;
4397
0
  }
4398
4399
0
  qpdbiter->result = result;
4400
0
  return result;
4401
0
}
4402
4403
static isc_result_t
4404
0
dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG) {
4405
0
  isc_result_t result;
4406
0
  qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
4407
0
  qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
4408
4409
0
  REQUIRE(qpdbiter->node != NULL);
4410
4411
0
  if (qpdbiter->result != ISC_R_SUCCESS) {
4412
0
    return qpdbiter->result;
4413
0
  }
4414
4415
0
  dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4416
4417
0
  result = dns_qpiter_next(&qpdbiter->iter, NULL,
4418
0
         (void **)&qpdbiter->node, NULL);
4419
4420
0
  switch (qpdbiter->nsec3mode) {
4421
0
  case nonsec3:
4422
0
    if (result == ISC_R_SUCCESS) {
4423
      /* we hit an NSEC or NSEC3 node. */
4424
0
      if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NORMAL) {
4425
0
        qpdbiter->node = NULL;
4426
0
        result = ISC_R_NOMORE;
4427
0
      }
4428
0
    }
4429
0
    break;
4430
0
  case full:
4431
    /* skip the NSEC3 origin node. */
4432
0
    if (result == ISC_R_SUCCESS &&
4433
0
        QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
4434
0
    {
4435
0
      result = dns_qpiter_next(&qpdbiter->iter, NULL,
4436
0
             (void **)&qpdbiter->node,
4437
0
             NULL);
4438
0
    }
4439
0
    if (result != ISC_R_SUCCESS) {
4440
0
      qpdbiter->node = NULL;
4441
0
      break;
4442
0
    }
4443
4444
    /*
4445
     * If we hit an NSEC node, we need to start at the NSEC3 part of
4446
     * the tree.
4447
     */
4448
0
    if (qpdbiter->node->nspace != DNS_DBNAMESPACE_NSEC) {
4449
0
      break;
4450
0
    }
4451
0
    INSIST(qpdbiter->node->nspace == DNS_DBNAMESPACE_NSEC);
4452
4453
0
    result = dns_qp_lookup(qpdbiter->snap, &qpdb->common.origin,
4454
0
               DNS_DBNAMESPACE_NSEC3, NULL,
4455
0
               &qpdbiter->iter, NULL,
4456
0
               (void **)&qpdbiter->node, NULL);
4457
0
    if (result != ISC_R_SUCCESS ||
4458
0
        QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
4459
0
    {
4460
      /* skip the NSEC3 origin node (or its predecessor). */
4461
0
      result = dns_qpiter_next(&qpdbiter->iter, NULL,
4462
0
             (void **)&qpdbiter->node,
4463
0
             NULL);
4464
0
    }
4465
0
    break;
4466
0
  case nsec3only:
4467
0
    break;
4468
0
  default:
4469
0
    UNREACHABLE();
4470
0
  }
4471
4472
0
  if (result == ISC_R_SUCCESS) {
4473
0
    reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4474
0
  } else {
4475
0
    qpdbiter->node = NULL;
4476
0
  }
4477
4478
0
  qpdbiter->result = result;
4479
0
  return result;
4480
0
}
4481
4482
static isc_result_t
4483
dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
4484
0
       dns_name_t *name DNS__DB_FLARG) {
4485
0
  qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
4486
0
  qpznode_t *node = qpdbiter->node;
4487
4488
0
  REQUIRE(qpdbiter->result == ISC_R_SUCCESS);
4489
0
  REQUIRE(qpdbiter->node != NULL);
4490
4491
0
  if (name != NULL) {
4492
0
    dns_name_copy(&qpdbiter->node->name, name);
4493
0
  }
4494
4495
0
  qpznode_acquire(node DNS__DB_FLARG_PASS);
4496
4497
0
  *nodep = (dns_dbnode_t *)qpdbiter->node;
4498
4499
0
  return ISC_R_SUCCESS;
4500
0
}
4501
4502
static isc_result_t
4503
0
dbiterator_pause(dns_dbiterator_t *iterator ISC_ATTR_UNUSED) {
4504
0
  return ISC_R_SUCCESS;
4505
0
}
4506
4507
static isc_result_t
4508
0
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
4509
0
  qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
4510
4511
0
  if (qpdbiter->result != ISC_R_SUCCESS) {
4512
0
    return qpdbiter->result;
4513
0
  }
4514
4515
0
  dns_name_copy(dns_rootname, name);
4516
0
  return ISC_R_SUCCESS;
4517
0
}
4518
4519
static isc_result_t
4520
qpzone_createiterator(dns_db_t *db, unsigned int options,
4521
0
          dns_dbiterator_t **iteratorp) {
4522
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
4523
0
  qpdb_dbiterator_t *iter = NULL;
4524
0
  isc_result_t result;
4525
4526
0
  REQUIRE(VALID_QPZONE(qpdb));
4527
4528
0
  iter = isc_mem_get(qpdb->common.mctx, sizeof(*iter));
4529
0
  *iter = (qpdb_dbiterator_t){
4530
0
    .common.magic = DNS_DBITERATOR_MAGIC,
4531
0
    .common.methods = &dbiterator_methods,
4532
0
    .common.relative_names = ((options & DNS_DB_RELATIVENAMES) !=
4533
0
            0),
4534
0
  };
4535
4536
0
  if ((options & DNS_DB_NSEC3ONLY) != 0) {
4537
0
    iter->nsec3mode = nsec3only;
4538
0
  } else if ((options & DNS_DB_NONSEC3) != 0) {
4539
0
    iter->nsec3mode = nonsec3;
4540
0
  } else {
4541
0
    iter->nsec3mode = full;
4542
0
  }
4543
4544
0
  dns_db_attach(db, &iter->common.db);
4545
4546
0
  dns_qpmulti_snapshot(qpdb->tree, &iter->snap);
4547
4548
0
  switch (iter->nsec3mode) {
4549
0
  case nonsec3:
4550
0
  case full:
4551
0
    dns_qpiter_init(iter->snap, &iter->iter);
4552
0
    break;
4553
0
  case nsec3only:
4554
    /*
4555
     * NSEC3 follows after all non-nsec3 nodes,
4556
     * seek the NSEC3 origin node.
4557
     */
4558
0
    result = dns_qp_lookup(iter->snap, &qpdb->common.origin,
4559
0
               DNS_DBNAMESPACE_NSEC3, NULL, &iter->iter,
4560
0
               NULL, NULL, NULL);
4561
0
    INSIST(result == ISC_R_SUCCESS);
4562
0
    break;
4563
0
  default:
4564
0
    UNREACHABLE();
4565
0
  }
4566
4567
0
  *iteratorp = (dns_dbiterator_t *)iter;
4568
0
  return ISC_R_SUCCESS;
4569
0
}
4570
4571
static isc_result_t
4572
qpzone_addrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
4573
       dns_dbversion_t *dbversion,
4574
       isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
4575
       unsigned int options,
4576
0
       dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
4577
0
  isc_result_t result;
4578
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
4579
0
  qpznode_t *node = (qpznode_t *)dbnode;
4580
0
  qpz_version_t *version = (qpz_version_t *)dbversion;
4581
0
  isc_region_t region;
4582
0
  dns_slabheader_t *newheader = NULL;
4583
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
4584
0
  isc_rwlock_t *nlock = NULL;
4585
0
  dns_fixedname_t fn;
4586
0
  dns_name_t *name = dns_fixedname_initname(&fn);
4587
0
  dns_qp_t *nsec = NULL;
4588
4589
0
  REQUIRE(VALID_QPZONE(qpdb));
4590
0
  REQUIRE(version != NULL && version->qpdb == qpdb);
4591
4592
  /*
4593
   * SOA records are only allowed at top of zone.
4594
   */
4595
0
  if (rdataset->type == dns_rdatatype_soa && node != qpdb->origin) {
4596
0
    return DNS_R_NOTZONETOP;
4597
0
  }
4598
4599
0
  REQUIRE((node->nspace == DNS_DBNAMESPACE_NSEC3 &&
4600
0
     (rdataset->type == dns_rdatatype_nsec3 ||
4601
0
      rdataset->covers == dns_rdatatype_nsec3)) ||
4602
0
    (node->nspace != DNS_DBNAMESPACE_NSEC3 &&
4603
0
     rdataset->type != dns_rdatatype_nsec3 &&
4604
0
     rdataset->covers != dns_rdatatype_nsec3));
4605
4606
0
  result = dns_rdataslab_fromrdataset(rdataset, node->mctx, &region,
4607
0
              qpdb->maxrrperset);
4608
0
  if (result != ISC_R_SUCCESS) {
4609
0
    if (result == DNS_R_TOOMANYRECORDS) {
4610
0
      dns__db_logtoomanyrecords((dns_db_t *)qpdb, &node->name,
4611
0
              rdataset->type, "adding",
4612
0
              qpdb->maxrrperset);
4613
0
    }
4614
0
    return result;
4615
0
  }
4616
4617
0
  dns_name_copy(&node->name, name);
4618
0
  dns_rdataset_getownercase(rdataset, name);
4619
4620
0
  newheader = (dns_slabheader_t *)region.base;
4621
0
  dns_slabheader_reset(newheader, (dns_dbnode_t *)node);
4622
0
  dns_slabheader_setownercase(newheader, name);
4623
4624
0
  newheader->ttl = rdataset->ttl;
4625
0
  if (rdataset->ttl == 0U) {
4626
0
    DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_ZEROTTL);
4627
0
  }
4628
4629
0
  newheader->serial = version->serial;
4630
0
  if (rdataset->attributes.resign) {
4631
0
    DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN);
4632
0
    newheader->resign =
4633
0
      (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >>
4634
0
          1);
4635
0
    newheader->resign_lsb = rdataset->resign & 0x1;
4636
0
  }
4637
4638
  /*
4639
   * Add to the auxiliary NSEC tree if we're adding an NSEC record.
4640
   */
4641
0
  if (!node->havensec && rdataset->type == dns_rdatatype_nsec) {
4642
0
    dns_qpmulti_write(qpdb->tree, &nsec);
4643
0
  }
4644
4645
  /*
4646
   * If we're adding a delegation type or adding to the auxiliary NSEC
4647
   * tree hold an exclusive lock on the tree.  In the latter case the
4648
   * lock does not necessarily have to be acquired but it will help
4649
   * purge ancient entries more effectively.
4650
   *
4651
   * (Note: node lock must be acquired after starting
4652
   * the QPDB transaction and released before committing.)
4653
   */
4654
0
  nlock = qpzone_get_lock(node);
4655
4656
0
  NODE_WRLOCK(nlock, &nlocktype);
4657
4658
0
  result = ISC_R_SUCCESS;
4659
0
  if (nsec != NULL) {
4660
0
    node->havensec = true;
4661
4662
    /*
4663
     * If it fails, there was already an NSEC node,
4664
     * so we can detach the new one we created and
4665
     * move on.
4666
     */
4667
0
    qpznode_t *nsecnode = new_qpznode(qpdb, name,
4668
0
              DNS_DBNAMESPACE_NSEC);
4669
0
    (void)dns_qp_insert(nsec, nsecnode, 0);
4670
0
    qpznode_detach(&nsecnode);
4671
0
  }
4672
4673
0
  if (result == ISC_R_SUCCESS) {
4674
0
    result = add(qpdb, node, name, version, newheader, options,
4675
0
           false, addedrdataset, 0 DNS__DB_FLARG_PASS);
4676
0
  }
4677
4678
  /*
4679
   * If we're adding a delegation type (e.g. NS or DNAME),
4680
   * then we need to set the callback bit on the node.
4681
   */
4682
0
  if (result == ISC_R_SUCCESS &&
4683
0
      delegating_type(qpdb, node, rdataset->type))
4684
0
  {
4685
0
    node->delegating = true;
4686
0
  }
4687
4688
0
  NODE_UNLOCK(nlock, &nlocktype);
4689
4690
0
  if (nsec != NULL) {
4691
0
    dns_qpmulti_commit(qpdb->tree, &nsec);
4692
0
  }
4693
4694
0
  return result;
4695
0
}
4696
4697
static isc_result_t
4698
qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
4699
      dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
4700
      unsigned int options,
4701
0
      dns_rdataset_t *newrdataset DNS__DB_FLARG) {
4702
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
4703
0
  qpznode_t *node = (qpznode_t *)dbnode;
4704
0
  qpz_version_t *version = (qpz_version_t *)dbversion;
4705
0
  dns_fixedname_t fname;
4706
0
  dns_name_t *nodename = dns_fixedname_initname(&fname);
4707
0
  dns_slabtop_t *foundtop = NULL;
4708
0
  dns_slabheader_t *newheader = NULL;
4709
0
  dns_slabheader_t *subresult = NULL;
4710
0
  isc_region_t region;
4711
0
  isc_result_t result;
4712
0
  qpz_changed_t *changed = NULL;
4713
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
4714
0
  isc_rwlock_t *nlock;
4715
4716
0
  REQUIRE(VALID_QPZONE(qpdb));
4717
0
  REQUIRE(version != NULL && version->qpdb == qpdb);
4718
4719
0
  REQUIRE((node->nspace == DNS_DBNAMESPACE_NSEC3 &&
4720
0
     (rdataset->type == dns_rdatatype_nsec3 ||
4721
0
      rdataset->covers == dns_rdatatype_nsec3)) ||
4722
0
    (node->nspace != DNS_DBNAMESPACE_NSEC3 &&
4723
0
     rdataset->type != dns_rdatatype_nsec3 &&
4724
0
     rdataset->covers != dns_rdatatype_nsec3));
4725
4726
0
  dns_name_copy(&node->name, nodename);
4727
0
  result = dns_rdataslab_fromrdataset(rdataset, node->mctx, &region, 0);
4728
0
  if (result != ISC_R_SUCCESS) {
4729
0
    return result;
4730
0
  }
4731
4732
0
  newheader = (dns_slabheader_t *)region.base;
4733
0
  dns_slabheader_reset(newheader, (dns_dbnode_t *)node);
4734
0
  newheader->ttl = rdataset->ttl;
4735
0
  atomic_init(&newheader->attributes, 0);
4736
0
  newheader->serial = version->serial;
4737
0
  if (rdataset->attributes.resign) {
4738
0
    DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN);
4739
0
    newheader->resign =
4740
0
      (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >>
4741
0
          1);
4742
0
    newheader->resign_lsb = rdataset->resign & 0x1;
4743
0
  }
4744
4745
0
  nlock = qpzone_get_lock(node);
4746
0
  NODE_WRLOCK(nlock, &nlocktype);
4747
4748
0
  changed = add_changed(qpdb, newheader, version DNS__DB_FLARG_PASS);
4749
0
  DNS_SLABTOP_FOREACH(top, node->data) {
4750
0
    if (top->typepair == newheader->typepair) {
4751
0
      foundtop = top;
4752
0
      break;
4753
0
    }
4754
0
  }
4755
  /*
4756
   * If header isn't NULL, we've found the right type.  There may be
4757
   * IGNORE rdatasets between the top of the chain and the first real
4758
   * data.  We skip over them.
4759
   */
4760
0
  dns_slabheader_t *header = NULL;
4761
0
  if (foundtop != NULL) {
4762
0
    dns_slabheader_t *tmp = NULL;
4763
0
    cds_list_for_each_entry(tmp, &foundtop->headers, headers_link) {
4764
0
      if (!IGNORE(tmp)) {
4765
0
        header = tmp;
4766
0
        break;
4767
0
      }
4768
0
    }
4769
0
  }
4770
0
  if (header != NULL && EXISTS(header)) {
4771
0
    unsigned int flags = 0;
4772
0
    subresult = NULL;
4773
0
    result = ISC_R_SUCCESS;
4774
0
    if ((options & DNS_DBSUB_EXACT) != 0) {
4775
0
      flags |= DNS_RDATASLAB_EXACT;
4776
0
      if (newheader->ttl != header->ttl) {
4777
0
        result = DNS_R_NOTEXACT;
4778
0
      }
4779
0
    }
4780
0
    if (result == ISC_R_SUCCESS) {
4781
0
      result = dns_rdataslab_subtract(
4782
0
        header, newheader, qpdb->common.mctx,
4783
0
        qpdb->common.rdclass,
4784
0
        DNS_TYPEPAIR_TYPE(foundtop->typepair), flags,
4785
0
        &subresult);
4786
0
    }
4787
0
    if (result == ISC_R_SUCCESS) {
4788
0
      dns_slabheader_destroy(&newheader);
4789
0
      newheader = subresult;
4790
0
      dns_slabheader_reset(newheader, (dns_dbnode_t *)node);
4791
0
      dns_slabheader_copycase(newheader, header);
4792
0
      if (RESIGN(header)) {
4793
0
        DNS_SLABHEADER_SETATTR(
4794
0
          newheader, DNS_SLABHEADERATTR_RESIGN);
4795
0
        newheader->resign = header->resign;
4796
0
        newheader->resign_lsb = header->resign_lsb;
4797
0
        resigninsert(newheader);
4798
0
      }
4799
      /*
4800
       * We have to set the serial since the rdataslab
4801
       * subtraction routine copies the reserved portion of
4802
       * header, not newheader.
4803
       */
4804
0
      newheader->serial = version->serial;
4805
      /*
4806
       * XXXJT: dns_rdataslab_subtract() copied the pointers
4807
       * to additional info.  We need to clear these fields
4808
       * to avoid having duplicated references.
4809
       */
4810
0
      maybe_update_recordsandsize(true, version, newheader,
4811
0
                nodename->length);
4812
0
    } else if (result == DNS_R_NXRRSET) {
4813
      /*
4814
       * This subtraction would remove all of the rdata;
4815
       * add a nonexistent header instead.
4816
       */
4817
0
      dns_slabheader_destroy(&newheader);
4818
0
      newheader = dns_slabheader_new(db->mctx,
4819
0
                   (dns_dbnode_t *)node);
4820
0
      newheader->ttl = 0;
4821
0
      newheader->typepair = foundtop->typepair;
4822
0
      atomic_init(&newheader->attributes,
4823
0
            DNS_SLABHEADERATTR_NONEXISTENT);
4824
0
      newheader->serial = version->serial;
4825
0
    } else {
4826
0
      dns_slabheader_destroy(&newheader);
4827
0
      goto unlock;
4828
0
    }
4829
4830
    /*
4831
     * If we're here, we want to link newheader at the top.
4832
     */
4833
0
    maybe_update_recordsandsize(false, version, header,
4834
0
              nodename->length);
4835
4836
0
    newheader->top = foundtop;
4837
0
    cds_list_add(&newheader->headers_link, &foundtop->headers);
4838
4839
0
    node->dirty = true;
4840
0
    changed->dirty = true;
4841
0
    resigndelete(qpdb, version, header DNS__DB_FLARG_PASS);
4842
0
  } else {
4843
    /*
4844
     * The rdataset doesn't exist, so we don't need to do anything
4845
     * to satisfy the deletion request.
4846
     */
4847
0
    dns_slabheader_destroy(&newheader);
4848
0
    if ((options & DNS_DBSUB_EXACT) != 0) {
4849
0
      result = DNS_R_NOTEXACT;
4850
0
    } else {
4851
0
      result = DNS_R_UNCHANGED;
4852
0
    }
4853
0
  }
4854
4855
0
  if (result == ISC_R_SUCCESS && newrdataset != NULL) {
4856
0
    bindrdataset(qpdb, node, newheader,
4857
0
           newrdataset DNS__DB_FLARG_PASS);
4858
0
  }
4859
4860
0
  if (result == DNS_R_NXRRSET && newrdataset != NULL &&
4861
0
      (options & DNS_DBSUB_WANTOLD) != 0)
4862
0
  {
4863
0
    bindrdataset(qpdb, node, header,
4864
0
           newrdataset DNS__DB_FLARG_PASS);
4865
0
  }
4866
4867
0
unlock:
4868
0
  NODE_UNLOCK(nlock, &nlocktype);
4869
0
  return result;
4870
0
}
4871
4872
static isc_result_t
4873
qpzone_deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode,
4874
          dns_dbversion_t *dbversion, dns_rdatatype_t type,
4875
0
          dns_rdatatype_t covers DNS__DB_FLARG) {
4876
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
4877
0
  qpznode_t *node = (qpznode_t *)dbnode;
4878
0
  qpz_version_t *version = (qpz_version_t *)dbversion;
4879
0
  dns_fixedname_t fname;
4880
0
  dns_name_t *nodename = dns_fixedname_initname(&fname);
4881
0
  isc_result_t result;
4882
0
  dns_slabheader_t *newheader = NULL;
4883
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
4884
0
  isc_rwlock_t *nlock = NULL;
4885
4886
0
  REQUIRE(VALID_QPZONE(qpdb));
4887
0
  REQUIRE(version != NULL && version->qpdb == qpdb);
4888
4889
0
  if (type == dns_rdatatype_any) {
4890
0
    return ISC_R_NOTIMPLEMENTED;
4891
0
  }
4892
0
  if (type == dns_rdatatype_rrsig && covers == dns_rdatatype_none) {
4893
0
    return ISC_R_NOTIMPLEMENTED;
4894
0
  }
4895
4896
0
  newheader = dns_slabheader_new(db->mctx, (dns_dbnode_t *)node);
4897
0
  newheader->typepair = DNS_TYPEPAIR_VALUE(type, covers);
4898
0
  newheader->ttl = 0;
4899
0
  atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT);
4900
0
  newheader->serial = version->serial;
4901
4902
0
  dns_name_copy(&node->name, nodename);
4903
4904
0
  nlock = qpzone_get_lock(node);
4905
0
  NODE_WRLOCK(nlock, &nlocktype);
4906
0
  result = add(qpdb, node, nodename, version, newheader, DNS_DBADD_FORCE,
4907
0
         false, NULL, 0 DNS__DB_FLARG_PASS);
4908
0
  NODE_UNLOCK(nlock, &nlocktype);
4909
0
  return result;
4910
0
}
4911
4912
static dns_glue_t *
4913
0
new_glue(isc_mem_t *mctx, const dns_name_t *name) {
4914
0
  dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue));
4915
0
  *glue = (dns_glue_t){
4916
0
    .name = DNS_NAME_INITEMPTY,
4917
0
  };
4918
4919
0
  dns_name_dup(name, mctx, &glue->name);
4920
4921
0
  return glue;
4922
0
}
4923
4924
static dns_gluelist_t *
4925
new_gluelist(dns_db_t *db, dns_slabheader_t *header,
4926
0
       const dns_dbversion_t *dbversion) {
4927
0
  dns_gluelist_t *gluelist = isc_mem_get(db->mctx, sizeof(*gluelist));
4928
0
  *gluelist = (dns_gluelist_t){
4929
0
    .version = dbversion,
4930
0
    .header = header,
4931
0
  };
4932
4933
0
  isc_mem_attach(db->mctx, &gluelist->mctx);
4934
4935
0
  cds_wfs_node_init(&gluelist->wfs_node);
4936
4937
0
  return gluelist;
4938
0
}
4939
4940
static isc_result_t
4941
glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
4942
0
    dns_rdataset_t *rdataset ISC_ATTR_UNUSED DNS__DB_FLARG) {
4943
0
  dns_glue_additionaldata_ctx_t *ctx = NULL;
4944
0
  isc_result_t result;
4945
0
  dns_fixedname_t fixedname_a;
4946
0
  dns_name_t *name_a = NULL;
4947
0
  dns_rdataset_t rdataset_a, sigrdataset_a;
4948
0
  const qpznode_t *node = NULL;
4949
0
  qpznode_t *node_a = NULL;
4950
0
  dns_fixedname_t fixedname_aaaa;
4951
0
  dns_name_t *name_aaaa = NULL;
4952
0
  dns_rdataset_t rdataset_aaaa, sigrdataset_aaaa;
4953
0
  qpznode_t *node_aaaa = NULL;
4954
0
  dns_glue_t *glue = NULL;
4955
4956
  /*
4957
   * NS records want addresses in additional records.
4958
   */
4959
0
  INSIST(qtype == dns_rdatatype_a);
4960
4961
0
  ctx = (dns_glue_additionaldata_ctx_t *)arg;
4962
4963
0
  node = (qpznode_t *)ctx->node;
4964
4965
0
  name_a = dns_fixedname_initname(&fixedname_a);
4966
0
  dns_rdataset_init(&rdataset_a);
4967
0
  dns_rdataset_init(&sigrdataset_a);
4968
4969
0
  name_aaaa = dns_fixedname_initname(&fixedname_aaaa);
4970
0
  dns_rdataset_init(&rdataset_aaaa);
4971
0
  dns_rdataset_init(&sigrdataset_aaaa);
4972
4973
0
  result = qpzone_find(ctx->db, name, ctx->version, dns_rdatatype_a,
4974
0
           DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a,
4975
0
           name_a, NULL, NULL, &rdataset_a,
4976
0
           &sigrdataset_a DNS__DB_FLARG_PASS);
4977
0
  if (result == DNS_R_GLUE) {
4978
0
    glue = new_glue(ctx->db->mctx, name_a);
4979
4980
0
    dns_rdataset_init(&glue->rdataset_a);
4981
0
    dns_rdataset_init(&glue->sigrdataset_a);
4982
0
    dns_rdataset_init(&glue->rdataset_aaaa);
4983
0
    dns_rdataset_init(&glue->sigrdataset_aaaa);
4984
4985
0
    dns_rdataset_clone(&rdataset_a, &glue->rdataset_a);
4986
0
    if (dns_rdataset_isassociated(&sigrdataset_a)) {
4987
0
      dns_rdataset_clone(&sigrdataset_a,
4988
0
             &glue->sigrdataset_a);
4989
0
    }
4990
0
  }
4991
4992
0
  result = qpzone_find(ctx->db, name, ctx->version, dns_rdatatype_aaaa,
4993
0
           DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_aaaa,
4994
0
           name_aaaa, NULL, NULL, &rdataset_aaaa,
4995
0
           &sigrdataset_aaaa DNS__DB_FLARG_PASS);
4996
0
  if (result == DNS_R_GLUE) {
4997
0
    if (glue == NULL) {
4998
0
      glue = new_glue(ctx->db->mctx, name_aaaa);
4999
5000
0
      dns_rdataset_init(&glue->rdataset_a);
5001
0
      dns_rdataset_init(&glue->sigrdataset_a);
5002
0
      dns_rdataset_init(&glue->rdataset_aaaa);
5003
0
      dns_rdataset_init(&glue->sigrdataset_aaaa);
5004
0
    } else {
5005
0
      INSIST(node_a == node_aaaa);
5006
0
      INSIST(dns_name_equal(name_a, name_aaaa));
5007
0
    }
5008
5009
0
    dns_rdataset_clone(&rdataset_aaaa, &glue->rdataset_aaaa);
5010
0
    if (dns_rdataset_isassociated(&sigrdataset_aaaa)) {
5011
0
      dns_rdataset_clone(&sigrdataset_aaaa,
5012
0
             &glue->sigrdataset_aaaa);
5013
0
    }
5014
0
  }
5015
5016
  /*
5017
   * If the currently processed NS record is in-bailiwick, mark any glue
5018
   * RRsets found for it with 'required' attribute.  Note that for
5019
   * simplicity, glue RRsets for all in-bailiwick NS records are marked
5020
   * this way, even though dns_message_rendersection() only checks the
5021
   * attributes for the first rdataset associated with the first name
5022
   * added to the ADDITIONAL section.
5023
   */
5024
0
  if (glue != NULL && dns_name_issubdomain(name, &node->name)) {
5025
0
    if (dns_rdataset_isassociated(&glue->rdataset_a)) {
5026
0
      glue->rdataset_a.attributes.required = true;
5027
0
    }
5028
0
    if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) {
5029
0
      glue->rdataset_aaaa.attributes.required = true;
5030
0
    }
5031
0
  }
5032
5033
0
  if (glue != NULL) {
5034
0
    glue->next = ctx->glue;
5035
0
    ctx->glue = glue;
5036
0
  }
5037
5038
0
  result = ISC_R_SUCCESS;
5039
5040
0
  if (dns_rdataset_isassociated(&rdataset_a)) {
5041
0
    dns_rdataset_disassociate(&rdataset_a);
5042
0
  }
5043
0
  if (dns_rdataset_isassociated(&sigrdataset_a)) {
5044
0
    dns_rdataset_disassociate(&sigrdataset_a);
5045
0
  }
5046
5047
0
  if (dns_rdataset_isassociated(&rdataset_aaaa)) {
5048
0
    dns_rdataset_disassociate(&rdataset_aaaa);
5049
0
  }
5050
0
  if (dns_rdataset_isassociated(&sigrdataset_aaaa)) {
5051
0
    dns_rdataset_disassociate(&sigrdataset_aaaa);
5052
0
  }
5053
5054
0
  if (node_a != NULL) {
5055
0
    dns__db_detachnode((dns_dbnode_t **)&node_a DNS__DB_FLARG_PASS);
5056
0
  }
5057
0
  if (node_aaaa != NULL) {
5058
0
    dns__db_detachnode(
5059
0
      (dns_dbnode_t **)&node_aaaa DNS__DB_FLARG_PASS);
5060
0
  }
5061
5062
0
  return result;
5063
0
}
5064
5065
0
#define IS_REQUIRED_GLUE(r) (((r)->attributes.required))
5066
5067
static void
5068
0
addglue_to_message(dns_glue_t *ge, dns_message_t *msg) {
5069
0
  for (; ge != NULL; ge = ge->next) {
5070
0
    dns_name_t *name = NULL;
5071
0
    dns_rdataset_t *rdataset_a = NULL;
5072
0
    dns_rdataset_t *sigrdataset_a = NULL;
5073
0
    dns_rdataset_t *rdataset_aaaa = NULL;
5074
0
    dns_rdataset_t *sigrdataset_aaaa = NULL;
5075
0
    bool prepend_name = false;
5076
5077
0
    dns_message_gettempname(msg, &name);
5078
5079
0
    dns_name_copy(&ge->name, name);
5080
5081
0
    if (dns_rdataset_isassociated(&ge->rdataset_a)) {
5082
0
      dns_message_gettemprdataset(msg, &rdataset_a);
5083
0
    }
5084
5085
0
    if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
5086
0
      dns_message_gettemprdataset(msg, &sigrdataset_a);
5087
0
    }
5088
5089
0
    if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
5090
0
      dns_message_gettemprdataset(msg, &rdataset_aaaa);
5091
0
    }
5092
5093
0
    if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
5094
0
      dns_message_gettemprdataset(msg, &sigrdataset_aaaa);
5095
0
    }
5096
5097
0
    if (rdataset_a != NULL) {
5098
0
      dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
5099
0
      ISC_LIST_APPEND(name->list, rdataset_a, link);
5100
0
      if (IS_REQUIRED_GLUE(rdataset_a)) {
5101
0
        prepend_name = true;
5102
0
      }
5103
0
    }
5104
5105
0
    if (sigrdataset_a != NULL) {
5106
0
      dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a);
5107
0
      ISC_LIST_APPEND(name->list, sigrdataset_a, link);
5108
0
    }
5109
5110
0
    if (rdataset_aaaa != NULL) {
5111
0
      dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa);
5112
0
      ISC_LIST_APPEND(name->list, rdataset_aaaa, link);
5113
0
      if (IS_REQUIRED_GLUE(rdataset_aaaa)) {
5114
0
        prepend_name = true;
5115
0
      }
5116
0
    }
5117
0
    if (sigrdataset_aaaa != NULL) {
5118
0
      dns_rdataset_clone(&ge->sigrdataset_aaaa,
5119
0
             sigrdataset_aaaa);
5120
0
      ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link);
5121
0
    }
5122
5123
0
    dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
5124
5125
    /*
5126
     * When looking for required glue, dns_message_rendersection()
5127
     * only processes the first rdataset associated with the first
5128
     * name added to the ADDITIONAL section.  dns_message_addname()
5129
     * performs an append on the list of names in a given section,
5130
     * so if any glue record was marked as required, we need to
5131
     * move the name it is associated with to the beginning of the
5132
     * list for the ADDITIONAL section or else required glue might
5133
     * not be rendered.
5134
     */
5135
0
    if (prepend_name) {
5136
0
      ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL],
5137
0
          name, link);
5138
0
      ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL],
5139
0
           name, link);
5140
0
    }
5141
0
  }
5142
0
}
5143
5144
static dns_gluelist_t *
5145
create_gluelist(qpzonedb_t *qpdb, qpz_version_t *version, qpznode_t *node,
5146
0
    dns_rdataset_t *rdataset) {
5147
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
5148
0
  dns_glue_additionaldata_ctx_t ctx = {
5149
0
    .db = (dns_db_t *)qpdb,
5150
0
    .version = (dns_dbversion_t *)version,
5151
0
    .node = (dns_dbnode_t *)node,
5152
0
  };
5153
0
  dns_gluelist_t *gluelist = new_gluelist(ctx.db, header, ctx.version);
5154
5155
  /*
5156
   * Get the owner name of the NS RRset - it will be necessary for
5157
   * identifying required glue in glue_nsdname_cb() (by
5158
   * determining which NS records in the delegation are
5159
   * in-bailiwick).
5160
   */
5161
5162
0
  (void)dns_rdataset_additionaldata(rdataset, dns_rootname,
5163
0
            glue_nsdname_cb, &ctx, 0);
5164
5165
0
  CMM_STORE_SHARED(gluelist->glue, ctx.glue);
5166
5167
0
  return gluelist;
5168
0
}
5169
5170
static void
5171
addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
5172
0
  dns_message_t *msg) {
5173
0
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
5174
0
  qpz_version_t *version = (qpz_version_t *)dbversion;
5175
0
  qpznode_t *node = (qpznode_t *)rdataset->slab.node;
5176
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
5177
0
  dns_glue_t *glue = NULL;
5178
0
  isc_statscounter_t counter = dns_gluecachestatscounter_hits_absent;
5179
5180
0
  REQUIRE(rdataset->type == dns_rdatatype_ns);
5181
0
  REQUIRE(qpdb == (qpzonedb_t *)rdataset->slab.db);
5182
0
  REQUIRE(qpdb == version->qpdb);
5183
0
  REQUIRE(!IS_STUB(qpdb));
5184
5185
0
  rcu_read_lock();
5186
5187
0
  dns_gluelist_t *gluelist = rcu_dereference(header->gluelist);
5188
0
  if (gluelist == NULL || gluelist->version != dbversion) {
5189
    /* No or old glue list was found in the table. */
5190
5191
0
    dns_gluelist_t *xchg_gluelist = gluelist;
5192
0
    dns_gluelist_t *old_gluelist = (void *)-1;
5193
0
    dns_gluelist_t *new_gluelist = create_gluelist(qpdb, version,
5194
0
                     node, rdataset);
5195
5196
0
    while (old_gluelist != xchg_gluelist &&
5197
0
           (xchg_gluelist == NULL ||
5198
0
      xchg_gluelist->version != dbversion))
5199
0
    {
5200
0
      old_gluelist = xchg_gluelist;
5201
0
      xchg_gluelist = rcu_cmpxchg_pointer(
5202
0
        &header->gluelist, old_gluelist, new_gluelist);
5203
0
    }
5204
5205
0
    if (old_gluelist == xchg_gluelist) {
5206
      /* CAS was successful */
5207
0
      cds_wfs_push(&version->glue_stack,
5208
0
             &new_gluelist->wfs_node);
5209
0
      gluelist = new_gluelist;
5210
0
    } else {
5211
0
      destroy_gluelist(&new_gluelist);
5212
0
      gluelist = xchg_gluelist;
5213
0
    }
5214
0
  }
5215
5216
0
  glue = CMM_LOAD_SHARED(gluelist->glue);
5217
5218
0
  if (glue != NULL) {
5219
0
    addglue_to_message(glue, msg);
5220
0
    counter = dns_gluecachestatscounter_hits_present;
5221
0
  }
5222
5223
0
  rcu_read_unlock();
5224
5225
  /* We have a cached result. Add it to the message and return. */
5226
0
  if (qpdb->gluecachestats != NULL) {
5227
0
    isc_stats_increment(qpdb->gluecachestats, counter);
5228
0
  }
5229
0
}
5230
5231
static void
5232
2
setmaxrrperset(dns_db_t *db, uint32_t value) {
5233
2
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
5234
5235
2
  REQUIRE(VALID_QPZONE(qpdb));
5236
5237
2
  qpdb->maxrrperset = value;
5238
2
}
5239
5240
static void
5241
2
setmaxtypepername(dns_db_t *db, uint32_t value) {
5242
2
  qpzonedb_t *qpdb = (qpzonedb_t *)db;
5243
5244
2
  REQUIRE(VALID_QPZONE(qpdb));
5245
5246
2
  qpdb->maxtypepername = value;
5247
2
}
5248
5249
static dns_dbmethods_t qpdb_zonemethods = {
5250
  .destroy = qpdb_destroy,
5251
  .beginload = beginload,
5252
  .endload = endload,
5253
  .currentversion = currentversion,
5254
  .newversion = newversion,
5255
  .attachversion = attachversion,
5256
  .closeversion = closeversion,
5257
  .findnode = qpzone_findnode,
5258
  .find = qpzone_find,
5259
  .createiterator = qpzone_createiterator,
5260
  .findrdataset = qpzone_findrdataset,
5261
  .allrdatasets = qpzone_allrdatasets,
5262
  .addrdataset = qpzone_addrdataset,
5263
  .subtractrdataset = qpzone_subtractrdataset,
5264
  .deleterdataset = qpzone_deleterdataset,
5265
  .issecure = issecure,
5266
  .nodecount = nodecount,
5267
  .getoriginnode = getoriginnode,
5268
  .getnsec3parameters = getnsec3parameters,
5269
  .findnsec3node = qpzone_findnsec3node,
5270
  .setsigningtime = setsigningtime,
5271
  .getsigningtime = getsigningtime,
5272
  .getsize = getsize,
5273
  .setgluecachestats = setgluecachestats,
5274
  .addglue = addglue,
5275
  .setmaxrrperset = setmaxrrperset,
5276
  .setmaxtypepername = setmaxtypepername,
5277
};
5278
5279
static dns_dbnode_methods_t qpznode_methods = (dns_dbnode_methods_t){
5280
  .attachnode = qpzone_attachnode,
5281
  .detachnode = qpzone_detachnode,
5282
  .deletedata = deletedata,
5283
};
5284
5285
static void
5286
6.39M
destroy_qpznode(qpznode_t *node) {
5287
6.39M
  DNS_SLABTOP_FOREACH(top, node->data) {
5288
5.35M
    dns_slabheader_t *header = NULL, *header_next = NULL;
5289
5.35M
    cds_list_for_each_entry_safe(header, header_next, &top->headers,
5290
5.35M
               headers_link)
5291
5.35M
    {
5292
5.35M
      cds_list_del(&header->headers_link);
5293
5.35M
      dns_slabheader_destroy(&header);
5294
5.35M
    }
5295
5296
5.35M
    dns_slabtop_destroy(node->mctx, &top);
5297
5.35M
  }
5298
5299
6.39M
  qpz_heap_unref(node->heap);
5300
6.39M
  dns_name_free(&node->name, node->mctx);
5301
6.39M
  isc_mem_putanddetach(&node->mctx, node, sizeof(qpznode_t));
5302
6.39M
}
5303
5304
#if DNS_DB_NODETRACE
5305
ISC_REFCOUNT_STATIC_TRACE_IMPL(qpznode, destroy_qpznode);
5306
#else
5307
25.6M
ISC_REFCOUNT_STATIC_IMPL(qpznode, destroy_qpznode);
qpzone.c:qpznode_ref
Line
Count
Source
5307
ISC_REFCOUNT_STATIC_IMPL(qpznode, destroy_qpznode);
qpzone.c:qpznode_detach
Line
Count
Source
5307
ISC_REFCOUNT_STATIC_IMPL(qpznode, destroy_qpznode);
qpzone.c:qpznode_unref
Line
Count
Source
5307
ISC_REFCOUNT_STATIC_IMPL(qpznode, destroy_qpznode);
5308
25.6M
#endif
5309
25.6M
5310
25.6M
ISC_REFCOUNT_STATIC_IMPL(qpz_heap, qpz_heap_destroy);
qpzone.c:qpz_heap_unref
Line
Count
Source
5310
ISC_REFCOUNT_STATIC_IMPL(qpz_heap, qpz_heap_destroy);
qpzone.c:qpz_heap_ref
Line
Count
Source
5310
ISC_REFCOUNT_STATIC_IMPL(qpz_heap, qpz_heap_destroy);
qpzone.c:qpz_heap_detach
Line
Count
Source
5310
ISC_REFCOUNT_STATIC_IMPL(qpz_heap, qpz_heap_destroy);
5311
12.8M
5312
12.8M
static void
5313
12.8M
qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
5314
12.8M
    uint32_t ival ISC_ATTR_UNUSED) {
5315
6.41M
  qpznode_t *data = pval;
5316
6.41M
  qpznode_ref(data);
5317
6.41M
}
5318
5319
static void
5320
qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
5321
6.41M
    uint32_t ival ISC_ATTR_UNUSED) {
5322
6.41M
  qpznode_t *data = pval;
5323
6.41M
  qpznode_detach(&data);
5324
6.41M
}
5325
5326
static size_t
5327
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
5328
16.7M
     uint32_t ival ISC_ATTR_UNUSED) {
5329
16.7M
  qpznode_t *data = pval;
5330
16.7M
  return dns_qpkey_fromname(key, &data->name, data->nspace);
5331
16.7M
}
5332
5333
static void
5334
0
qp_triename(void *uctx ISC_ATTR_UNUSED, char *buf, size_t size) {
5335
0
  snprintf(buf, size, "QPDB");
5336
0
}