Coverage Report

Created: 2026-03-07 06:55

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