Coverage Report

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