Coverage Report

Created: 2025-11-24 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/qpcache.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
20
#include <isc/ascii.h>
21
#include <isc/async.h>
22
#include <isc/atomic.h>
23
#include <isc/file.h>
24
#include <isc/heap.h>
25
#include <isc/hex.h>
26
#include <isc/log.h>
27
#include <isc/loop.h>
28
#include <isc/mem.h>
29
#include <isc/mutex.h>
30
#include <isc/os.h>
31
#include <isc/queue.h>
32
#include <isc/random.h>
33
#include <isc/refcount.h>
34
#include <isc/result.h>
35
#include <isc/rwlock.h>
36
#include <isc/sieve.h>
37
#include <isc/stdio.h>
38
#include <isc/string.h>
39
#include <isc/time.h>
40
#include <isc/urcu.h>
41
#include <isc/util.h>
42
43
#include <dns/callbacks.h>
44
#include <dns/db.h>
45
#include <dns/dbiterator.h>
46
#include <dns/fixedname.h>
47
#include <dns/masterdump.h>
48
#include <dns/nsec.h>
49
#include <dns/qp.h>
50
#include <dns/rdata.h>
51
#include <dns/rdataset.h>
52
#include <dns/rdatasetiter.h>
53
#include <dns/rdataslab.h>
54
#include <dns/rdatastruct.h>
55
#include <dns/rdatatype.h>
56
#include <dns/stats.h>
57
#include <dns/time.h>
58
#include <dns/types.h>
59
#include <dns/view.h>
60
61
#include "db_p.h"
62
#include "qpcache_p.h"
63
#include "rdataslab_p.h"
64
65
#ifndef DNS_QPCACHE_LOG_STATS_LEVEL
66
#define DNS_QPCACHE_LOG_STATS_LEVEL 3
67
#endif
68
69
#define CHECK(op)                            \
70
  do {                                 \
71
    result = (op);               \
72
    if (result != ISC_R_SUCCESS) \
73
      goto failure;        \
74
  } while (0)
75
76
#define STALE_TTL(header, qpdb) \
77
0
  (NXDOMAIN(header) ? 0 : qpdb->common.serve_stale_ttl)
78
79
#define ACTIVE(header, now)            \
80
0
  (((header)->expire > (now)) || \
81
0
   ((header)->expire == (now) && ZEROTTL(header)))
82
83
#define EXPIREDOK(iterator) \
84
0
  (((iterator)->common.options & DNS_DB_EXPIREDOK) != 0)
85
86
0
#define STALEOK(iterator) (((iterator)->common.options & DNS_DB_STALEOK) != 0)
87
88
0
#define KEEPSTALE(qpdb) ((qpdb)->common.serve_stale_ttl > 0)
89
90
/*%
91
 * Note that "impmagic" is not the first four bytes of the struct, so
92
 * ISC_MAGIC_VALID cannot be used.
93
 */
94
0
#define QPDB_MAGIC ISC_MAGIC('Q', 'P', 'D', '4')
95
#define VALID_QPDB(qpdb) \
96
  ((qpdb) != NULL && (qpdb)->common.impmagic == QPDB_MAGIC)
97
98
0
#define HEADERNODE(h) ((qpcnode_t *)((h)->node))
99
100
/*
101
 * Allow clients with a virtual time of up to 10 seconds in the past to see
102
 * records that would have otherwise have expired.
103
 */
104
0
#define QPDB_VIRTUAL 10
105
106
/*
107
 * This defines the number of headers that we try to expire each time the
108
 * expire_ttl_headers() is run.  The number should be small enough, so the
109
 * TTL-based header expiration doesn't take too long, but it should be large
110
 * enough, so we expire enough headers if their TTL is clustered.
111
 */
112
0
#define DNS_QPDB_EXPIRE_TTL_COUNT 10
113
114
/*%
115
 * Forward declarations
116
 */
117
typedef struct qpcache qpcache_t;
118
119
/*%
120
 * This is the structure that is used for each node in the qp trie of
121
 * trees.
122
 */
123
typedef struct qpcnode qpcnode_t;
124
struct qpcnode {
125
  DBNODE_FIELDS;
126
127
  qpcache_t *qpdb;
128
129
  uint8_t     : 0;
130
  unsigned int delegating : 1;
131
  unsigned int nspace : 2; /*%< range is 0..3 */
132
  unsigned int havensec : 1;
133
  uint8_t     : 0;
134
135
  /*
136
   * 'erefs' counts external references held by a caller: for
137
   * example, it could be incremented by dns_db_findnode(),
138
   * and decremented by dns_db_detachnode().
139
   *
140
   * 'references' counts internal references to the node object,
141
   * including the one held by the QP trie so the node won't be
142
   * deleted while it's quiescently stored in the database - even
143
   * though 'erefs' may be zero because no external caller is
144
   * using it at the time.
145
   *
146
   * Generally when 'erefs' is incremented or decremented,
147
   * 'references' is too. When both go to zero (meaning callers
148
   * and the database have both released the object) the object
149
   * is freed.
150
   *
151
   * Whenever 'erefs' is incremented from zero, we also aquire a
152
   * node use reference (see 'qpcache->references' below), and
153
   * release it when 'erefs' goes back to zero. This prevents the
154
   * database from being shut down until every caller has released
155
   * all nodes.
156
   */
157
  isc_refcount_t references;
158
  isc_refcount_t erefs;
159
160
  struct cds_list_head types_list;
161
  struct cds_list_head *data;
162
163
  /*%
164
   * NOTE: The 'dirty' flag is protected by the node lock, so
165
   * this bitfield has to be separated from the one above.
166
   * We don't want it to share the same qword with bits
167
   * that can be accessed without the node lock.
168
   */
169
  uint8_t       : 0;
170
  uint8_t dirty : 1;
171
  uint8_t       : 0;
172
173
  /*%
174
   * Used for dead nodes cleaning.  This linked list is used to mark nodes
175
   * which have no data any longer, but we cannot unlink at that exact
176
   * moment because we did not or could not obtain a write lock on the
177
   * tree.
178
   */
179
  isc_queue_node_t deadlink;
180
};
181
182
/*%
183
 * One bucket structure will be created for each loop, and
184
 * nodes in the database will evenly distributed among buckets
185
 * to reduce contention between threads.
186
 */
187
typedef struct qpcache_bucket {
188
  /*%
189
   * Temporary storage for stale cache nodes and dynamically
190
   * deleted nodes that await being cleaned up.
191
   */
192
  isc_queue_t deadnodes;
193
194
  /* Per-bucket lock. */
195
  isc_rwlock_t lock;
196
197
  /*
198
   * The heap is used for TTL based expiry.  Note that qpcache->hmctx
199
   * is the memory context to use for heap memory; this differs from
200
   * the main database memory context, which is qpcache->common.mctx.
201
   */
202
  isc_heap_t *heap;
203
204
  /* SIEVE-LRU cache cleaning state. */
205
  ISC_SIEVE(dns_slabtop_t) sieve;
206
207
  /* Padding to prevent false sharing between locks. */
208
  uint8_t __padding[ISC_OS_CACHELINE_SIZE -
209
        (sizeof(isc_queue_t) + sizeof(isc_rwlock_t) +
210
         sizeof(isc_heap_t *) +
211
         sizeof(ISC_SIEVE(dns_slabtop_t))) %
212
          ISC_OS_CACHELINE_SIZE];
213
214
} qpcache_bucket_t;
215
216
struct qpcache {
217
  /* Unlocked. */
218
  dns_db_t common;
219
  /* Locks the data in this struct */
220
  isc_rwlock_t lock;
221
  /* Locks the tree structure (prevents nodes appearing/disappearing) */
222
  isc_rwlock_t tree_lock;
223
224
  /*
225
   * NOTE: 'references' is NOT the global reference counter for
226
   * the database object handled by dns_db_attach() and _detach();
227
   * that one is 'common.references'.
228
   *
229
   * Instead, 'references' counts the number of nodes being used by
230
   * at least one external caller. (It's called 'references' to
231
   * leverage the ISC_REFCOUNT_STATIC macros, but 'nodes_in_use'
232
   * might be a clearer name.)
233
   *
234
   * One additional reference to this counter is held by the database
235
   * object itself. When 'common.references' goes to zero, that
236
   * reference is released. When in turn 'references' goes to zero,
237
   * the database is shut down and freed.
238
   */
239
  isc_refcount_t references;
240
241
  dns_stats_t *rrsetstats;
242
  isc_stats_t *cachestats;
243
244
  uint32_t maxrrperset;  /* Maximum RRs per RRset */
245
  uint32_t maxtypepername; /* Maximum number of RR types per owner */
246
247
  /*
248
   * The time after a failed lookup, where stale answers from cache
249
   * may be used directly in a DNS response without attempting a
250
   * new iterative lookup.
251
   */
252
  uint32_t serve_stale_refresh;
253
254
  /* Locked by tree_lock. */
255
  dns_qp_t *tree;
256
257
  isc_mem_t *hmctx; /* Memory context for the heaps */
258
259
  size_t buckets_count;
260
  qpcache_bucket_t buckets[]; /* attribute((counted_by(buckets_count))) */
261
};
262
263
#ifdef DNS_DB_NODETRACE
264
#define qpcache_ref(ptr)   qpcache__ref(ptr, __func__, __FILE__, __LINE__)
265
#define qpcache_unref(ptr) qpcache__unref(ptr, __func__, __FILE__, __LINE__)
266
#define qpcache_attach(ptr, ptrp) \
267
  qpcache__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
268
#define qpcache_detach(ptrp) qpcache__detach(ptrp, __func__, __FILE__, __LINE__)
269
ISC_REFCOUNT_STATIC_TRACE_DECL(qpcache);
270
#else
271
ISC_REFCOUNT_STATIC_DECL(qpcache);
272
#endif
273
274
/*%
275
 * Search Context
276
 */
277
typedef struct {
278
  qpcache_t *qpdb;
279
  unsigned int options;
280
  dns_qpchain_t chain;
281
  dns_qpiter_t iter;
282
  bool need_cleanup;
283
  qpcnode_t *zonecut;
284
  dns_slabheader_t *zonecut_header;
285
  dns_slabheader_t *zonecut_sigheader;
286
  isc_stdtime_t now;
287
} qpc_search_t;
288
289
#ifdef DNS_DB_NODETRACE
290
#define qpcnode_ref(ptr)   qpcnode__ref(ptr, __func__, __FILE__, __LINE__)
291
#define qpcnode_unref(ptr) qpcnode__unref(ptr, __func__, __FILE__, __LINE__)
292
#define qpcnode_attach(ptr, ptrp) \
293
  qpcnode__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
294
#define qpcnode_detach(ptrp) qpcnode__detach(ptrp, __func__, __FILE__, __LINE__)
295
ISC_REFCOUNT_STATIC_TRACE_DECL(qpcnode);
296
#else
297
ISC_REFCOUNT_STATIC_DECL(qpcnode);
298
#endif
299
300
/*
301
 * Node methods forward declarations
302
 */
303
static void
304
qpcnode_attachnode(dns_dbnode_t *source, dns_dbnode_t **targetp DNS__DB_FLARG);
305
static void
306
qpcnode_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG);
307
static void
308
qpcnode_deletedata(dns_dbnode_t *node, void *data);
309
static void
310
qpcnode_expiredata(dns_dbnode_t *node, void *data);
311
312
static dns_dbnode_methods_t qpcnode_methods = (dns_dbnode_methods_t){
313
  .attachnode = qpcnode_attachnode,
314
  .detachnode = qpcnode_detachnode,
315
  .deletedata = qpcnode_deletedata,
316
  .expiredata = qpcnode_expiredata,
317
};
318
319
/* QP methods */
320
static void
321
qp_attach(void *uctx, void *pval, uint32_t ival);
322
static void
323
qp_detach(void *uctx, void *pval, uint32_t ival);
324
static size_t
325
qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
326
static void
327
qp_triename(void *uctx, char *buf, size_t size);
328
329
static dns_qpmethods_t qpmethods = {
330
  qp_attach,
331
  qp_detach,
332
  qp_makekey,
333
  qp_triename,
334
};
335
336
static void
337
qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
338
0
    uint32_t ival ISC_ATTR_UNUSED) {
339
0
  qpcnode_t *data = pval;
340
0
  qpcnode_ref(data);
341
0
}
342
343
static void
344
qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
345
0
    uint32_t ival ISC_ATTR_UNUSED) {
346
0
  qpcnode_t *data = pval;
347
0
  qpcnode_detach(&data);
348
0
}
349
350
static size_t
351
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
352
0
     uint32_t ival ISC_ATTR_UNUSED) {
353
0
  qpcnode_t *data = pval;
354
0
  return dns_qpkey_fromname(key, &data->name, data->nspace);
355
0
}
356
357
static void
358
0
qp_triename(void *uctx ISC_ATTR_UNUSED, char *buf, size_t size) {
359
0
  snprintf(buf, size, "qpdb-lite");
360
0
}
361
362
static void
363
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG);
364
static isc_result_t
365
rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG);
366
static isc_result_t
367
rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG);
368
static void
369
rdatasetiter_current(dns_rdatasetiter_t *iterator,
370
         dns_rdataset_t *rdataset DNS__DB_FLARG);
371
372
static dns_rdatasetitermethods_t rdatasetiter_methods = {
373
  rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next,
374
  rdatasetiter_current
375
};
376
377
typedef struct qpc_rditer {
378
  dns_rdatasetiter_t common;
379
  dns_slabtop_t *current;
380
} qpc_rditer_t;
381
382
static void
383
dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG);
384
static isc_result_t
385
dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG);
386
static isc_result_t
387
dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG);
388
static isc_result_t
389
dbiterator_seek(dns_dbiterator_t *iterator,
390
    const dns_name_t *name DNS__DB_FLARG);
391
static isc_result_t
392
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG);
393
static isc_result_t
394
dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG);
395
static isc_result_t
396
dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
397
       dns_name_t *name DNS__DB_FLARG);
398
static isc_result_t
399
dbiterator_pause(dns_dbiterator_t *iterator);
400
static isc_result_t
401
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
402
403
static dns_dbiteratormethods_t dbiterator_methods = {
404
  dbiterator_destroy, dbiterator_first, dbiterator_last,
405
  dbiterator_seek,    dbiterator_prev,  dbiterator_next,
406
  dbiterator_current, dbiterator_pause, dbiterator_origin
407
};
408
409
/*
410
 * In the cache, NSEC3 records are currently stored in the NORMAL
411
 * namespace.  If we ever implement synth-from-dnssec using NSEC3 records,
412
 * they'll need be moved into the NSEC3 namespace for efficiency, and
413
 * the iterator implementation will need to be more complex, as in
414
 * qpzone.
415
 */
416
typedef struct qpc_dbit {
417
  dns_dbiterator_t common;
418
  bool paused;
419
  isc_rwlocktype_t tree_locked;
420
  isc_result_t result;
421
  dns_fixedname_t fixed;
422
  dns_name_t *name;
423
  dns_qpiter_t iter;
424
  qpcnode_t *node;
425
} qpc_dbit_t;
426
427
static void
428
qpcache__destroy(qpcache_t *qpdb);
429
430
static dns_dbmethods_t qpdb_cachemethods;
431
432
static void
433
cleanup_deadnodes_cb(void *arg);
434
435
/*
436
 * Locking
437
 *
438
 * If a routine is going to lock more than one lock in this module, then
439
 * the locking must be done in the following order:
440
 *
441
 *      Tree Lock
442
 *
443
 *      Node Lock       (Only one from the set may be locked at one time by
444
 *                       any caller)
445
 *
446
 *      Database Lock
447
 *
448
 * Failure to follow this hierarchy can result in deadlock.
449
 */
450
451
/*
452
 * Cache-eviction routines.
453
 */
454
455
static size_t
456
expireheader(dns_slabheader_t *header, isc_rwlocktype_t *nlocktypep,
457
       isc_rwlocktype_t *tlocktypep, dns_expire_t reason DNS__DB_FLARG);
458
459
static size_t
460
0
rdataset_size(dns_slabheader_t *header) {
461
0
  if (EXISTS(header)) {
462
0
    return dns_rdataslab_size(header);
463
0
  }
464
465
0
  return sizeof(*header);
466
0
}
467
468
static dns_slabheader_t *
469
0
first_header(dns_slabtop_t *top) {
470
0
  dns_slabheader_t *header = NULL;
471
0
  cds_list_for_each_entry(header, &top->headers, headers_link) {
472
0
    return header;
473
0
  }
474
0
  return NULL;
475
0
}
476
477
static dns_slabheader_t *
478
0
next_header(dns_slabheader_t *header) {
479
0
  return cds_list_entry((header)->headers_link.next, dns_slabheader_t,
480
0
            headers_link);
481
0
}
482
483
static dns_slabheader_t *
484
0
first_existing_header(dns_slabtop_t *top) {
485
0
  dns_slabheader_t *header = first_header(top);
486
0
  if (EXISTS(header)) {
487
0
    return header;
488
0
  }
489
0
  return NULL;
490
0
}
491
492
static void
493
expire_lru_headers(qpcache_t *qpdb, uint32_t idx, size_t requested,
494
       isc_rwlocktype_t *nlocktypep,
495
0
       isc_rwlocktype_t *tlocktypep DNS__DB_FLARG) {
496
0
  size_t expired = 0;
497
498
0
  do {
499
0
    dns_slabtop_t *top = ISC_SIEVE_NEXT(qpdb->buckets[idx].sieve,
500
0
                visited, link);
501
0
    if (top == NULL) {
502
0
      return;
503
0
    }
504
505
0
    dns_slabtop_t *related = top->related;
506
507
0
    if (ISC_SIEVE_LINKED(top, link)) {
508
0
      ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, top, link);
509
0
    }
510
511
0
    dns_slabheader_t *header = first_header(top);
512
0
    expired += expireheader(header, nlocktypep, tlocktypep,
513
0
          dns_expire_lru DNS__DB_FLARG_PASS);
514
515
0
    if (related != NULL) {
516
0
      header = first_header(related);
517
518
0
      expired +=
519
0
        expireheader(header, nlocktypep, tlocktypep,
520
0
               dns_expire_lru DNS__DB_FLARG_PASS);
521
0
    }
522
523
0
  } while (expired < requested);
524
0
}
525
526
static void
527
qpcache_miss(qpcache_t *qpdb, dns_slabheader_t *newheader,
528
       isc_rwlocktype_t *nlocktypep,
529
0
       isc_rwlocktype_t *tlocktypep DNS__DB_FLARG) {
530
0
  uint32_t idx = HEADERNODE(newheader)->locknum;
531
532
0
  isc_heap_insert(qpdb->buckets[idx].heap, newheader);
533
0
  newheader->heap = qpdb->buckets[idx].heap;
534
535
0
  if (isc_mem_isovermem(qpdb->common.mctx)) {
536
    /*
537
     * Maximum estimated size of the data being added: The size
538
     * of the rdataset, plus a new QP database node and nodename,
539
     * and a possible additional NSEC node and nodename. Also add
540
     * a 12k margin for a possible QP-trie chunk allocation.
541
     * (It's okay to overestimate, we want to get cache memory
542
     * down quickly.)
543
     */
544
545
0
    size_t purgesize =
546
0
      2 * (sizeof(qpcnode_t) +
547
0
           dns_name_size(&HEADERNODE(newheader)->name)) +
548
0
      rdataset_size(newheader) + QP_SAFETY_MARGIN;
549
550
0
    expire_lru_headers(qpdb, idx, purgesize, nlocktypep,
551
0
           tlocktypep DNS__DB_FLARG_PASS);
552
0
  }
553
554
0
  ISC_SIEVE_INSERT(qpdb->buckets[idx].sieve, newheader->top, link);
555
0
}
556
557
static void
558
0
qpcache_hit(qpcache_t *qpdb ISC_ATTR_UNUSED, dns_slabheader_t *header) {
559
  /*
560
   * On cache hit, we only mark the header as seen.
561
   */
562
0
  ISC_SIEVE_MARK(header->top, visited);
563
0
}
564
565
/*
566
 * DB Routines
567
 */
568
569
static void
570
0
clean_cache_headers(dns_slabtop_t *top) {
571
0
  dns_slabheader_t *parent = first_header(top);
572
0
  if (parent == NULL) {
573
0
    return;
574
0
  }
575
576
0
  dns_slabheader_t *header = next_header(parent), *header_next = NULL;
577
0
  cds_list_for_each_entry_safe_from(header, header_next, &top->headers,
578
0
            headers_link) {
579
0
    cds_list_del(&header->headers_link);
580
0
    dns_slabheader_destroy(&header);
581
0
  }
582
0
}
583
584
static void
585
0
clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
586
  /*
587
   * Caller must be holding the node lock.
588
   */
589
590
0
  DNS_SLABTOP_FOREACH(top, node->data) {
591
0
    clean_cache_headers(top);
592
593
    /*
594
     * If current top header is nonexistent, ancient, or stale
595
     * and we are not keeping stale, we can clean it up too.
596
     */
597
0
    dns_slabheader_t *header = first_header(top);
598
0
    if (header == NULL) {
599
0
      continue;
600
0
    }
601
602
0
    if (!EXISTS(header) || ANCIENT(header) ||
603
0
        (STALE(header) && !KEEPSTALE(qpdb)))
604
0
    {
605
0
      cds_list_del(&header->headers_link);
606
0
      dns_slabheader_destroy(&header);
607
0
    }
608
609
    /*
610
     * If current slabtop is empty, we can clean it up.
611
     */
612
0
    if (header == NULL) {
613
0
      if (top->related != NULL) {
614
0
        top->related->related = NULL;
615
0
        top->related = NULL;
616
0
      }
617
618
0
      cds_list_del(&top->types_link);
619
620
0
      if (ISC_SIEVE_LINKED(top, link)) {
621
0
        ISC_SIEVE_UNLINK(
622
0
          qpdb->buckets[node->locknum].sieve, top,
623
0
          link);
624
0
      }
625
0
      dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top);
626
0
    }
627
0
  }
628
629
0
  node->dirty = false;
630
0
}
631
632
/*
633
 * tree_lock(write) must be held.
634
 */
635
static void
636
0
delete_node(qpcache_t *qpdb, qpcnode_t *node) {
637
0
  isc_result_t result = ISC_R_UNEXPECTED;
638
639
0
  if (isc_log_wouldlog(ISC_LOG_DEBUG(DNS_QPCACHE_LOG_STATS_LEVEL))) {
640
0
    char printname[DNS_NAME_FORMATSIZE];
641
0
    dns_name_format(&node->name, printname, sizeof(printname));
642
0
    isc_log_write(DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
643
0
            ISC_LOG_DEBUG(DNS_QPCACHE_LOG_STATS_LEVEL),
644
0
            "delete_node(): %p %s (bucket %d)", node,
645
0
            printname, node->locknum);
646
0
  }
647
648
0
  switch (node->nspace) {
649
0
  case DNS_DBNAMESPACE_NORMAL:
650
0
    if (node->havensec) {
651
      /*
652
       * Delete the corresponding node from the auxiliary NSEC
653
       * tree before deleting from the main tree.
654
       */
655
0
      result = dns_qp_deletename(qpdb->tree, &node->name,
656
0
               DNS_DBNAMESPACE_NSEC, NULL,
657
0
               NULL);
658
0
      if (result != ISC_R_SUCCESS) {
659
0
        isc_log_write(DNS_LOGCATEGORY_DATABASE,
660
0
                DNS_LOGMODULE_CACHE,
661
0
                ISC_LOG_WARNING,
662
0
                "delete_node(): "
663
0
                "dns_qp_deletename: %s",
664
0
                isc_result_totext(result));
665
0
      }
666
0
    }
667
0
    result = dns_qp_deletename(qpdb->tree, &node->name,
668
0
             node->nspace, NULL, NULL);
669
0
    break;
670
0
  case DNS_DBNAMESPACE_NSEC:
671
0
    result = dns_qp_deletename(qpdb->tree, &node->name,
672
0
             node->nspace, NULL, NULL);
673
0
    break;
674
0
  }
675
0
  if (result != ISC_R_SUCCESS) {
676
0
    isc_log_write(DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
677
0
            ISC_LOG_WARNING,
678
0
            "delete_node(): "
679
0
            "dns_qp_deletename: %s",
680
0
            isc_result_totext(result));
681
0
  }
682
0
}
683
684
/*
685
 * The caller must specify its currect node and tree lock status.
686
 * It's okay for neither lock to be held if there are existing external
687
 * references to the node, but if this is the first external reference,
688
 * then the caller must be holding at least one lock.
689
 *
690
 * If incrementing erefs from zero, we also increment the node use counter
691
 * in the qpcache object.
692
 *
693
 * This function is called from qpcnode_acquire(), so that internal
694
 * and external references are acquired at the same time, and from
695
 * qpcnode_release() when we only need to increase the internal references.
696
 */
697
static void
698
qpcnode_erefs_increment(qpcache_t *qpdb, qpcnode_t *node,
699
      isc_rwlocktype_t nlocktype,
700
0
      isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
701
0
  uint_fast32_t refs = isc_refcount_increment0(&node->erefs);
702
703
#if DNS_DB_NODETRACE
704
  fprintf(stderr, "incr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
705
    func, file, line, node, refs + 1);
706
#endif
707
708
0
  if (refs > 0) {
709
0
    return;
710
0
  }
711
712
  /*
713
   * this is the first external reference to the node.
714
   *
715
   * we need to hold the node or tree lock to avoid
716
   * incrementing the reference count while also deleting
717
   * the node. delete_node() is always protected by both
718
   * tree and node locks being write-locked.
719
   */
720
0
  INSIST(nlocktype != isc_rwlocktype_none ||
721
0
         tlocktype != isc_rwlocktype_none);
722
723
0
  qpcache_ref(qpdb);
724
0
}
725
726
static void
727
qpcnode_acquire(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t nlocktype,
728
0
    isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
729
0
  qpcnode_ref(node);
730
0
  qpcnode_erefs_increment(qpdb, node, nlocktype,
731
0
        tlocktype DNS__DB_FLARG_PASS);
732
0
}
733
734
/*
735
 * Decrement the external references to a node. If the counter
736
 * goes to zero, decrement the node use counter in the qpcache object
737
 * as well, and return true. Otherwise return false.
738
 */
739
static bool
740
0
qpcnode_erefs_decrement(qpcache_t *qpdb, qpcnode_t *node DNS__DB_FLARG) {
741
0
  uint_fast32_t refs = isc_refcount_decrement(&node->erefs);
742
743
#if DNS_DB_NODETRACE
744
  fprintf(stderr, "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
745
    func, file, line, node, refs - 1);
746
#endif
747
0
  if (refs > 1) {
748
0
    return false;
749
0
  }
750
751
0
  qpcache_unref(qpdb);
752
0
  return true;
753
0
}
754
755
/*
756
 * Caller must be holding a node lock, either read or write.
757
 *
758
 * Note that the lock must be held even when node references are
759
 * atomically modified; in that case the decrement operation itself does not
760
 * have to be protected, but we must avoid a race condition where multiple
761
 * threads are decreasing the reference to zero simultaneously and at least
762
 * one of them is going to free the node.
763
 *
764
 * This calls dec_erefs() to decrement the external node reference counter,
765
 * (and possibly the node use counter), cleans up and deletes the node
766
 * if necessary, then decrements the internal reference counter as well.
767
 */
768
static void
769
qpcnode_release(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep,
770
0
    isc_rwlocktype_t *tlocktypep DNS__DB_FLARG) {
771
0
  REQUIRE(*nlocktypep != isc_rwlocktype_none);
772
773
0
  if (!qpcnode_erefs_decrement(qpdb, node DNS__DB_FLARG_PASS)) {
774
0
    goto unref;
775
0
  }
776
777
  /* Handle easy and typical case first. */
778
0
  if (!node->dirty && !cds_list_empty(node->data)) {
779
0
    goto unref;
780
0
  }
781
782
0
  if (*nlocktypep == isc_rwlocktype_read) {
783
    /*
784
     * The external reference count went to zero and the node
785
     * is dirty or has no data, so we might want to delete it.
786
     * To do that, we'll need a write lock. If we don't already
787
     * have one, we have to make sure nobody else has
788
     * acquired a reference in the meantime, so we increment
789
     * erefs (but NOT references!), upgrade the node lock,
790
     * decrement erefs again, and see if it's still zero.
791
     *
792
     * We can't really assume anything about the result code of
793
     * erefs_increment.  If another thread acquires reference it
794
     * will be larger than 0, if it doesn't it is going to be 0.
795
     */
796
0
    isc_rwlock_t *nlock = &qpdb->buckets[node->locknum].lock;
797
0
    qpcnode_erefs_increment(qpdb, node, *nlocktypep,
798
0
          *tlocktypep DNS__DB_FLARG_PASS);
799
0
    NODE_FORCEUPGRADE(nlock, nlocktypep);
800
0
    if (!qpcnode_erefs_decrement(qpdb, node DNS__DB_FLARG_PASS)) {
801
0
      goto unref;
802
0
    }
803
0
  }
804
805
0
  if (node->dirty) {
806
0
    clean_cache_node(qpdb, node);
807
0
  }
808
809
0
  if (!cds_list_empty(node->data)) {
810
0
    goto unref;
811
0
  }
812
813
0
  if (*tlocktypep == isc_rwlocktype_write) {
814
    /*
815
     * We can delete the node if we have the tree write lock.
816
     */
817
0
    delete_node(qpdb, node);
818
0
  } else {
819
    /*
820
     * If we don't have the tree lock, we will add this node to a
821
     * linked list of nodes in this locking bucket which we will
822
     * free later.
823
     */
824
0
    qpcnode_acquire(qpdb, node, *nlocktypep,
825
0
        *tlocktypep DNS__DB_FLARG_PASS);
826
827
0
    isc_queue_node_init(&node->deadlink);
828
0
    if (!isc_queue_enqueue_entry(
829
0
          &qpdb->buckets[node->locknum].deadnodes, node,
830
0
          deadlink))
831
0
    {
832
      /* Queue was empty, trigger new cleaning */
833
0
      isc_loop_t *loop = isc_loop_get(node->locknum);
834
835
0
      qpcache_ref(qpdb);
836
0
      isc_async_run(loop, cleanup_deadnodes_cb, qpdb);
837
0
    }
838
0
  }
839
840
0
unref:
841
0
  qpcnode_unref(node);
842
0
}
843
844
static void
845
update_rrsetstats(dns_stats_t *stats, const dns_typepair_t typepair,
846
0
      const uint_least16_t hattributes, const bool increment) {
847
0
  dns_rdatastatstype_t statattributes = 0;
848
0
  dns_rdatastatstype_t base = 0;
849
0
  dns_rdatastatstype_t type;
850
0
  dns_slabheader_t *header = &(dns_slabheader_t){
851
0
    .typepair = typepair,
852
0
    .attributes = hattributes,
853
0
  };
854
855
0
  if (!EXISTS(header) || !STATCOUNT(header)) {
856
0
    return;
857
0
  }
858
859
0
  if (NEGATIVE(header)) {
860
0
    if (NXDOMAIN(header)) {
861
0
      statattributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN;
862
0
    } else {
863
0
      statattributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
864
0
      base = DNS_TYPEPAIR_TYPE(header->typepair);
865
0
    }
866
0
  } else {
867
0
    base = DNS_TYPEPAIR_TYPE(header->typepair);
868
0
  }
869
870
0
  if (STALE(header)) {
871
0
    statattributes |= DNS_RDATASTATSTYPE_ATTR_STALE;
872
0
  }
873
0
  if (ANCIENT(header)) {
874
0
    statattributes |= DNS_RDATASTATSTYPE_ATTR_ANCIENT;
875
0
  }
876
877
0
  type = DNS_RDATASTATSTYPE_VALUE(base, statattributes);
878
0
  if (increment) {
879
0
    dns_rdatasetstats_increment(stats, type);
880
0
  } else {
881
0
    dns_rdatasetstats_decrement(stats, type);
882
0
  }
883
0
}
884
885
static void
886
0
mark(dns_slabheader_t *header, uint_least16_t flag) {
887
0
  uint_least16_t attributes = atomic_load_acquire(&header->attributes);
888
0
  uint_least16_t newattributes = 0;
889
0
  qpcache_t *qpdb = HEADERNODE(header)->qpdb;
890
891
  /*
892
   * If we are already ancient there is nothing to do.
893
   */
894
0
  do {
895
0
    if ((attributes & flag) != 0) {
896
0
      return;
897
0
    }
898
0
    newattributes = attributes | flag;
899
0
  } while (!atomic_compare_exchange_weak_acq_rel(
900
0
    &header->attributes, &attributes, newattributes));
901
902
  /*
903
   * Decrement and increment the stats counter for the appropriate
904
   * RRtype.
905
   */
906
0
  update_rrsetstats(qpdb->rrsetstats, header->typepair, attributes,
907
0
        false);
908
0
  update_rrsetstats(qpdb->rrsetstats, header->typepair, newattributes,
909
0
        true);
910
0
}
911
912
static void
913
0
setttl(dns_slabheader_t *header, isc_stdtime_t newts) {
914
0
  isc_stdtime_t oldts = header->expire;
915
916
0
  header->expire = newts;
917
918
0
  if (header->heap == NULL || header->heap_index == 0 || newts == oldts) {
919
0
    return;
920
0
  }
921
922
0
  if (newts < oldts) {
923
0
    isc_heap_increased(header->heap, header->heap_index);
924
0
  } else {
925
0
    isc_heap_decreased(header->heap, header->heap_index);
926
0
  }
927
928
0
  if (newts == 0) {
929
0
    isc_heap_delete(header->heap, header->heap_index);
930
0
  }
931
0
}
932
933
static void
934
0
mark_ancient(dns_slabheader_t *header) {
935
0
  setttl(header, 0);
936
0
  mark(header, DNS_SLABHEADERATTR_ANCIENT);
937
0
  HEADERNODE(header)->dirty = 1;
938
0
}
939
940
/*
941
 * Caller must hold the node (write) lock.
942
 */
943
static size_t
944
expireheader(dns_slabheader_t *header, isc_rwlocktype_t *nlocktypep,
945
0
       isc_rwlocktype_t *tlocktypep, dns_expire_t reason DNS__DB_FLARG) {
946
0
  size_t expired = rdataset_size(header);
947
948
0
  mark_ancient(header);
949
950
0
  if (isc_refcount_current(&HEADERNODE(header)->erefs) == 0) {
951
0
    qpcache_t *qpdb = HEADERNODE(header)->qpdb;
952
953
    /*
954
     * If no one else is using the node, we can clean it up now.
955
     * We first need to gain a new reference to the node to meet a
956
     * requirement of qpcnode_release().
957
     */
958
0
    qpcnode_acquire(qpdb, HEADERNODE(header), *nlocktypep,
959
0
        *tlocktypep DNS__DB_FLARG_PASS);
960
0
    qpcnode_release(qpdb, HEADERNODE(header), nlocktypep,
961
0
        tlocktypep DNS__DB_FLARG_PASS);
962
963
0
    if (qpdb->cachestats == NULL) {
964
0
      return expired;
965
0
    }
966
967
0
    switch (reason) {
968
0
    case dns_expire_ttl:
969
0
      isc_stats_increment(qpdb->cachestats,
970
0
              dns_cachestatscounter_deletettl);
971
0
      break;
972
0
    case dns_expire_lru:
973
0
      isc_stats_increment(qpdb->cachestats,
974
0
              dns_cachestatscounter_deletelru);
975
0
      break;
976
0
    default:
977
0
      break;
978
0
    }
979
0
  }
980
981
0
  return expired;
982
0
}
983
984
static void
985
0
update_cachestats(qpcache_t *qpdb, isc_result_t result) {
986
0
  if (qpdb->cachestats == NULL) {
987
0
    return;
988
0
  }
989
990
0
  switch (result) {
991
0
  case DNS_R_COVERINGNSEC:
992
0
    isc_stats_increment(qpdb->cachestats,
993
0
            dns_cachestatscounter_coveringnsec);
994
0
    FALLTHROUGH;
995
0
  case ISC_R_SUCCESS:
996
0
  case DNS_R_CNAME:
997
0
  case DNS_R_DNAME:
998
0
  case DNS_R_DELEGATION:
999
0
  case DNS_R_NCACHENXDOMAIN:
1000
0
  case DNS_R_NCACHENXRRSET:
1001
0
    isc_stats_increment(qpdb->cachestats,
1002
0
            dns_cachestatscounter_hits);
1003
0
    break;
1004
0
  default:
1005
0
    isc_stats_increment(qpdb->cachestats,
1006
0
            dns_cachestatscounter_misses);
1007
0
  }
1008
0
}
1009
1010
static void
1011
bindrdataset(qpcache_t *qpdb, qpcnode_t *node, dns_slabheader_t *header,
1012
       isc_stdtime_t now, isc_rwlocktype_t nlocktype,
1013
       isc_rwlocktype_t tlocktype,
1014
0
       dns_rdataset_t *rdataset DNS__DB_FLARG) {
1015
0
  bool stale = STALE(header);
1016
0
  bool ancient = ANCIENT(header);
1017
1018
  /*
1019
   * Caller must be holding the node reader lock.
1020
   * XXXJT: technically, we need a writer lock, since we'll increment
1021
   * the header count below.  However, since the actual counter value
1022
   * doesn't matter, we prioritize performance here.  (We may want to
1023
   * use atomic increment when available).
1024
   */
1025
1026
0
  if (rdataset == NULL) {
1027
0
    return;
1028
0
  }
1029
1030
0
  qpcnode_acquire(qpdb, node, nlocktype, tlocktype DNS__DB_FLARG_PASS);
1031
1032
0
  INSIST(rdataset->methods == NULL); /* We must be disassociated. */
1033
1034
  /*
1035
   * Mark header stale or ancient if the RRset is no longer active.
1036
   */
1037
0
  if (!ACTIVE(header, now)) {
1038
0
    dns_ttl_t stale_ttl = header->expire + STALE_TTL(header, qpdb);
1039
    /*
1040
     * If this data is in the stale window keep it and if
1041
     * DNS_DBFIND_STALEOK is not set we tell the caller to
1042
     * skip this record.  We skip the records with ZEROTTL
1043
     * (these records should not be cached anyway).
1044
     */
1045
1046
0
    if (!ZEROTTL(header) && KEEPSTALE(qpdb) && stale_ttl > now) {
1047
0
      stale = true;
1048
0
    } else {
1049
      /*
1050
       * We are not keeping stale, or it is outside the
1051
       * stale window. Mark ancient, i.e. ready for cleanup.
1052
       */
1053
0
      ancient = true;
1054
0
    }
1055
0
  }
1056
1057
0
  rdataset->methods = &dns_rdataslab_rdatasetmethods;
1058
0
  rdataset->rdclass = qpdb->common.rdclass;
1059
0
  if (NEGATIVE(header)) {
1060
0
    rdataset->type = dns_rdatatype_none;
1061
0
    rdataset->covers = DNS_TYPEPAIR_TYPE(header->typepair);
1062
0
    INSIST(DNS_TYPEPAIR_COVERS(header->typepair) ==
1063
0
           dns_rdatatype_none);
1064
0
  } else {
1065
0
    rdataset->type = DNS_TYPEPAIR_TYPE(header->typepair);
1066
0
    rdataset->covers = DNS_TYPEPAIR_COVERS(header->typepair);
1067
0
  }
1068
0
  rdataset->ttl = !ZEROTTL(header) ? header->expire - now : 0;
1069
0
  rdataset->trust = atomic_load(&header->trust);
1070
0
  rdataset->resign = 0;
1071
1072
0
  if (NEGATIVE(header)) {
1073
0
    rdataset->attributes.negative = true;
1074
0
  }
1075
0
  if (NXDOMAIN(header)) {
1076
0
    rdataset->attributes.nxdomain = true;
1077
0
  }
1078
0
  if (OPTOUT(header)) {
1079
0
    rdataset->attributes.optout = true;
1080
0
  }
1081
0
  if (PREFETCH(header)) {
1082
0
    rdataset->attributes.prefetch = true;
1083
0
  }
1084
1085
0
  if (stale && !ancient) {
1086
0
    dns_ttl_t stale_ttl = header->expire + STALE_TTL(header, qpdb);
1087
0
    if (stale_ttl > now) {
1088
0
      rdataset->ttl = stale_ttl - now;
1089
0
    } else {
1090
0
      rdataset->ttl = 0;
1091
0
    }
1092
0
    if (STALE_WINDOW(header)) {
1093
0
      rdataset->attributes.stale_window = true;
1094
0
    }
1095
0
    rdataset->attributes.stale = true;
1096
0
    rdataset->expire = header->expire;
1097
0
  } else if (!ACTIVE(header, now)) {
1098
0
    rdataset->attributes.ancient = true;
1099
0
    rdataset->ttl = 0;
1100
0
  }
1101
1102
0
  rdataset->slab.db = (dns_db_t *)qpdb;
1103
0
  rdataset->slab.node = (dns_dbnode_t *)node;
1104
0
  rdataset->slab.raw = header->raw;
1105
0
  rdataset->slab.iter_pos = NULL;
1106
0
  rdataset->slab.iter_count = 0;
1107
1108
  /*
1109
   * Add noqname proof.
1110
   */
1111
0
  rdataset->slab.noqname = header->noqname;
1112
0
  if (header->noqname != NULL) {
1113
0
    rdataset->attributes.noqname = true;
1114
0
  }
1115
0
  rdataset->slab.closest = header->closest;
1116
0
  if (header->closest != NULL) {
1117
0
    rdataset->attributes.closest = true;
1118
0
  }
1119
0
}
1120
1121
static void
1122
bindrdatasets(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *found,
1123
        dns_slabheader_t *foundsig, isc_stdtime_t now,
1124
        isc_rwlocktype_t nlocktype, isc_rwlocktype_t tlocktype,
1125
        dns_rdataset_t *rdataset,
1126
0
        dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
1127
0
  bindrdataset(qpdb, qpnode, found, now, nlocktype, tlocktype,
1128
0
         rdataset DNS__DB_FLARG_PASS);
1129
0
  qpcache_hit(qpdb, found);
1130
0
  if (!NEGATIVE(found) && foundsig != NULL) {
1131
0
    bindrdataset(qpdb, qpnode, foundsig, now, nlocktype, tlocktype,
1132
0
           sigrdataset DNS__DB_FLARG_PASS);
1133
0
    qpcache_hit(qpdb, foundsig);
1134
0
  }
1135
0
}
1136
1137
static isc_result_t
1138
setup_delegation(qpc_search_t *search, dns_dbnode_t **nodep,
1139
     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1140
0
     isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
1141
0
  dns_typepair_t typepair;
1142
0
  qpcnode_t *node = NULL;
1143
1144
0
  REQUIRE(search != NULL);
1145
0
  REQUIRE(search->zonecut != NULL);
1146
0
  REQUIRE(search->zonecut_header != NULL);
1147
1148
  /*
1149
   * The caller MUST NOT be holding any node locks.
1150
   */
1151
1152
0
  node = search->zonecut;
1153
0
  typepair = search->zonecut_header->typepair;
1154
1155
0
  if (nodep != NULL) {
1156
    /*
1157
     * Note that we don't have to increment the node's reference
1158
     * count here because we're going to use the reference we
1159
     * already have in the search block.
1160
     */
1161
0
    *nodep = (dns_dbnode_t *)node;
1162
0
    search->need_cleanup = false;
1163
0
  }
1164
0
  if (rdataset != NULL) {
1165
0
    isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1166
0
    isc_rwlock_t *nlock =
1167
0
      &search->qpdb->buckets[node->locknum].lock;
1168
0
    NODE_RDLOCK(nlock, &nlocktype);
1169
0
    bindrdatasets(search->qpdb, node, search->zonecut_header,
1170
0
            search->zonecut_sigheader, search->now, nlocktype,
1171
0
            tlocktype, rdataset,
1172
0
            sigrdataset DNS__DB_FLARG_PASS);
1173
0
    NODE_UNLOCK(nlock, &nlocktype);
1174
0
  }
1175
1176
0
  if (typepair == DNS_TYPEPAIR_VALUE(dns_rdatatype_dname, 0)) {
1177
0
    return DNS_R_DNAME;
1178
0
  }
1179
0
  return DNS_R_DELEGATION;
1180
0
}
1181
1182
static bool
1183
0
check_stale_header(dns_slabheader_t *header, qpc_search_t *search) {
1184
0
  if (ACTIVE(header, search->now)) {
1185
0
    return false;
1186
0
  }
1187
1188
0
  isc_stdtime_t stale = header->expire + STALE_TTL(header, search->qpdb);
1189
  /*
1190
   * If this data is in the stale window keep it and if
1191
   * DNS_DBFIND_STALEOK is not set we tell the caller to
1192
   * skip this record.  We skip the records with ZEROTTL
1193
   * (these records should not be cached anyway).
1194
   */
1195
1196
0
  DNS_SLABHEADER_CLRATTR(header, DNS_SLABHEADERATTR_STALE_WINDOW);
1197
0
  if (!ZEROTTL(header) && KEEPSTALE(search->qpdb) && stale > search->now)
1198
0
  {
1199
0
    mark(header, DNS_SLABHEADERATTR_STALE);
1200
    /*
1201
     * If DNS_DBFIND_STALESTART is set then it means we
1202
     * failed to resolve the name during recursion, in
1203
     * this case we mark the time in which the refresh
1204
     * failed.
1205
     */
1206
0
    if ((search->options & DNS_DBFIND_STALESTART) != 0) {
1207
0
      atomic_store_release(&header->last_refresh_fail_ts,
1208
0
               search->now);
1209
0
    } else if ((search->options & DNS_DBFIND_STALEENABLED) != 0 &&
1210
0
         search->now <
1211
0
           (atomic_load_acquire(
1212
0
              &header->last_refresh_fail_ts) +
1213
0
            search->qpdb->serve_stale_refresh))
1214
0
    {
1215
      /*
1216
       * If we are within interval between last
1217
       * refresh failure time + 'stale-refresh-time',
1218
       * then don't skip this stale entry but use it
1219
       * instead.
1220
       */
1221
0
      DNS_SLABHEADER_SETATTR(header,
1222
0
                 DNS_SLABHEADERATTR_STALE_WINDOW);
1223
0
      return false;
1224
0
    } else if ((search->options & DNS_DBFIND_STALETIMEOUT) != 0) {
1225
      /*
1226
       * We want stale RRset due to timeout, so we
1227
       * don't skip it.
1228
       */
1229
0
      return false;
1230
0
    }
1231
0
    return (search->options & DNS_DBFIND_STALEOK) == 0;
1232
0
  }
1233
1234
0
  return true;
1235
0
}
1236
1237
static bool
1238
0
check_header(dns_slabheader_t *header, qpc_search_t *search) {
1239
0
  return header == NULL || check_stale_header(header, search) ||
1240
0
         !EXISTS(header) || ANCIENT(header);
1241
0
}
1242
1243
/*
1244
 * Return true if we've found headers for both 'type' and RRSIG('type'),
1245
 * or (optionally, if 'negtype' is nonzero) if we've found a single
1246
 * negative header covering either 'negtype' or ANY.
1247
 */
1248
static bool
1249
related_headers(dns_slabheader_t *header, dns_slabheader_t *sigheader,
1250
    dns_typepair_t typepair, dns_slabheader_t **foundp,
1251
0
    dns_slabheader_t **foundsigp) {
1252
0
  if (header != NULL) {
1253
0
    REQUIRE(DNS_TYPEPAIR_TYPE(header->typepair) !=
1254
0
      dns_rdatatype_rrsig);
1255
0
    REQUIRE(DNS_TYPEPAIR_COVERS(header->typepair) ==
1256
0
      dns_rdatatype_none);
1257
0
  }
1258
0
  if (sigheader != NULL) {
1259
0
    REQUIRE(DNS_TYPEPAIR_TYPE(sigheader->typepair) ==
1260
0
      dns_rdatatype_rrsig);
1261
0
    REQUIRE(DNS_TYPEPAIR_COVERS(sigheader->typepair) !=
1262
0
        dns_rdatatype_none ||
1263
0
      NEGATIVE(sigheader));
1264
0
  }
1265
1266
  /*
1267
   * Nothing exists if there's a NEGATIVE(dns_typepair_any).
1268
   */
1269
0
  if (header != NULL && header->typepair == dns_typepair_any) {
1270
0
    INSIST(NEGATIVE(header));
1271
0
    INSIST(sigheader == NULL);
1272
0
    *foundp = header;
1273
0
    *foundsigp = NULL;
1274
0
    return true;
1275
0
  }
1276
1277
  /*
1278
   * Use the sigheader if we are looking for RRSIG.
1279
   */
1280
0
  if (DNS_TYPEPAIR_TYPE(typepair) == dns_rdatatype_rrsig) {
1281
0
    if (sigheader == NULL) {
1282
0
      return false;
1283
0
    }
1284
1285
0
    REQUIRE(EXISTS(sigheader) && !ANCIENT(sigheader));
1286
0
    if (sigheader->typepair == typepair) {
1287
0
      *foundp = sigheader;
1288
0
      *foundsigp = NULL;
1289
0
      return true;
1290
0
    }
1291
0
    return false;
1292
0
  } else {
1293
0
    if (header == NULL) {
1294
0
      return false;
1295
0
    }
1296
1297
0
    REQUIRE(EXISTS(header) && !ANCIENT(header));
1298
0
    REQUIRE(!NEGATIVE(header) || sigheader == NULL);
1299
1300
0
    if (header->typepair == typepair) {
1301
0
      *foundp = header;
1302
0
      *foundsigp = sigheader;
1303
0
      return true;
1304
0
    }
1305
0
  }
1306
1307
0
  return false;
1308
0
}
1309
1310
static void
1311
find_headers(qpcnode_t *node, qpc_search_t *search, dns_rdatatype_t type,
1312
0
       dns_slabheader_t **foundp, dns_slabheader_t **foundsigp) {
1313
0
  DNS_SLABTOP_FOREACH(top, node->data) {
1314
0
    dns_slabheader_t *header = NULL, *sigheader = NULL;
1315
0
    dns_slabtop_t *related = top->related;
1316
1317
0
    if (top->typepair == dns_typepair_any) {
1318
0
      INSIST(top->related == NULL);
1319
0
      header = first_header(top);
1320
0
      INSIST(NEGATIVE(header));
1321
0
      if (check_header(header, search)) {
1322
        /*
1323
         * NEGATIVE(ANY), but it is no longer valid.
1324
         */
1325
0
        header = NULL;
1326
0
        continue;
1327
0
      }
1328
0
      *foundp = NULL;
1329
0
      *foundsigp = NULL;
1330
0
      return;
1331
0
    }
1332
1333
0
    if (top->typepair == DNS_TYPEPAIR(type)) {
1334
0
      header = first_header(top);
1335
0
      if (related != NULL) {
1336
0
        sigheader = first_header(related);
1337
0
      }
1338
0
    } else if (top->typepair == DNS_SIGTYPEPAIR(type)) {
1339
0
      sigheader = first_header(top);
1340
0
      if (related != NULL) {
1341
0
        header = first_header(related);
1342
0
      }
1343
0
    } else {
1344
      /* Not our type; continue with next slabtop */
1345
0
      continue;
1346
0
    }
1347
1348
0
    if (check_header(header, search)) {
1349
0
      header = NULL;
1350
0
    }
1351
0
    if (check_header(sigheader, search)) {
1352
0
      sigheader = NULL;
1353
0
    }
1354
1355
    /*
1356
     * This function only sets positive headers.
1357
     */
1358
0
    if (header != NULL && !NEGATIVE(header)) {
1359
0
      *foundp = header;
1360
0
      *foundsigp = sigheader;
1361
0
    }
1362
1363
0
    return;
1364
0
  }
1365
0
}
1366
1367
static isc_result_t
1368
0
check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) {
1369
0
  qpc_search_t *search = arg;
1370
0
  dns_slabheader_t *found = NULL, *foundsig = NULL;
1371
0
  isc_result_t result;
1372
0
  isc_rwlock_t *nlock = NULL;
1373
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1374
1375
0
  REQUIRE(search->zonecut == NULL);
1376
1377
0
  nlock = &search->qpdb->buckets[node->locknum].lock;
1378
0
  NODE_RDLOCK(nlock, &nlocktype);
1379
1380
  /*
1381
   * Look for a DNAME or RRSIG DNAME rdataset.
1382
   */
1383
0
  find_headers(node, search, dns_rdatatype_dname, &found, &foundsig);
1384
1385
0
  if (found != NULL && (!DNS_TRUST_PENDING(atomic_load(&found->trust)) ||
1386
0
            (search->options & DNS_DBFIND_PENDINGOK) != 0))
1387
0
  {
1388
    /*
1389
     * We increment the reference count on node to ensure that
1390
     * search->zonecut_header will still be valid later.
1391
     */
1392
0
    qpcnode_acquire(search->qpdb, node, nlocktype,
1393
0
        isc_rwlocktype_none DNS__DB_FLARG_PASS);
1394
0
    search->zonecut = node;
1395
0
    search->zonecut_header = found;
1396
0
    search->zonecut_sigheader = foundsig;
1397
0
    search->need_cleanup = true;
1398
0
    result = DNS_R_PARTIALMATCH;
1399
0
  } else {
1400
0
    result = DNS_R_CONTINUE;
1401
0
  }
1402
1403
0
  NODE_UNLOCK(nlock, &nlocktype);
1404
1405
0
  return result;
1406
0
}
1407
1408
static isc_result_t
1409
find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node,
1410
         dns_dbnode_t **nodep, dns_name_t *foundname,
1411
         dns_rdataset_t *rdataset,
1412
0
         dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
1413
0
  isc_result_t result = ISC_R_NOTFOUND;
1414
0
  qpcache_t *qpdb = NULL;
1415
1416
  /*
1417
   * Caller must be holding the tree lock.
1418
   */
1419
1420
0
  qpdb = search->qpdb;
1421
1422
0
  for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) {
1423
0
    dns_slabheader_t *found = NULL, *foundsig = NULL;
1424
0
    isc_rwlock_t *nlock = NULL;
1425
0
    isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1426
1427
0
    dns_qpchain_node(&search->chain, i, NULL, (void **)&node, NULL);
1428
0
    nlock = &qpdb->buckets[node->locknum].lock;
1429
1430
0
    NODE_RDLOCK(nlock, &nlocktype);
1431
1432
    /*
1433
     * Look for NS and RRSIG NS rdatasets.
1434
     */
1435
0
    find_headers(node, search, dns_rdatatype_ns, &found, &foundsig);
1436
1437
0
    if (found != NULL) {
1438
      /*
1439
       * If we have to set foundname, we do it before
1440
       * anything else.
1441
       */
1442
0
      if (foundname != NULL) {
1443
0
        dns_name_copy(&node->name, foundname);
1444
0
      }
1445
0
      result = DNS_R_DELEGATION;
1446
0
      if (nodep != NULL) {
1447
0
        qpcnode_acquire(
1448
0
          search->qpdb, node, nlocktype,
1449
0
          isc_rwlocktype_none DNS__DB_FLARG_PASS);
1450
0
        *nodep = (dns_dbnode_t *)node;
1451
0
      }
1452
0
      bindrdatasets(search->qpdb, node, found, foundsig,
1453
0
              search->now, nlocktype,
1454
0
              isc_rwlocktype_none, rdataset,
1455
0
              sigrdataset DNS__DB_FLARG_PASS);
1456
0
    }
1457
1458
0
    NODE_UNLOCK(nlock, &nlocktype);
1459
1460
0
    if (found != NULL) {
1461
0
      break;
1462
0
    }
1463
0
  }
1464
1465
0
  return result;
1466
0
}
1467
1468
/*
1469
 * Look for a potentially covering NSEC in the cache where `name`
1470
 * is known not to exist.  This uses the auxiliary NSEC tree to find
1471
 * the potential NSEC owner. If found, we update 'foundname', 'nodep',
1472
 * 'rdataset' and 'sigrdataset', and return DNS_R_COVERINGNSEC.
1473
 * Otherwise, return ISC_R_NOTFOUND.
1474
 */
1475
static isc_result_t
1476
find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
1477
      dns_dbnode_t **nodep, dns_name_t *foundname,
1478
      dns_rdataset_t *rdataset,
1479
0
      dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
1480
0
  dns_fixedname_t fpredecessor, fixed;
1481
0
  dns_name_t *predecessor = NULL, *fname = NULL;
1482
0
  qpcnode_t *node = NULL;
1483
0
  dns_qpiter_t iter;
1484
0
  isc_result_t result;
1485
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1486
0
  isc_rwlock_t *nlock = NULL;
1487
0
  dns_slabheader_t *found = NULL, *foundsig = NULL;
1488
1489
  /*
1490
   * Look for the node in the auxiliary NSEC namespace.
1491
   */
1492
0
  result = dns_qp_lookup(search->qpdb->tree, name, DNS_DBNAMESPACE_NSEC,
1493
0
             NULL, &iter, NULL, (void **)&node, NULL);
1494
  /*
1495
   * When DNS_R_PARTIALMATCH or ISC_R_NOTFOUND is returned from
1496
   * dns_qp_lookup there is potentially a covering NSEC present
1497
   * in the cache so we need to search for it.  Otherwise we are
1498
   * done here.
1499
   */
1500
0
  if (result != DNS_R_PARTIALMATCH && result != ISC_R_NOTFOUND) {
1501
0
    return ISC_R_NOTFOUND;
1502
0
  }
1503
1504
0
  fname = dns_fixedname_initname(&fixed);
1505
0
  predecessor = dns_fixedname_initname(&fpredecessor);
1506
1507
  /*
1508
   * Extract predecessor from iterator.
1509
   */
1510
0
  result = dns_qpiter_current(&iter, predecessor, NULL, NULL);
1511
0
  if (result != ISC_R_SUCCESS) {
1512
0
    return ISC_R_NOTFOUND;
1513
0
  }
1514
1515
  /*
1516
   * Lookup the predecessor in the normal namespace.
1517
   */
1518
0
  node = NULL;
1519
0
  result = dns_qp_getname(search->qpdb->tree, predecessor,
1520
0
        DNS_DBNAMESPACE_NORMAL, (void **)&node, NULL);
1521
0
  if (result != ISC_R_SUCCESS) {
1522
0
    return result;
1523
0
  }
1524
0
  dns_name_copy(&node->name, fname);
1525
1526
0
  nlock = &search->qpdb->buckets[node->locknum].lock;
1527
0
  NODE_RDLOCK(nlock, &nlocktype);
1528
1529
0
  find_headers(node, search, dns_rdatatype_nsec, &found, &foundsig);
1530
1531
0
  if (found != NULL) {
1532
0
    if (nodep != NULL) {
1533
0
      qpcnode_acquire(search->qpdb, node, nlocktype,
1534
0
          isc_rwlocktype_none DNS__DB_FLARG_PASS);
1535
0
      *nodep = (dns_dbnode_t *)node;
1536
0
    }
1537
0
    bindrdatasets(search->qpdb, node, found, foundsig, search->now,
1538
0
            nlocktype, isc_rwlocktype_none, rdataset,
1539
0
            sigrdataset DNS__DB_FLARG_PASS);
1540
0
    dns_name_copy(fname, foundname);
1541
1542
0
    result = DNS_R_COVERINGNSEC;
1543
0
  } else {
1544
0
    result = ISC_R_NOTFOUND;
1545
0
  }
1546
0
  NODE_UNLOCK(nlock, &nlocktype);
1547
0
  return result;
1548
0
}
1549
1550
static inline bool
1551
0
missing_answer(dns_slabheader_t *found, unsigned int options) {
1552
0
  if (found == NULL) {
1553
0
    return true;
1554
0
  }
1555
1556
0
  dns_trust_t trust = atomic_load(&found->trust);
1557
0
  return (DNS_TRUST_ADDITIONAL(trust) &&
1558
0
    (options & DNS_DBFIND_ADDITIONALOK) == 0) ||
1559
0
         (DNS_TRUST_GLUE(trust) && (options & DNS_DBFIND_GLUEOK) == 0) ||
1560
0
         (DNS_TRUST_PENDING(trust) &&
1561
0
    (options & DNS_DBFIND_PENDINGOK) == 0);
1562
0
}
1563
1564
static void
1565
qpc_search_init(qpc_search_t *search, qpcache_t *db, unsigned int options,
1566
0
    isc_stdtime_t now) {
1567
  /*
1568
   * qpc_search_t contains two structures with large buffers (dns_qpiter_t
1569
   * and dns_qpchain_t). Those two structures will be initialized later by
1570
   * dns_qp_lookup anyway.
1571
   * To avoid the overhead of zero initialization, we avoid designated
1572
   * initializers and initialize all "small" fields manually.
1573
   */
1574
0
  search->qpdb = (qpcache_t *)db;
1575
0
  search->options = options;
1576
  /*
1577
   * qpch->in - Init by dns_qp_lookup
1578
   * qpiter - Init by dns_qp_lookup
1579
   */
1580
0
  search->need_cleanup = false;
1581
0
  search->now = now ? now : isc_stdtime_now();
1582
0
  search->zonecut = NULL;
1583
0
  search->zonecut_header = NULL;
1584
0
  search->zonecut_sigheader = NULL;
1585
0
}
1586
1587
static isc_result_t
1588
qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
1589
       dns_rdatatype_t type, unsigned int options, isc_stdtime_t __now,
1590
       dns_dbnode_t **nodep, dns_name_t *foundname,
1591
       dns_clientinfomethods_t *methods ISC_ATTR_UNUSED,
1592
       dns_clientinfo_t *clientinfo ISC_ATTR_UNUSED,
1593
       dns_rdataset_t *rdataset,
1594
0
       dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
1595
0
  qpcnode_t *node = NULL;
1596
0
  isc_result_t result;
1597
0
  bool cname_ok = true;
1598
0
  bool found_noqname = false;
1599
0
  bool all_negative = true;
1600
0
  bool empty_node;
1601
0
  isc_rwlock_t *nlock = NULL;
1602
0
  isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
1603
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1604
0
  dns_slabheader_t *found = NULL, *foundsig = NULL;
1605
0
  dns_slabheader_t *nsheader = NULL, *nssig = NULL;
1606
0
  dns_slabheader_t *nsecheader = NULL, *nsecsig = NULL;
1607
0
  dns_typepair_t typepair;
1608
1609
0
  if (type == dns_rdatatype_none) {
1610
    /* We can't search negative cache directly */
1611
0
    return ISC_R_NOTFOUND;
1612
0
  }
1613
1614
0
  qpc_search_t search;
1615
0
  qpc_search_init(&search, (qpcache_t *)db, options, __now);
1616
1617
0
  REQUIRE(VALID_QPDB((qpcache_t *)db));
1618
0
  REQUIRE(version == NULL);
1619
1620
0
  TREE_RDLOCK(&search.qpdb->tree_lock, &tlocktype);
1621
1622
  /*
1623
   * Search down from the root of the tree.
1624
   */
1625
0
  result = dns_qp_lookup(search.qpdb->tree, name, DNS_DBNAMESPACE_NORMAL,
1626
0
             NULL, NULL, &search.chain, (void **)&node, NULL);
1627
0
  if (result != ISC_R_NOTFOUND && foundname != NULL) {
1628
0
    dns_name_copy(&node->name, foundname);
1629
0
  }
1630
1631
  /*
1632
   * Check the QP chain to see if there's a node above us with a
1633
   * active DNAME or NS rdatasets.
1634
   *
1635
   * We're only interested in nodes above QNAME, so if the result
1636
   * was success, then we skip the last item in the chain.
1637
   */
1638
0
  unsigned int len = dns_qpchain_length(&search.chain);
1639
0
  if (result == ISC_R_SUCCESS) {
1640
0
    len--;
1641
0
  }
1642
1643
0
  for (unsigned int i = 0; i < len; i++) {
1644
0
    isc_result_t zcresult;
1645
0
    qpcnode_t *encloser = NULL;
1646
1647
0
    dns_qpchain_node(&search.chain, i, NULL, (void **)&encloser,
1648
0
         NULL);
1649
1650
0
    zcresult = check_zonecut(encloser,
1651
0
           (void *)&search DNS__DB_FLARG_PASS);
1652
0
    if (zcresult != DNS_R_CONTINUE) {
1653
0
      result = DNS_R_PARTIALMATCH;
1654
0
      search.chain.len = i - 1;
1655
0
      node = encloser;
1656
0
      if (foundname != NULL) {
1657
0
        dns_name_copy(&node->name, foundname);
1658
0
      }
1659
0
      break;
1660
0
    }
1661
0
  }
1662
1663
0
  if (result == DNS_R_PARTIALMATCH) {
1664
    /*
1665
     * If we discovered a covering DNAME skip looking for a covering
1666
     * NSEC.
1667
     */
1668
0
    if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0 &&
1669
0
        (search.zonecut_header == NULL ||
1670
0
         search.zonecut_header->typepair != dns_rdatatype_dname))
1671
0
    {
1672
0
      result = find_coveringnsec(
1673
0
        &search, name, nodep, foundname, rdataset,
1674
0
        sigrdataset DNS__DB_FLARG_PASS);
1675
0
      if (result == DNS_R_COVERINGNSEC) {
1676
0
        goto tree_exit;
1677
0
      }
1678
0
    }
1679
0
    if (search.zonecut != NULL) {
1680
0
      result = setup_delegation(&search, nodep, rdataset,
1681
0
              sigrdataset,
1682
0
              tlocktype DNS__DB_FLARG_PASS);
1683
0
      goto tree_exit;
1684
0
    } else {
1685
0
    find_ns:
1686
0
      result = find_deepest_zonecut(
1687
0
        &search, node, nodep, foundname, rdataset,
1688
0
        sigrdataset DNS__DB_FLARG_PASS);
1689
0
      goto tree_exit;
1690
0
    }
1691
0
  } else if (result != ISC_R_SUCCESS) {
1692
0
    goto tree_exit;
1693
0
  }
1694
1695
  /*
1696
   * Certain DNSSEC types are not subject to CNAME matching
1697
   * (RFC4035, section 2.5 and RFC3007).
1698
   */
1699
0
  if (type == dns_rdatatype_key || type == dns_rdatatype_nsec ||
1700
0
      type == dns_rdatatype_rrsig)
1701
0
  {
1702
0
    cname_ok = false;
1703
0
  }
1704
1705
  /*
1706
   * We now go looking for rdata...
1707
   */
1708
1709
0
  nlock = &search.qpdb->buckets[node->locknum].lock;
1710
0
  NODE_RDLOCK(nlock, &nlocktype);
1711
1712
  /*
1713
   * These pointers need to be reset here in case we did
1714
   * 'goto find_ns' from somewhere below.
1715
   */
1716
0
  found = NULL;
1717
0
  foundsig = NULL;
1718
0
  typepair = DNS_TYPEPAIR(type);
1719
0
  nsheader = NULL;
1720
0
  nsecheader = NULL;
1721
0
  nssig = NULL;
1722
0
  nsecsig = NULL;
1723
0
  empty_node = true;
1724
1725
0
  DNS_SLABTOP_FOREACH(top, node->data) {
1726
0
    dns_slabheader_t *header = NULL, *sigheader = NULL;
1727
0
    if (DNS_TYPEPAIR_TYPE(top->typepair) == dns_rdatatype_rrsig) {
1728
0
      sigheader = first_header(top);
1729
0
      if (top->related != NULL) {
1730
0
        header = first_header(top->related);
1731
0
      }
1732
0
    } else {
1733
0
      header = first_header(top);
1734
0
      if (top->related != NULL) {
1735
0
        sigheader = first_header(top->related);
1736
0
      }
1737
0
    }
1738
1739
0
    if (check_header(header, &search)) {
1740
0
      header = NULL;
1741
0
    }
1742
1743
0
    if (check_header(sigheader, &search)) {
1744
0
      sigheader = NULL;
1745
0
    }
1746
1747
0
    if (header == NULL && sigheader == NULL) {
1748
0
      continue;
1749
0
    }
1750
1751
    /*
1752
     * We now know that there is at least one active
1753
     * non-stale rdataset at this node.
1754
     */
1755
0
    empty_node = false;
1756
1757
0
    if (header != NULL && header->noqname != NULL &&
1758
0
        atomic_load(&header->trust) == dns_trust_secure)
1759
0
    {
1760
0
      found_noqname = true;
1761
0
    }
1762
1763
0
    if (header != NULL && !NEGATIVE(header)) {
1764
0
      all_negative = false;
1765
0
    }
1766
1767
0
    if (sigheader != NULL && !NEGATIVE(sigheader)) {
1768
0
      all_negative = false;
1769
0
    }
1770
1771
0
    if (related_headers(header, sigheader, typepair, &found,
1772
0
            &foundsig))
1773
0
    {
1774
      /*
1775
       * We can't exit early until we have an answer with
1776
       * sufficient trust level - see missing_answer()
1777
       * for details - because we might need NS or NSEC
1778
       * records.
1779
       */
1780
0
      if (missing_answer(found, options)) {
1781
0
        continue;
1782
0
      }
1783
1784
      /* We found something, continue with next header */
1785
0
      break;
1786
0
    }
1787
1788
0
    if (header == NULL || NEGATIVE(header)) {
1789
      /*
1790
       * We are not interested in the negative headers for the
1791
       * auxiliary types, only for the main type we are
1792
       * looking for.
1793
       */
1794
0
      continue;
1795
0
    }
1796
1797
0
    switch (top->typepair) {
1798
0
    case dns_rdatatype_cname:
1799
0
    case DNS_SIGTYPEPAIR(dns_rdatatype_cname):
1800
0
      if (cname_ok) {
1801
0
        found = header;
1802
0
        foundsig = sigheader;
1803
0
      }
1804
0
      break;
1805
1806
0
    case dns_rdatatype_ns:
1807
0
    case DNS_SIGTYPEPAIR(dns_rdatatype_ns):
1808
0
      nsheader = header;
1809
0
      nssig = sigheader;
1810
0
      break;
1811
1812
0
    case dns_rdatatype_nsec:
1813
0
    case DNS_SIGTYPEPAIR(dns_rdatatype_nsec):
1814
0
      nsecheader = header;
1815
0
      nsecsig = sigheader;
1816
0
      break;
1817
1818
0
    default:
1819
0
      if (typepair == dns_typepair_any) {
1820
        /* QTYPE==ANY, so any anwers will do */
1821
0
        found = header;
1822
0
        break;
1823
0
      }
1824
0
    }
1825
1826
0
    if (!missing_answer(found, options)) {
1827
0
      break;
1828
0
    }
1829
0
  }
1830
1831
0
  if (empty_node) {
1832
    /*
1833
     * We have an exact match for the name, but there are no
1834
     * extant rdatasets.  That means that this node doesn't
1835
     * meaningfully exist, and that we really have a partial match.
1836
     */
1837
0
    NODE_UNLOCK(nlock, &nlocktype);
1838
0
    if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) {
1839
0
      result = find_coveringnsec(
1840
0
        &search, name, nodep, foundname, rdataset,
1841
0
        sigrdataset DNS__DB_FLARG_PASS);
1842
0
      if (result == DNS_R_COVERINGNSEC) {
1843
0
        goto tree_exit;
1844
0
      }
1845
0
    }
1846
0
    goto find_ns;
1847
0
  }
1848
1849
  /*
1850
   * If we didn't find what we were looking for...
1851
   */
1852
0
  if (missing_answer(found, options)) {
1853
    /*
1854
     * Return covering NODATA NSEC record.
1855
     */
1856
0
    if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0 &&
1857
0
        nsecheader != NULL)
1858
0
    {
1859
0
      if (nodep != NULL) {
1860
0
        qpcnode_acquire(search.qpdb, node, nlocktype,
1861
0
            tlocktype DNS__DB_FLARG_PASS);
1862
0
        *nodep = (dns_dbnode_t *)node;
1863
0
      }
1864
0
      bindrdatasets(search.qpdb, node, nsecheader, nsecsig,
1865
0
              search.now, nlocktype, tlocktype,
1866
0
              rdataset, sigrdataset DNS__DB_FLARG_PASS);
1867
0
      result = DNS_R_COVERINGNSEC;
1868
0
      goto node_exit;
1869
0
    }
1870
1871
    /*
1872
     * This name was from a wild card.  Look for a covering NSEC.
1873
     */
1874
0
    if (found == NULL && (found_noqname || all_negative) &&
1875
0
        (search.options & DNS_DBFIND_COVERINGNSEC) != 0)
1876
0
    {
1877
0
      NODE_UNLOCK(nlock, &nlocktype);
1878
0
      result = find_coveringnsec(
1879
0
        &search, name, nodep, foundname, rdataset,
1880
0
        sigrdataset DNS__DB_FLARG_PASS);
1881
0
      if (result == DNS_R_COVERINGNSEC) {
1882
0
        goto tree_exit;
1883
0
      }
1884
0
      goto find_ns;
1885
0
    }
1886
1887
    /*
1888
     * If there is an NS rdataset at this node, then this is the
1889
     * deepest zone cut.
1890
     */
1891
0
    if (nsheader != NULL) {
1892
0
      if (nodep != NULL) {
1893
0
        qpcnode_acquire(search.qpdb, node, nlocktype,
1894
0
            tlocktype DNS__DB_FLARG_PASS);
1895
0
        *nodep = (dns_dbnode_t *)node;
1896
0
      }
1897
0
      bindrdatasets(search.qpdb, node, nsheader, nssig,
1898
0
              search.now, nlocktype, tlocktype,
1899
0
              rdataset, sigrdataset DNS__DB_FLARG_PASS);
1900
0
      result = DNS_R_DELEGATION;
1901
0
      goto node_exit;
1902
0
    }
1903
1904
    /*
1905
     * Go find the deepest zone cut.
1906
     */
1907
0
    NODE_UNLOCK(nlock, &nlocktype);
1908
0
    goto find_ns;
1909
0
  }
1910
1911
  /*
1912
   * We found what we were looking for, or we found a CNAME.
1913
   */
1914
1915
0
  if (nodep != NULL) {
1916
0
    qpcnode_acquire(search.qpdb, node, nlocktype,
1917
0
        tlocktype DNS__DB_FLARG_PASS);
1918
0
    *nodep = (dns_dbnode_t *)node;
1919
0
  }
1920
1921
0
  if (NEGATIVE(found)) {
1922
    /*
1923
     * We found a negative cache entry.
1924
     */
1925
0
    if (NXDOMAIN(found)) {
1926
0
      result = DNS_R_NCACHENXDOMAIN;
1927
0
    } else {
1928
0
      result = DNS_R_NCACHENXRRSET;
1929
0
    }
1930
0
  } else if (typepair != found->typepair &&
1931
0
       typepair != dns_typepair_any &&
1932
0
       found->typepair == DNS_TYPEPAIR(dns_rdatatype_cname))
1933
0
  {
1934
    /*
1935
     * We weren't doing an ANY query and we found a CNAME instead
1936
     * of the type we were looking for, so we need to indicate
1937
     * that result to the caller.
1938
     */
1939
0
    result = DNS_R_CNAME;
1940
0
  } else {
1941
    /*
1942
     * An ordinary successful query!
1943
     */
1944
0
    result = ISC_R_SUCCESS;
1945
0
  }
1946
1947
0
  if (typepair != dns_typepair_any || result == DNS_R_NCACHENXDOMAIN ||
1948
0
      result == DNS_R_NCACHENXRRSET)
1949
0
  {
1950
0
    bindrdatasets(search.qpdb, node, found, foundsig, search.now,
1951
0
            nlocktype, tlocktype, rdataset,
1952
0
            sigrdataset DNS__DB_FLARG_PASS);
1953
0
  }
1954
1955
0
node_exit:
1956
0
  NODE_UNLOCK(nlock, &nlocktype);
1957
1958
0
tree_exit:
1959
0
  TREE_UNLOCK(&search.qpdb->tree_lock, &tlocktype);
1960
1961
  /*
1962
   * If we found a zonecut but aren't going to use it, we have to
1963
   * let go of it.
1964
   */
1965
0
  if (search.need_cleanup) {
1966
0
    node = search.zonecut;
1967
0
    INSIST(node != NULL);
1968
0
    nlock = &search.qpdb->buckets[node->locknum].lock;
1969
1970
0
    NODE_RDLOCK(nlock, &nlocktype);
1971
0
    qpcnode_release(search.qpdb, node, &nlocktype,
1972
0
        &tlocktype DNS__DB_FLARG_PASS);
1973
0
    NODE_UNLOCK(nlock, &nlocktype);
1974
0
    INSIST(tlocktype == isc_rwlocktype_none);
1975
0
  }
1976
1977
0
  update_cachestats(search.qpdb, result);
1978
0
  return result;
1979
0
}
1980
1981
static isc_result_t
1982
seek_ns_headers(qpc_search_t *search, qpcnode_t *node, dns_dbnode_t **nodep,
1983
    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1984
    dns_name_t *foundname, dns_name_t *dcname,
1985
0
    isc_rwlocktype_t *tlocktype) {
1986
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1987
0
  isc_rwlock_t *nlock = &search->qpdb->buckets[node->locknum].lock;
1988
0
  dns_slabheader_t *found = NULL, *foundsig = NULL;
1989
1990
0
  NODE_RDLOCK(nlock, &nlocktype);
1991
1992
0
  find_headers(node, search, dns_rdatatype_ns, &found, &foundsig);
1993
1994
0
  if (found == NULL) {
1995
0
    isc_result_t result;
1996
1997
    /*
1998
     * No active NS records found. Call find_deepest_zonecut()
1999
     * to look for them in nodes above this one.
2000
     */
2001
0
    NODE_UNLOCK(nlock, &nlocktype);
2002
0
    result = find_deepest_zonecut(search, node, nodep, foundname,
2003
0
                rdataset,
2004
0
                sigrdataset DNS__DB_FLARG_PASS);
2005
0
    if (dcname != NULL) {
2006
0
      dns_name_copy(foundname, dcname);
2007
0
    }
2008
0
    return result;
2009
0
  }
2010
2011
0
  if (nodep != NULL) {
2012
0
    qpcnode_acquire(search->qpdb, node, nlocktype,
2013
0
        *tlocktype DNS__DB_FLARG_PASS);
2014
0
    *nodep = (dns_dbnode_t *)node;
2015
0
  }
2016
2017
0
  bindrdatasets(search->qpdb, node, found, foundsig, search->now,
2018
0
          nlocktype, *tlocktype, rdataset,
2019
0
          sigrdataset DNS__DB_FLARG_PASS);
2020
2021
0
  NODE_UNLOCK(nlock, &nlocktype);
2022
2023
0
  return ISC_R_SUCCESS;
2024
0
}
2025
2026
static isc_result_t
2027
qpcache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
2028
        isc_stdtime_t __now, dns_dbnode_t **nodep,
2029
        dns_name_t *foundname, dns_name_t *dcname,
2030
        dns_rdataset_t *rdataset,
2031
0
        dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
2032
0
  qpcnode_t *node = NULL;
2033
0
  isc_result_t result;
2034
0
  isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
2035
0
  qpc_search_t search = (qpc_search_t){
2036
0
    .qpdb = (qpcache_t *)db,
2037
0
    .options = options,
2038
0
    .now = __now ? __now : isc_stdtime_now(),
2039
0
  };
2040
0
  unsigned int len = 0;
2041
2042
0
  REQUIRE(VALID_QPDB((qpcache_t *)db));
2043
2044
0
  TREE_RDLOCK(&search.qpdb->tree_lock, &tlocktype);
2045
2046
  /*
2047
   * Search down from the root of the tree.
2048
   */
2049
0
  result = dns_qp_lookup(search.qpdb->tree, name, DNS_DBNAMESPACE_NORMAL,
2050
0
             NULL, NULL, &search.chain, (void **)&node, NULL);
2051
2052
0
  switch (result) {
2053
0
  case ISC_R_SUCCESS:
2054
0
    if ((options & DNS_DBFIND_NOEXACT) == 0) {
2055
0
      if (dcname != NULL) {
2056
0
        dns_name_copy(&node->name, dcname);
2057
0
      }
2058
0
      dns_name_copy(&node->name, foundname);
2059
0
      result = seek_ns_headers(&search, node, nodep, rdataset,
2060
0
             sigrdataset, foundname, dcname,
2061
0
             &tlocktype);
2062
0
      break;
2063
0
    }
2064
2065
0
    len = dns_qpchain_length(&search.chain);
2066
0
    if (len < 2) {
2067
0
      result = ISC_R_NOTFOUND;
2068
0
      break;
2069
0
    }
2070
2071
0
    FALLTHROUGH;
2072
0
  case DNS_R_PARTIALMATCH:
2073
0
    if (dcname != NULL) {
2074
0
      dns_name_copy(&node->name, dcname);
2075
0
    }
2076
2077
0
    if (result == ISC_R_SUCCESS) {
2078
      /* Fell through from the previous case */
2079
0
      INSIST(len >= 2);
2080
2081
0
      node = NULL;
2082
0
      dns_qpchain_node(&search.chain, len - 2, NULL,
2083
0
           (void **)&node, NULL);
2084
0
      search.chain.len = len - 1;
2085
0
    }
2086
2087
0
    result = find_deepest_zonecut(&search, node, nodep, foundname,
2088
0
                rdataset,
2089
0
                sigrdataset DNS__DB_FLARG_PASS);
2090
0
    break;
2091
0
  default:
2092
0
    break;
2093
0
  }
2094
2095
0
  TREE_UNLOCK(&search.qpdb->tree_lock, &tlocktype);
2096
2097
0
  INSIST(!search.need_cleanup);
2098
2099
0
  if (result == DNS_R_DELEGATION) {
2100
0
    result = ISC_R_SUCCESS;
2101
0
  }
2102
2103
0
  return result;
2104
0
}
2105
2106
static isc_result_t
2107
qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
2108
         dns_rdatatype_t type, dns_rdatatype_t covers,
2109
         isc_stdtime_t __now, dns_rdataset_t *rdataset,
2110
0
         dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
2111
0
  qpcache_t *qpdb = (qpcache_t *)db;
2112
0
  qpcnode_t *qpnode = (qpcnode_t *)node;
2113
0
  dns_slabheader_t *found = NULL, *foundsig = NULL;
2114
0
  dns_typepair_t typepair, sigpair;
2115
0
  isc_result_t result = ISC_R_SUCCESS;
2116
0
  isc_rwlock_t *nlock = NULL;
2117
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2118
0
  qpc_search_t search = (qpc_search_t){
2119
0
    .qpdb = (qpcache_t *)db,
2120
0
    .now = __now ? __now : isc_stdtime_now(),
2121
0
  };
2122
2123
0
  REQUIRE(VALID_QPDB(qpdb));
2124
0
  REQUIRE(version == NULL);
2125
0
  REQUIRE(type != dns_rdatatype_any);
2126
2127
0
  if (type == dns_rdatatype_none) {
2128
    /* We can't search negative cache directly */
2129
0
    return ISC_R_NOTFOUND;
2130
0
  }
2131
2132
0
  nlock = &qpdb->buckets[qpnode->locknum].lock;
2133
0
  NODE_RDLOCK(nlock, &nlocktype);
2134
2135
0
  typepair = DNS_TYPEPAIR_VALUE(type, covers);
2136
0
  sigpair = (type != dns_rdatatype_rrsig) ? DNS_SIGTYPEPAIR(type)
2137
0
            : dns_typepair_none;
2138
2139
0
  DNS_SLABTOP_FOREACH(top, qpnode->data) {
2140
0
    dns_slabheader_t *header = NULL, *sigheader = NULL;
2141
2142
0
    if (top->typepair != typepair && top->typepair != sigpair &&
2143
0
        top->typepair != dns_typepair_any)
2144
0
    {
2145
0
      continue;
2146
0
    }
2147
2148
0
    if (DNS_TYPEPAIR_TYPE(top->typepair) == dns_rdatatype_rrsig) {
2149
0
      sigheader = first_header(top);
2150
0
      if (top->related != NULL) {
2151
0
        header = first_header(top->related);
2152
0
      }
2153
0
    } else {
2154
0
      header = first_header(top);
2155
0
      if (top->related != NULL) {
2156
0
        sigheader = first_header(top->related);
2157
0
      }
2158
0
    }
2159
2160
0
    if (check_header(header, &search)) {
2161
0
      header = NULL;
2162
0
    }
2163
2164
0
    if (check_header(sigheader, &search)) {
2165
0
      sigheader = NULL;
2166
0
    }
2167
2168
0
    (void)related_headers(header, sigheader, typepair, &found,
2169
0
              &foundsig);
2170
0
    break;
2171
0
  }
2172
2173
0
  if (found != NULL) {
2174
0
    bindrdatasets(qpdb, qpnode, found, foundsig, search.now,
2175
0
            nlocktype, isc_rwlocktype_none, rdataset,
2176
0
            sigrdataset DNS__DB_FLARG_PASS);
2177
0
  }
2178
2179
0
  NODE_UNLOCK(nlock, &nlocktype);
2180
2181
0
  if (found == NULL) {
2182
0
    return ISC_R_NOTFOUND;
2183
0
  }
2184
2185
0
  if (NEGATIVE(found)) {
2186
    /*
2187
     * We found a negative cache entry.
2188
     */
2189
0
    if (NXDOMAIN(found)) {
2190
0
      result = DNS_R_NCACHENXDOMAIN;
2191
0
    } else {
2192
0
      result = DNS_R_NCACHENXRRSET;
2193
0
    }
2194
0
  }
2195
2196
0
  update_cachestats(qpdb, result);
2197
2198
0
  return result;
2199
0
}
2200
2201
static isc_result_t
2202
0
setcachestats(dns_db_t *db, isc_stats_t *stats) {
2203
0
  qpcache_t *qpdb = (qpcache_t *)db;
2204
2205
0
  REQUIRE(VALID_QPDB(qpdb));
2206
0
  REQUIRE(stats != NULL);
2207
2208
0
  isc_stats_attach(stats, &qpdb->cachestats);
2209
0
  return ISC_R_SUCCESS;
2210
0
}
2211
2212
static dns_stats_t *
2213
0
getrrsetstats(dns_db_t *db) {
2214
0
  qpcache_t *qpdb = (qpcache_t *)db;
2215
2216
0
  REQUIRE(VALID_QPDB(qpdb));
2217
2218
0
  return qpdb->rrsetstats;
2219
0
}
2220
2221
static isc_result_t
2222
0
setservestalettl(dns_db_t *db, dns_ttl_t ttl) {
2223
0
  qpcache_t *qpdb = (qpcache_t *)db;
2224
2225
0
  REQUIRE(VALID_QPDB(qpdb));
2226
2227
  /* currently no bounds checking.  0 means disable. */
2228
0
  qpdb->common.serve_stale_ttl = ttl;
2229
0
  return ISC_R_SUCCESS;
2230
0
}
2231
2232
static isc_result_t
2233
0
getservestalettl(dns_db_t *db, dns_ttl_t *ttl) {
2234
0
  qpcache_t *qpdb = (qpcache_t *)db;
2235
2236
0
  REQUIRE(VALID_QPDB(qpdb));
2237
2238
0
  *ttl = qpdb->common.serve_stale_ttl;
2239
0
  return ISC_R_SUCCESS;
2240
0
}
2241
2242
static isc_result_t
2243
0
setservestalerefresh(dns_db_t *db, uint32_t interval) {
2244
0
  qpcache_t *qpdb = (qpcache_t *)db;
2245
2246
0
  REQUIRE(VALID_QPDB(qpdb));
2247
2248
  /* currently no bounds checking.  0 means disable. */
2249
0
  qpdb->serve_stale_refresh = interval;
2250
0
  return ISC_R_SUCCESS;
2251
0
}
2252
2253
static isc_result_t
2254
0
getservestalerefresh(dns_db_t *db, uint32_t *interval) {
2255
0
  qpcache_t *qpdb = (qpcache_t *)db;
2256
2257
0
  REQUIRE(VALID_QPDB(qpdb));
2258
2259
0
  *interval = qpdb->serve_stale_refresh;
2260
0
  return ISC_R_SUCCESS;
2261
0
}
2262
2263
static void
2264
0
qpcnode_expiredata(dns_dbnode_t *node, void *data) {
2265
0
  qpcnode_t *qpnode = (qpcnode_t *)node;
2266
0
  qpcache_t *qpdb = (qpcache_t *)qpnode->qpdb;
2267
2268
0
  dns_slabtop_t *related = NULL;
2269
0
  dns_slabheader_t *header = data;
2270
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2271
0
  isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
2272
2273
0
  isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
2274
0
  NODE_WRLOCK(nlock, &nlocktype);
2275
0
  related = header->top->related;
2276
2277
0
  (void)expireheader(header, &nlocktype, &tlocktype,
2278
0
         dns_expire_flush DNS__DB_FILELINE);
2279
0
  if (related != NULL) {
2280
0
    header = first_header(related);
2281
0
    (void)expireheader(header, &nlocktype, &tlocktype,
2282
0
           dns_expire_flush DNS__DB_FILELINE);
2283
0
  }
2284
2285
0
  NODE_UNLOCK(nlock, &nlocktype);
2286
0
  INSIST(tlocktype == isc_rwlocktype_none);
2287
0
}
2288
2289
/*%
2290
 * These functions allow the heap code to rank the priority of each
2291
 * element.  It returns true if v1 happens "sooner" than v2.
2292
 */
2293
static bool
2294
0
ttl_sooner(void *v1, void *v2) {
2295
0
  dns_slabheader_t *h1 = v1;
2296
0
  dns_slabheader_t *h2 = v2;
2297
2298
0
  return h1->expire < h2->expire;
2299
0
}
2300
2301
/*%
2302
 * This function sets the heap index into the header.
2303
 */
2304
static void
2305
0
set_index(void *what, unsigned int idx) {
2306
0
  dns_slabheader_t *h = what;
2307
2308
0
  h->heap_index = idx;
2309
0
}
2310
2311
static void
2312
0
qpcache__destroy(qpcache_t *qpdb) {
2313
0
  unsigned int i;
2314
0
  char buf[DNS_NAME_FORMATSIZE];
2315
2316
0
  dns_qp_destroy(&qpdb->tree);
2317
2318
0
  if (dns_name_dynamic(&qpdb->common.origin)) {
2319
0
    dns_name_format(&qpdb->common.origin, buf, sizeof(buf));
2320
0
  } else {
2321
0
    strlcpy(buf, "<UNKNOWN>", sizeof(buf));
2322
0
  }
2323
0
  isc_log_write(DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
2324
0
          ISC_LOG_DEBUG(DNS_QPCACHE_LOG_STATS_LEVEL), "done %s(%s)",
2325
0
          __func__, buf);
2326
2327
0
  if (dns_name_dynamic(&qpdb->common.origin)) {
2328
0
    dns_name_free(&qpdb->common.origin, qpdb->common.mctx);
2329
0
  }
2330
0
  for (i = 0; i < qpdb->buckets_count; i++) {
2331
0
    NODE_DESTROYLOCK(&qpdb->buckets[i].lock);
2332
2333
0
    INSIST(ISC_SIEVE_EMPTY(qpdb->buckets[i].sieve));
2334
2335
0
    INSIST(isc_queue_empty(&qpdb->buckets[i].deadnodes));
2336
0
    isc_queue_destroy(&qpdb->buckets[i].deadnodes);
2337
2338
0
    isc_heap_destroy(&qpdb->buckets[i].heap);
2339
0
  }
2340
2341
0
  dns_stats_detach(&qpdb->rrsetstats);
2342
2343
0
  if (qpdb->cachestats != NULL) {
2344
0
    isc_stats_detach(&qpdb->cachestats);
2345
0
  }
2346
2347
0
  TREE_DESTROYLOCK(&qpdb->tree_lock);
2348
0
  isc_refcount_destroy(&qpdb->references);
2349
0
  isc_refcount_destroy(&qpdb->common.references);
2350
2351
0
  isc_rwlock_destroy(&qpdb->lock);
2352
0
  qpdb->common.magic = 0;
2353
0
  qpdb->common.impmagic = 0;
2354
0
  isc_mem_detach(&qpdb->hmctx);
2355
2356
0
  isc_mem_putanddetach(&qpdb->common.mctx, qpdb,
2357
0
           sizeof(*qpdb) + qpdb->buckets_count *
2358
0
                 sizeof(qpdb->buckets[0]));
2359
0
}
2360
2361
static void
2362
0
qpcache_destroy(dns_db_t *arg) {
2363
0
  qpcache_t *qpdb = (qpcache_t *)arg;
2364
2365
0
  qpcache_detach(&qpdb);
2366
0
}
2367
2368
/*%
2369
 * Clean up dead nodes.  These are nodes which have no references, and
2370
 * have no data.  They are dead but we could not or chose not to delete
2371
 * them when we deleted all the data at that node because we did not want
2372
 * to wait for the tree write lock.
2373
 */
2374
static void
2375
0
cleanup_deadnodes(qpcache_t *qpdb, uint16_t locknum) {
2376
0
  isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
2377
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2378
0
  isc_rwlock_t *nlock = &qpdb->buckets[locknum].lock;
2379
0
  qpcnode_t *qpnode = NULL, *qpnext = NULL;
2380
0
  isc_queue_t deadnodes;
2381
2382
0
  INSIST(locknum < qpdb->buckets_count);
2383
2384
0
  isc_queue_init(&deadnodes);
2385
2386
0
  TREE_WRLOCK(&qpdb->tree_lock, &tlocktype);
2387
0
  NODE_WRLOCK(nlock, &nlocktype);
2388
2389
0
  isc_queue_splice(&deadnodes, &qpdb->buckets[locknum].deadnodes);
2390
0
  isc_queue_for_each_entry_safe(&deadnodes, qpnode, qpnext, deadlink) {
2391
0
    qpcnode_release(qpdb, qpnode, &nlocktype,
2392
0
        &tlocktype DNS__DB_FILELINE);
2393
0
  }
2394
2395
0
  NODE_UNLOCK(nlock, &nlocktype);
2396
0
  TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
2397
0
}
2398
2399
static void
2400
0
cleanup_deadnodes_cb(void *arg) {
2401
0
  qpcache_t *qpdb = arg;
2402
0
  uint16_t locknum = isc_tid();
2403
2404
0
  cleanup_deadnodes(qpdb, locknum);
2405
0
  qpcache_unref(qpdb);
2406
0
}
2407
/*
2408
 * This function is assumed to be called when a node is newly referenced
2409
 * and can be in the deadnode list.  In that case the node will be references
2410
 * and cleanup_deadnodes() will remove it from the list when the cleaning
2411
 * happens.
2412
 * Note: while a new reference is gained in multiple places, there are only very
2413
 * few cases where the node can be in the deadnode list (only empty nodes can
2414
 * have been added to the list).
2415
 */
2416
static void
2417
reactivate_node(qpcache_t *qpdb, qpcnode_t *node,
2418
0
    isc_rwlocktype_t tlocktype ISC_ATTR_UNUSED DNS__DB_FLARG) {
2419
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2420
0
  isc_rwlock_t *nlock = &qpdb->buckets[node->locknum].lock;
2421
2422
0
  NODE_RDLOCK(nlock, &nlocktype);
2423
0
  qpcnode_acquire(qpdb, node, nlocktype, tlocktype DNS__DB_FLARG_PASS);
2424
0
  NODE_UNLOCK(nlock, &nlocktype);
2425
0
}
2426
2427
static qpcnode_t *
2428
0
new_qpcnode(qpcache_t *qpdb, const dns_name_t *name, dns_namespace_t nspace) {
2429
0
  qpcnode_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata));
2430
0
  *newdata = (qpcnode_t){
2431
0
    .types_list = CDS_LIST_HEAD_INIT(newdata->types_list),
2432
0
    .data = &newdata->types_list,
2433
0
    .methods = &qpcnode_methods,
2434
0
    .qpdb = qpdb,
2435
0
    .name = DNS_NAME_INITEMPTY,
2436
0
    .nspace = nspace,
2437
0
    .references = ISC_REFCOUNT_INITIALIZER(1),
2438
0
    .locknum = isc_random_uniform(qpdb->buckets_count),
2439
0
  };
2440
2441
0
  isc_mem_attach(qpdb->common.mctx, &newdata->mctx);
2442
0
  dns_name_dup(name, newdata->mctx, &newdata->name);
2443
2444
#ifdef DNS_DB_NODETRACE
2445
  fprintf(stderr, "new_qpcnode:%s:%s:%d:%p->references = 1\n", __func__,
2446
    __FILE__, __LINE__ + 1, name);
2447
#endif
2448
0
  return newdata;
2449
0
}
2450
2451
static isc_result_t
2452
qpcache_findnode(dns_db_t *db, const dns_name_t *name, bool create,
2453
     dns_clientinfomethods_t *methods ISC_ATTR_UNUSED,
2454
     dns_clientinfo_t *clientinfo ISC_ATTR_UNUSED,
2455
0
     dns_dbnode_t **nodep DNS__DB_FLARG) {
2456
0
  qpcache_t *qpdb = (qpcache_t *)db;
2457
0
  qpcnode_t *node = NULL;
2458
0
  isc_result_t result;
2459
0
  isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
2460
0
  dns_namespace_t nspace = DNS_DBNAMESPACE_NORMAL;
2461
2462
0
  TREE_RDLOCK(&qpdb->tree_lock, &tlocktype);
2463
0
  result = dns_qp_getname(qpdb->tree, name, nspace, (void **)&node, NULL);
2464
0
  if (result != ISC_R_SUCCESS) {
2465
0
    if (!create) {
2466
0
      goto unlock;
2467
0
    }
2468
    /*
2469
     * Try to upgrade the lock and if that fails unlock then relock.
2470
     */
2471
0
    TREE_FORCEUPGRADE(&qpdb->tree_lock, &tlocktype);
2472
0
    result = dns_qp_getname(qpdb->tree, name, nspace,
2473
0
          (void **)&node, NULL);
2474
0
    if (result != ISC_R_SUCCESS) {
2475
0
      node = new_qpcnode(qpdb, name, nspace);
2476
0
      result = dns_qp_insert(qpdb->tree, node, 0);
2477
0
      INSIST(result == ISC_R_SUCCESS);
2478
0
      qpcnode_unref(node);
2479
0
    }
2480
0
  }
2481
2482
0
  reactivate_node(qpdb, node, tlocktype DNS__DB_FLARG_PASS);
2483
2484
0
  *nodep = (dns_dbnode_t *)node;
2485
0
unlock:
2486
0
  TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
2487
2488
0
  return result;
2489
0
}
2490
2491
static isc_result_t
2492
qpcache_createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED,
2493
0
           dns_dbiterator_t **iteratorp) {
2494
0
  qpcache_t *qpdb = (qpcache_t *)db;
2495
0
  qpc_dbit_t *qpdbiter = NULL;
2496
2497
0
  REQUIRE(VALID_QPDB(qpdb));
2498
2499
0
  qpdbiter = isc_mem_get(qpdb->common.mctx, sizeof(*qpdbiter));
2500
0
  *qpdbiter = (qpc_dbit_t){
2501
0
    .common.methods = &dbiterator_methods,
2502
0
    .common.magic = DNS_DBITERATOR_MAGIC,
2503
0
    .paused = true,
2504
0
  };
2505
2506
0
  qpdbiter->name = dns_fixedname_initname(&qpdbiter->fixed);
2507
0
  dns_db_attach(db, &qpdbiter->common.db);
2508
0
  dns_qpiter_init(qpdb->tree, &qpdbiter->iter);
2509
2510
0
  *iteratorp = (dns_dbiterator_t *)qpdbiter;
2511
0
  return ISC_R_SUCCESS;
2512
0
}
2513
2514
static isc_result_t
2515
qpcache_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
2516
         unsigned int options, isc_stdtime_t __now,
2517
0
         dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
2518
0
  qpcache_t *qpdb = (qpcache_t *)db;
2519
0
  qpcnode_t *qpnode = (qpcnode_t *)node;
2520
0
  qpc_rditer_t *iterator = NULL;
2521
2522
0
  REQUIRE(VALID_QPDB(qpdb));
2523
0
  REQUIRE(version == NULL);
2524
2525
0
  iterator = isc_mem_get(qpdb->common.mctx, sizeof(*iterator));
2526
0
  *iterator = (qpc_rditer_t){
2527
0
    .common.magic = DNS_RDATASETITER_MAGIC,
2528
0
    .common.methods = &rdatasetiter_methods,
2529
0
    .common.db = db,
2530
0
    .common.node = node,
2531
0
    .common.options = options,
2532
0
    .common.now = __now ? __now : isc_stdtime_now(),
2533
0
  };
2534
2535
0
  qpcnode_acquire(qpdb, qpnode, isc_rwlocktype_none,
2536
0
      isc_rwlocktype_none DNS__DB_FLARG_PASS);
2537
2538
0
  *iteratorp = (dns_rdatasetiter_t *)iterator;
2539
2540
0
  return ISC_R_SUCCESS;
2541
0
}
2542
2543
static bool
2544
0
overmaxtype(qpcache_t *qpdb, uint32_t ntypes) {
2545
0
  if (qpdb->maxtypepername == 0) {
2546
0
    return false;
2547
0
  }
2548
2549
0
  return ntypes >= qpdb->maxtypepername;
2550
0
}
2551
2552
static bool
2553
0
prio_header(dns_slabtop_t *top) {
2554
0
  return prio_type(top->typepair);
2555
0
}
2556
2557
static void
2558
0
qpcnode_attachnode(dns_dbnode_t *source, dns_dbnode_t **targetp DNS__DB_FLARG) {
2559
0
  REQUIRE(targetp != NULL && *targetp == NULL);
2560
2561
0
  qpcnode_t *node = (qpcnode_t *)source;
2562
0
  qpcache_t *qpdb = (qpcache_t *)node->qpdb;
2563
2564
0
  qpcnode_acquire(qpdb, node, isc_rwlocktype_none,
2565
0
      isc_rwlocktype_none DNS__DB_FLARG_PASS);
2566
2567
0
  *targetp = source;
2568
0
}
2569
2570
static void
2571
0
qpcnode_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG) {
2572
0
  qpcnode_t *node = NULL;
2573
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2574
0
  isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
2575
0
  isc_rwlock_t *nlock = NULL;
2576
2577
0
  REQUIRE(nodep != NULL && *nodep != NULL);
2578
2579
0
  node = (qpcnode_t *)(*nodep);
2580
0
  qpcache_t *qpdb = (qpcache_t *)node->qpdb;
2581
0
  *nodep = NULL;
2582
0
  nlock = &qpdb->buckets[node->locknum].lock;
2583
2584
0
  REQUIRE(VALID_QPDB(qpdb));
2585
2586
  /*
2587
   * We can't destroy qpcache while holding a nodelock, so we need to
2588
   * reference it before acquiring the lock and release it afterward.
2589
   * Additionally, we must ensure that we don't destroy the database while
2590
   * the NODE_LOCK is locked.
2591
   */
2592
0
  qpcache_ref(qpdb);
2593
2594
0
  rcu_read_lock();
2595
0
  NODE_RDLOCK(nlock, &nlocktype);
2596
0
  qpcnode_release(qpdb, node, &nlocktype, &tlocktype DNS__DB_FLARG_PASS);
2597
0
  NODE_UNLOCK(nlock, &nlocktype);
2598
0
  rcu_read_unlock();
2599
2600
0
  qpcache_detach(&qpdb);
2601
0
}
2602
2603
static isc_result_t
2604
expire_ncache_entry(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabtop_t *top,
2605
        dns_slabheader_t *newheader, dns_trust_t trust,
2606
        dns_rdataset_t *addedrdataset, isc_stdtime_t now,
2607
        isc_rwlocktype_t nlocktype,
2608
0
        isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
2609
0
  dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair);
2610
0
  dns_rdatatype_t covers = DNS_TYPEPAIR_COVERS(newheader->typepair);
2611
0
  dns_typepair_t sigpair = !dns_rdatatype_issig(rdtype)
2612
0
           ? DNS_SIGTYPEPAIR(rdtype)
2613
0
           : dns_typepair_none;
2614
  /*
2615
   * 1. If we find a cached NXDOMAIN, don't cache anything else
2616
   *    (dns_typepair_any).
2617
   *
2618
   * 2. Don't cache an RRSIG if it covers a type for which we have a
2619
   *    cached NODATA record.
2620
   */
2621
0
  if ((top->typepair == dns_typepair_any) ||
2622
0
      (sigpair != dns_rdatatype_none && newheader->typepair == sigpair &&
2623
0
       DNS_TYPEPAIR_TYPE(top->typepair) == covers))
2624
0
  {
2625
0
    dns_slabheader_t *header = first_header(top);
2626
0
    if (header == NULL) {
2627
0
      return DNS_R_CONTINUE;
2628
0
    }
2629
2630
0
    if (trust < header->trust) {
2631
      /*
2632
       * The NXDOMAIN/NODATA(QTYPE=ANY) is more trusted.
2633
       */
2634
0
      qpcache_hit(qpdb, header);
2635
0
      bindrdataset(qpdb, qpnode, header, now, nlocktype,
2636
0
             tlocktype,
2637
0
             addedrdataset DNS__DB_FLARG_PASS);
2638
0
      return DNS_R_UNCHANGED;
2639
0
    }
2640
2641
    /*
2642
     * The new rdataset is better.  Expire the ncache entry.
2643
     */
2644
0
    mark_ancient(header);
2645
0
    return DNS_R_CONTINUE;
2646
0
  }
2647
2648
0
  return DNS_R_CONTINUE;
2649
0
}
2650
2651
static isc_result_t
2652
add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
2653
    unsigned int options, dns_rdataset_t *addedrdataset, isc_stdtime_t now,
2654
0
    isc_rwlocktype_t nlocktype, isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
2655
0
  dns_slabtop_t *priotop = NULL, *expiretop = NULL;
2656
0
  dns_slabtop_t *oldtop = NULL, *related = NULL;
2657
0
  dns_trust_t trust;
2658
0
  uint32_t ntypes = 0;
2659
0
  dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair);
2660
0
  dns_rdatatype_t covers = DNS_TYPEPAIR_COVERS(newheader->typepair);
2661
2662
0
  REQUIRE(rdtype != dns_rdatatype_none);
2663
0
  if (dns_rdatatype_issig(rdtype)) {
2664
    /* signature must be either negative or cover something */
2665
0
    REQUIRE(NEGATIVE(newheader) || covers != dns_rdatatype_none);
2666
0
  } else {
2667
    /* non-signature it must cover nothing */
2668
0
    REQUIRE(covers == dns_rdatatype_none);
2669
0
  }
2670
  /* positive header can't be for type ANY */
2671
0
  REQUIRE(rdtype != dns_rdatatype_any || NEGATIVE(newheader));
2672
2673
0
  if ((options & DNS_DBADD_FORCE) != 0) {
2674
0
    trust = dns_trust_ultimate;
2675
0
  } else {
2676
0
    trust = newheader->trust;
2677
0
  }
2678
2679
0
  DNS_SLABTOP_FOREACH(top, qpnode->data) {
2680
0
    dns_slabheader_t *header = first_header(top);
2681
0
    if (header == NULL) {
2682
0
      continue;
2683
0
    }
2684
2685
0
    if (EXISTS(newheader) && NEGATIVE(newheader) &&
2686
0
        rdtype == dns_rdatatype_any)
2687
0
    {
2688
      /*
2689
       * We're adding a negative cache entry which
2690
       * covers all types (NXDOMAIN, NODATA(QTYPE=ANY)).
2691
       *
2692
       * Make all other data ancient so that the only
2693
       * rdataset that can be found at this node is the
2694
       * negative cache entry.
2695
       */
2696
0
      mark_ancient(header);
2697
0
    }
2698
2699
0
    if (EXISTS(newheader) && NEGATIVE(newheader) &&
2700
0
        rdtype == dns_rdatatype_rrsig)
2701
0
    {
2702
      /*
2703
       * We're adding a proof that a signature doesn't exist.
2704
       *
2705
       * Mark all existing signatures as ancient.
2706
       */
2707
0
      if (DNS_TYPEPAIR_TYPE(top->typepair) ==
2708
0
          dns_rdatatype_rrsig)
2709
0
      {
2710
0
        mark_ancient(header);
2711
0
      }
2712
0
    }
2713
2714
0
    if (EXISTS(newheader) && !NEGATIVE(newheader) &&
2715
0
        NEGATIVE(header) && EXISTS(header) && ACTIVE(header, now))
2716
0
    {
2717
      /*
2718
       * Look for existing active NXDOMAIN or negative
2719
       * covered type if we are adding RRSIG.
2720
       */
2721
0
      isc_result_t result = expire_ncache_entry(
2722
0
        qpdb, qpnode, top, newheader, trust,
2723
0
        addedrdataset, now, nlocktype, tlocktype);
2724
0
      if (result == DNS_R_UNCHANGED) {
2725
        /*
2726
         * The existing negative entry is more trusted
2727
         * than the new rdataset.
2728
         */
2729
0
        return DNS_R_UNCHANGED;
2730
0
      }
2731
0
      INSIST(result == DNS_R_CONTINUE);
2732
0
    }
2733
2734
0
    if (ACTIVE(header, now)) {
2735
0
      ++ntypes;
2736
0
      expiretop = top;
2737
0
    }
2738
0
    if (prio_header(top)) {
2739
0
      priotop = top;
2740
0
    }
2741
2742
0
    if (top->typepair == newheader->typepair) {
2743
0
      INSIST(oldtop == NULL);
2744
0
      oldtop = top;
2745
0
    }
2746
2747
0
    if (rdtype == dns_rdatatype_rrsig) {
2748
0
      if (DNS_TYPEPAIR_TYPE(top->typepair) == covers) {
2749
0
        INSIST(related == NULL);
2750
0
        related = top;
2751
0
      }
2752
0
    } else {
2753
0
      if (top->typepair == DNS_SIGTYPEPAIR(rdtype)) {
2754
0
        INSIST(related == NULL);
2755
0
        related = top;
2756
0
      }
2757
0
    }
2758
0
  }
2759
2760
0
  if (oldtop != NULL) {
2761
0
    dns_slabheader_t *oldheader = first_header(oldtop);
2762
0
    INSIST(oldheader != NULL);
2763
2764
    /*
2765
     * Deleting an already non-existent rdataset has no effect.
2766
     */
2767
0
    if (!EXISTS(oldheader) && !EXISTS(newheader)) {
2768
0
      return DNS_R_UNCHANGED;
2769
0
    }
2770
2771
    /*
2772
     * Trying to add an rdataset with lower trust to a cache
2773
     * DB has no effect, provided that the cache data isn't
2774
     * stale. If the cache data is stale, new lower trust
2775
     * data will supersede it below. Unclear what the best
2776
     * policy is here.
2777
     */
2778
0
    dns_trust_t oldtrust = atomic_load(&oldheader->trust);
2779
0
    if (trust < oldtrust &&
2780
0
        (ACTIVE(oldheader, now) || !EXISTS(oldheader)))
2781
0
    {
2782
0
      qpcache_hit(qpdb, oldheader);
2783
0
      bindrdataset(qpdb, qpnode, oldheader, now, nlocktype,
2784
0
             tlocktype,
2785
0
             addedrdataset DNS__DB_FLARG_PASS);
2786
0
      if (ACTIVE(oldheader, now) &&
2787
0
          (options & DNS_DBADD_EQUALOK) != 0 &&
2788
0
          dns_rdataslab_equalx(
2789
0
            oldheader, newheader, qpdb->common.rdclass,
2790
0
            DNS_TYPEPAIR_TYPE(oldtop->typepair)))
2791
0
      {
2792
        /*
2793
         * Updated by caller to ISC_R_SUCCESS after
2794
         * cleaning up newheader.
2795
         */
2796
0
        return ISC_R_EXISTS;
2797
0
      }
2798
0
      return DNS_R_UNCHANGED;
2799
0
    }
2800
2801
    /*
2802
     * Don't replace existing NS in the cache if they already exist
2803
     * and replacing the existing one would increase the TTL. This
2804
     * prevents named being locked to old servers. Don't lower trust
2805
     * of existing record if the update is forced. Nothing special
2806
     * to be done w.r.t stale data; it gets replaced normally
2807
     * further down.
2808
     */
2809
0
    if (ACTIVE(oldheader, now) &&
2810
0
        oldtop->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
2811
0
        EXISTS(oldheader) && EXISTS(newheader) &&
2812
0
        newheader->trust < oldtrust &&
2813
0
        oldheader->expire < newheader->expire &&
2814
0
        dns_rdataslab_equalx(oldheader, newheader,
2815
0
           qpdb->common.rdclass,
2816
0
           DNS_TYPEPAIR_TYPE(oldtop->typepair)))
2817
0
    {
2818
0
      if (oldheader->noqname == NULL &&
2819
0
          newheader->noqname != NULL)
2820
0
      {
2821
0
        oldheader->noqname = newheader->noqname;
2822
0
        newheader->noqname = NULL;
2823
0
      }
2824
0
      if (oldheader->closest == NULL &&
2825
0
          newheader->closest != NULL)
2826
0
      {
2827
0
        oldheader->closest = newheader->closest;
2828
0
        newheader->closest = NULL;
2829
0
      }
2830
2831
0
      qpcache_hit(qpdb, oldheader);
2832
0
      bindrdataset(qpdb, qpnode, oldheader, now, nlocktype,
2833
0
             tlocktype,
2834
0
             addedrdataset DNS__DB_FLARG_PASS);
2835
0
      if ((options & DNS_DBADD_EQUALOK) != 0) {
2836
        /*
2837
         * Updated by caller to ISC_R_SUCCESS after
2838
         * cleaning up newheader.
2839
         */
2840
0
        return ISC_R_EXISTS;
2841
0
      }
2842
0
      return DNS_R_UNCHANGED;
2843
0
    }
2844
2845
    /*
2846
     * If we will be replacing an NS RRset, force its TTL
2847
     * to be no more than the current NS RRset's TTL.  This
2848
     * ensures the delegations that are withdrawn are honoured.
2849
     */
2850
0
    if (ACTIVE(oldheader, now) &&
2851
0
        oldtop->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
2852
0
        EXISTS(oldheader) && EXISTS(newheader) &&
2853
0
        newheader->trust > oldtrust)
2854
0
    {
2855
0
      if (newheader->expire > oldheader->expire) {
2856
0
        if (ZEROTTL(oldheader)) {
2857
0
          DNS_SLABHEADER_SETATTR(
2858
0
            newheader,
2859
0
            DNS_SLABHEADERATTR_ZEROTTL);
2860
0
        }
2861
0
        newheader->expire = oldheader->expire;
2862
0
      }
2863
0
    }
2864
0
    if (ACTIVE(oldheader, now) &&
2865
0
        (options & DNS_DBADD_PREFETCH) == 0 &&
2866
0
        (oldtop->typepair == DNS_TYPEPAIR(dns_rdatatype_a) ||
2867
0
         oldtop->typepair == DNS_TYPEPAIR(dns_rdatatype_aaaa) ||
2868
0
         oldtop->typepair == DNS_TYPEPAIR(dns_rdatatype_ds) ||
2869
0
         oldtop->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ds)) &&
2870
0
        EXISTS(oldheader) && EXISTS(newheader) &&
2871
0
        newheader->trust < oldtrust &&
2872
0
        oldheader->expire < newheader->expire &&
2873
0
        dns_rdataslab_equal(oldheader, newheader))
2874
0
    {
2875
0
      if (oldheader->noqname == NULL &&
2876
0
          newheader->noqname != NULL)
2877
0
      {
2878
0
        oldheader->noqname = newheader->noqname;
2879
0
        newheader->noqname = NULL;
2880
0
      }
2881
0
      if (oldheader->closest == NULL &&
2882
0
          newheader->closest != NULL)
2883
0
      {
2884
0
        oldheader->closest = newheader->closest;
2885
0
        newheader->closest = NULL;
2886
0
      }
2887
2888
0
      qpcache_hit(qpdb, oldheader);
2889
0
      bindrdataset(qpdb, qpnode, oldheader, now, nlocktype,
2890
0
             tlocktype,
2891
0
             addedrdataset DNS__DB_FLARG_PASS);
2892
0
      if ((options & DNS_DBADD_EQUALOK) != 0) {
2893
        /*
2894
         * Updated by caller to ISC_R_SUCCESS after
2895
         * cleaning up newheader.
2896
         */
2897
0
        return ISC_R_EXISTS;
2898
0
      }
2899
0
      return DNS_R_UNCHANGED;
2900
0
    }
2901
2902
0
    newheader->top = oldheader->top;
2903
0
    cds_list_add(&newheader->headers_link,
2904
0
           &oldheader->top->headers);
2905
2906
0
    if (ISC_SIEVE_LINKED(oldheader->top, link)) {
2907
0
      ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve,
2908
0
           oldheader->top, link);
2909
0
    }
2910
2911
0
    qpcache_miss(qpdb, newheader, &nlocktype,
2912
0
           &tlocktype DNS__DB_FLARG_PASS);
2913
2914
0
    mark_ancient(oldheader);
2915
2916
0
    if (EXISTS(newheader) && NEGATIVE(newheader) &&
2917
0
        !dns_rdatatype_issig(rdtype))
2918
0
    {
2919
0
      if (oldtop->related != NULL) {
2920
0
        dns_slabheader_t *oldsigheader =
2921
0
          first_header(oldtop->related);
2922
0
        mark_ancient(oldsigheader);
2923
0
      }
2924
0
    }
2925
0
  } else if (!EXISTS(newheader)) {
2926
    /*
2927
     * The type already doesn't exist; no point trying
2928
     * to delete it.
2929
     */
2930
0
    return DNS_R_UNCHANGED;
2931
0
  } else {
2932
    /* No rdatasets of the given type exist at the node. */
2933
0
    dns_slabtop_t *newtop = dns_slabtop_new(
2934
0
      ((dns_db_t *)qpdb)->mctx, newheader->typepair);
2935
2936
0
    if (prio_header(newtop)) {
2937
      /* This is a priority type, prepend it */
2938
0
      cds_list_add(&newtop->types_link, qpnode->data);
2939
0
    } else if (priotop != NULL) {
2940
      /* Append after the priority headers */
2941
0
      cds_list_add(&newtop->types_link, &priotop->types_link);
2942
0
    } else {
2943
      /* There were no priority headers */
2944
0
      cds_list_add(&newtop->types_link, qpnode->data);
2945
0
    }
2946
2947
0
    if (related != NULL) {
2948
0
      INSIST(related->related == NULL);
2949
0
      related->related = newtop;
2950
0
      newtop->related = related;
2951
0
    }
2952
2953
0
    newheader->top = newtop;
2954
0
    cds_list_add(&newheader->headers_link, &newtop->headers);
2955
2956
0
    qpcache_miss(qpdb, newheader, &nlocktype,
2957
0
           &tlocktype DNS__DB_FLARG_PASS);
2958
2959
0
    if (overmaxtype(qpdb, ntypes)) {
2960
0
      if (expiretop == NULL) {
2961
0
        expiretop = newtop;
2962
0
      }
2963
0
      if (NEGATIVE(newheader) && !prio_header(newtop)) {
2964
        /*
2965
         * Add the new non-priority negative
2966
         * header to the database only
2967
         * temporarily.
2968
         */
2969
0
        expiretop = newtop;
2970
0
      }
2971
2972
0
      mark_ancient(first_header(expiretop));
2973
0
      if (expiretop->related != NULL) {
2974
0
        mark_ancient(first_header(expiretop->related));
2975
0
      }
2976
0
    }
2977
0
  }
2978
2979
0
  bindrdataset(qpdb, qpnode, newheader, now, nlocktype, tlocktype,
2980
0
         addedrdataset DNS__DB_FLARG_PASS);
2981
2982
0
  return ISC_R_SUCCESS;
2983
0
}
2984
2985
static isc_result_t
2986
addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
2987
0
     dns_rdataset_t *rdataset) {
2988
0
  isc_result_t result;
2989
0
  dns_slabheader_proof_t *noqname = NULL;
2990
0
  dns_name_t name = DNS_NAME_INITEMPTY;
2991
0
  dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT;
2992
0
  isc_region_t r1, r2;
2993
2994
0
  result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig);
2995
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
2996
2997
0
  result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, maxrrperset);
2998
0
  if (result != ISC_R_SUCCESS) {
2999
0
    goto cleanup;
3000
0
  }
3001
3002
0
  result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, maxrrperset);
3003
0
  if (result != ISC_R_SUCCESS) {
3004
0
    goto cleanup;
3005
0
  }
3006
3007
0
  noqname = isc_mem_get(mctx, sizeof(*noqname));
3008
0
  *noqname = (dns_slabheader_proof_t){
3009
0
    .neg = ((dns_slabheader_t *)r1.base)->raw,
3010
0
    .negsig = ((dns_slabheader_t *)r2.base)->raw,
3011
0
    .type = neg.type,
3012
0
    .name = DNS_NAME_INITEMPTY,
3013
0
  };
3014
0
  dns_name_dup(&name, mctx, &noqname->name);
3015
0
  newheader->noqname = noqname;
3016
3017
0
cleanup:
3018
0
  dns_rdataset_disassociate(&neg);
3019
0
  dns_rdataset_disassociate(&negsig);
3020
3021
0
  return result;
3022
0
}
3023
3024
static isc_result_t
3025
addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
3026
0
     dns_rdataset_t *rdataset) {
3027
0
  isc_result_t result;
3028
0
  dns_slabheader_proof_t *closest = NULL;
3029
0
  dns_name_t name = DNS_NAME_INITEMPTY;
3030
0
  dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT;
3031
0
  isc_region_t r1, r2;
3032
3033
0
  result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig);
3034
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
3035
3036
0
  result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, maxrrperset);
3037
0
  if (result != ISC_R_SUCCESS) {
3038
0
    goto cleanup;
3039
0
  }
3040
3041
0
  result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, maxrrperset);
3042
0
  if (result != ISC_R_SUCCESS) {
3043
0
    goto cleanup;
3044
0
  }
3045
3046
0
  closest = isc_mem_get(mctx, sizeof(*closest));
3047
0
  *closest = (dns_slabheader_proof_t){
3048
0
    .neg = ((dns_slabheader_t *)r1.base)->raw,
3049
0
    .negsig = ((dns_slabheader_t *)r2.base)->raw,
3050
0
    .name = DNS_NAME_INITEMPTY,
3051
0
    .type = neg.type,
3052
0
  };
3053
0
  dns_name_dup(&name, mctx, &closest->name);
3054
0
  newheader->closest = closest;
3055
3056
0
cleanup:
3057
0
  dns_rdataset_disassociate(&neg);
3058
0
  dns_rdataset_disassociate(&negsig);
3059
0
  return result;
3060
0
}
3061
3062
static void
3063
expire_ttl_headers(qpcache_t *qpdb, unsigned int locknum,
3064
       isc_rwlocktype_t *nlocktypep, isc_rwlocktype_t *tlocktypep,
3065
       isc_stdtime_t now DNS__DB_FLARG);
3066
3067
static isc_result_t
3068
qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
3069
        isc_stdtime_t __now, dns_rdataset_t *rdataset,
3070
        unsigned int options,
3071
0
        dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
3072
0
  qpcache_t *qpdb = (qpcache_t *)db;
3073
0
  qpcnode_t *qpnode = (qpcnode_t *)node;
3074
0
  isc_region_t region;
3075
0
  dns_slabheader_t *newheader = NULL;
3076
0
  isc_result_t result;
3077
0
  bool delegating = false;
3078
0
  bool newnsec = false;
3079
0
  isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
3080
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3081
0
  isc_rwlock_t *nlock = NULL;
3082
0
  dns_fixedname_t fixed;
3083
0
  dns_name_t *name = NULL;
3084
0
  isc_stdtime_t now = __now ? __now : isc_stdtime_now();
3085
3086
0
  REQUIRE(VALID_QPDB(qpdb));
3087
0
  REQUIRE(version == NULL);
3088
3089
0
  result = dns_rdataslab_fromrdataset(rdataset, qpnode->mctx, &region,
3090
0
              qpdb->maxrrperset);
3091
0
  if (result != ISC_R_SUCCESS) {
3092
0
    if (result == DNS_R_TOOMANYRECORDS) {
3093
0
      dns__db_logtoomanyrecords((dns_db_t *)qpdb,
3094
0
              &qpnode->name, rdataset->type,
3095
0
              "adding", qpdb->maxrrperset);
3096
0
    }
3097
0
    return result;
3098
0
  }
3099
3100
0
  name = dns_fixedname_initname(&fixed);
3101
0
  dns_name_copy(&qpnode->name, name);
3102
0
  dns_rdataset_getownercase(rdataset, name);
3103
3104
0
  newheader = (dns_slabheader_t *)region.base;
3105
0
  dns_slabheader_reset(newheader, node);
3106
3107
  /*
3108
   * By default, dns_rdataslab_fromrdataset() sets newheader->ttl
3109
   * to the rdataset TTL. In the case of the cache, that's wrong;
3110
   * we need it to be set to the expire time instead.
3111
   */
3112
0
  setttl(newheader, rdataset->ttl + now);
3113
0
  if (rdataset->ttl == 0U) {
3114
0
    DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_ZEROTTL);
3115
0
  }
3116
3117
0
  if (rdataset->attributes.prefetch) {
3118
0
    DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_PREFETCH);
3119
0
  }
3120
0
  if (rdataset->attributes.negative) {
3121
0
    DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_NEGATIVE);
3122
0
  }
3123
0
  if (rdataset->attributes.nxdomain) {
3124
0
    DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_NXDOMAIN);
3125
0
  }
3126
0
  if (rdataset->attributes.optout) {
3127
0
    DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_OPTOUT);
3128
0
  }
3129
0
  if (rdataset->attributes.noqname) {
3130
0
    result = addnoqname(qpnode->mctx, newheader, qpdb->maxrrperset,
3131
0
            rdataset);
3132
0
    if (result != ISC_R_SUCCESS) {
3133
0
      return result;
3134
0
    }
3135
0
  }
3136
0
  if (rdataset->attributes.closest) {
3137
0
    result = addclosest(qpnode->mctx, newheader, qpdb->maxrrperset,
3138
0
            rdataset);
3139
0
    if (result != ISC_R_SUCCESS) {
3140
0
      return result;
3141
0
    }
3142
0
  }
3143
3144
0
  nlock = &qpdb->buckets[qpnode->locknum].lock;
3145
3146
  /*
3147
   * If we're adding a delegation type (which would be an NS or DNAME
3148
   * for a zone, but only DNAME counts for a cache), we need to set
3149
   * the callback bit on the node.
3150
   */
3151
0
  if (rdataset->type == dns_rdatatype_dname) {
3152
0
    delegating = true;
3153
0
  }
3154
3155
  /*
3156
   * Add to the auxiliary NSEC tree if we're adding an NSEC record.
3157
   */
3158
0
  if (rdataset->type == dns_rdatatype_nsec) {
3159
0
    NODE_RDLOCK(nlock, &nlocktype);
3160
0
    if (!qpnode->havensec) {
3161
0
      newnsec = true;
3162
0
    }
3163
0
    NODE_UNLOCK(nlock, &nlocktype);
3164
0
  }
3165
3166
  /*
3167
   * If we're adding a delegation type or adding to the auxiliary
3168
   * NSEC tree, hold an exclusive lock on the tree.
3169
   */
3170
0
  if (delegating || newnsec) {
3171
0
    TREE_WRLOCK(&qpdb->tree_lock, &tlocktype);
3172
0
  }
3173
3174
0
  NODE_WRLOCK(nlock, &nlocktype);
3175
3176
0
  expire_ttl_headers(qpdb, qpnode->locknum, &nlocktype, &tlocktype,
3177
0
         now DNS__DB_FLARG_PASS);
3178
3179
0
  if (newnsec && !qpnode->havensec) {
3180
0
    qpcnode_t *nsecnode = NULL;
3181
3182
0
    result = dns_qp_getname(qpdb->tree, name, DNS_DBNAMESPACE_NSEC,
3183
0
          (void **)&nsecnode, NULL);
3184
0
    if (result != ISC_R_SUCCESS) {
3185
0
      INSIST(nsecnode == NULL);
3186
0
      nsecnode = new_qpcnode(qpdb, name,
3187
0
                 DNS_DBNAMESPACE_NSEC);
3188
0
      result = dns_qp_insert(qpdb->tree, nsecnode, 0);
3189
0
      INSIST(result == ISC_R_SUCCESS);
3190
0
      qpcnode_detach(&nsecnode);
3191
0
    }
3192
0
    qpnode->havensec = true;
3193
0
  }
3194
3195
0
  result = add(qpdb, qpnode, newheader, options, addedrdataset, now,
3196
0
         nlocktype, tlocktype DNS__DB_FLARG_PASS);
3197
3198
0
  if (result == ISC_R_SUCCESS) {
3199
0
    DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_STATCOUNT);
3200
0
    update_rrsetstats(qpdb->rrsetstats, newheader->typepair,
3201
0
          newheader->attributes, true);
3202
3203
0
    if (delegating) {
3204
0
      qpnode->delegating = 1;
3205
0
    }
3206
0
  } else {
3207
0
    dns_slabheader_destroy(&newheader);
3208
0
  }
3209
3210
0
  NODE_UNLOCK(nlock, &nlocktype);
3211
3212
0
  if (result == ISC_R_EXISTS) {
3213
0
    result = ISC_R_SUCCESS;
3214
0
  }
3215
3216
0
  if (tlocktype != isc_rwlocktype_none) {
3217
0
    TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
3218
0
  }
3219
3220
0
  INSIST(tlocktype == isc_rwlocktype_none);
3221
3222
0
  return result;
3223
0
}
3224
3225
static isc_result_t
3226
qpcache_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
3227
           dns_dbversion_t *version, dns_rdatatype_t type,
3228
0
           dns_rdatatype_t covers DNS__DB_FLARG) {
3229
0
  qpcache_t *qpdb = (qpcache_t *)db;
3230
0
  qpcnode_t *qpnode = (qpcnode_t *)node;
3231
0
  isc_result_t result;
3232
0
  dns_slabheader_t *newheader = NULL;
3233
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3234
0
  isc_rwlock_t *nlock = NULL;
3235
0
  uint16_t attributes = DNS_SLABHEADERATTR_NONEXISTENT;
3236
3237
0
  REQUIRE(VALID_QPDB(qpdb));
3238
0
  REQUIRE(version == NULL);
3239
3240
  /* Positive ANY type can't be in the cache. */
3241
0
  if (type == dns_rdatatype_any) {
3242
0
    return ISC_R_NOTIMPLEMENTED;
3243
0
  }
3244
3245
  /* Convert the negative type into positive type. */
3246
0
  if (type == dns_rdatatype_none && covers != dns_rdatatype_none) {
3247
0
    type = covers;
3248
0
    covers = dns_rdatatype_none;
3249
0
    attributes |= DNS_SLABHEADERATTR_NEGATIVE;
3250
0
  }
3251
3252
0
  newheader = dns_slabheader_new(db->mctx, node);
3253
0
  newheader->typepair = DNS_TYPEPAIR_VALUE(type, covers);
3254
0
  setttl(newheader, 0);
3255
0
  atomic_init(&newheader->attributes, attributes);
3256
3257
0
  nlock = &qpdb->buckets[qpnode->locknum].lock;
3258
0
  NODE_WRLOCK(nlock, &nlocktype);
3259
0
  result = add(qpdb, qpnode, newheader, DNS_DBADD_FORCE, NULL, 0,
3260
0
         nlocktype, isc_rwlocktype_none DNS__DB_FLARG_PASS);
3261
0
  if (result != ISC_R_SUCCESS) {
3262
0
    dns_slabheader_destroy(&newheader);
3263
0
  }
3264
0
  NODE_UNLOCK(nlock, &nlocktype);
3265
3266
0
  return result;
3267
0
}
3268
3269
static unsigned int
3270
0
nodecount(dns_db_t *db) {
3271
0
  qpcache_t *qpdb = (qpcache_t *)db;
3272
0
  dns_qp_memusage_t mu;
3273
0
  isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
3274
3275
0
  REQUIRE(VALID_QPDB(qpdb));
3276
3277
0
  TREE_RDLOCK(&qpdb->tree_lock, &tlocktype);
3278
0
  mu = dns_qp_memusage(qpdb->tree);
3279
0
  TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
3280
3281
0
  return mu.leaves;
3282
0
}
3283
3284
isc_result_t
3285
dns__qpcache_create(isc_mem_t *mctx, const dns_name_t *origin,
3286
        dns_dbtype_t type, dns_rdataclass_t rdclass,
3287
        unsigned int argc, char *argv[],
3288
0
        void *driverarg ISC_ATTR_UNUSED, dns_db_t **dbp) {
3289
0
  qpcache_t *qpdb = NULL;
3290
0
  isc_mem_t *hmctx = mctx;
3291
0
  isc_loop_t *loop = isc_loop();
3292
0
  int i;
3293
0
  size_t nloops = isc_loopmgr_nloops();
3294
3295
  /* This database implementation only supports cache semantics */
3296
0
  REQUIRE(type == dns_dbtype_cache);
3297
0
  REQUIRE(loop != NULL);
3298
3299
0
  qpdb = isc_mem_get(mctx,
3300
0
         sizeof(*qpdb) + nloops * sizeof(qpdb->buckets[0]));
3301
0
  *qpdb = (qpcache_t){
3302
0
    .common.methods = &qpdb_cachemethods,
3303
0
    .common.origin = DNS_NAME_INITEMPTY,
3304
0
    .common.rdclass = rdclass,
3305
0
    .common.attributes = DNS_DBATTR_CACHE,
3306
0
    .common.references = 1,
3307
0
    .references = 1,
3308
0
    .buckets_count = nloops,
3309
0
  };
3310
3311
  /*
3312
   * If argv[0] exists, it points to a memory context to use for heap
3313
   */
3314
0
  if (argc != 0) {
3315
0
    hmctx = (isc_mem_t *)argv[0];
3316
0
  }
3317
3318
0
  isc_rwlock_init(&qpdb->lock);
3319
0
  TREE_INITLOCK(&qpdb->tree_lock);
3320
3321
0
  qpdb->buckets_count = isc_loopmgr_nloops();
3322
3323
0
  dns_rdatasetstats_create(mctx, &qpdb->rrsetstats);
3324
0
  for (i = 0; i < (int)qpdb->buckets_count; i++) {
3325
0
    ISC_SIEVE_INIT(qpdb->buckets[i].sieve);
3326
3327
0
    qpdb->buckets[i].heap = NULL;
3328
0
    isc_heap_create(hmctx, ttl_sooner, set_index, 0,
3329
0
        &qpdb->buckets[i].heap);
3330
3331
0
    isc_queue_init(&qpdb->buckets[i].deadnodes);
3332
3333
0
    NODE_INITLOCK(&qpdb->buckets[i].lock);
3334
0
  }
3335
3336
  /*
3337
   * Attach to the mctx.  The database will persist so long as there
3338
   * are references to it, and attaching to the mctx ensures that our
3339
   * mctx won't disappear out from under us.
3340
   */
3341
0
  isc_mem_attach(mctx, &qpdb->common.mctx);
3342
0
  isc_mem_attach(hmctx, &qpdb->hmctx);
3343
3344
  /*
3345
   * Make a copy of the origin name.
3346
   */
3347
0
  dns_name_dup(origin, mctx, &qpdb->common.origin);
3348
3349
  /*
3350
   * Make the qp trie.
3351
   */
3352
0
  dns_qp_create(mctx, &qpmethods, qpdb, &qpdb->tree);
3353
3354
0
  qpdb->common.magic = DNS_DB_MAGIC;
3355
0
  qpdb->common.impmagic = QPDB_MAGIC;
3356
3357
0
  *dbp = (dns_db_t *)qpdb;
3358
3359
0
  return ISC_R_SUCCESS;
3360
0
}
3361
3362
/*
3363
 * Rdataset Iterator Methods
3364
 */
3365
3366
static void
3367
0
rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
3368
0
  qpc_rditer_t *iterator = NULL;
3369
3370
0
  iterator = (qpc_rditer_t *)(*iteratorp);
3371
3372
0
  dns__db_detachnode(&iterator->common.node DNS__DB_FLARG_PASS);
3373
0
  isc_mem_put(iterator->common.db->mctx, iterator, sizeof(*iterator));
3374
3375
0
  *iteratorp = NULL;
3376
0
}
3377
3378
static bool
3379
iterator_active(qpcache_t *qpdb, qpc_rditer_t *iterator,
3380
0
    dns_slabheader_t *header) {
3381
0
  dns_ttl_t stale_ttl = header->expire + STALE_TTL(header, qpdb);
3382
3383
  /*
3384
   * If this header is still active then return it.
3385
   */
3386
0
  if (ACTIVE(header, iterator->common.now)) {
3387
0
    return true;
3388
0
  }
3389
3390
  /*
3391
   * If we are not returning stale records or the rdataset is
3392
   * too old don't return it.
3393
   */
3394
0
  if (!STALEOK(iterator) || (iterator->common.now > stale_ttl)) {
3395
0
    return false;
3396
0
  }
3397
0
  return true;
3398
0
}
3399
3400
static isc_result_t
3401
0
rdatasetiter_first(dns_rdatasetiter_t *it DNS__DB_FLARG) {
3402
0
  qpc_rditer_t *iterator = (qpc_rditer_t *)it;
3403
0
  qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
3404
0
  qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node;
3405
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3406
0
  isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
3407
3408
0
  iterator->current = NULL;
3409
3410
0
  NODE_RDLOCK(nlock, &nlocktype);
3411
3412
0
  DNS_SLABTOP_FOREACH(top, qpnode->data) {
3413
0
    dns_slabheader_t *header = first_existing_header(top);
3414
3415
0
    if (EXPIREDOK(iterator) ||
3416
0
        (header != NULL && iterator_active(qpdb, iterator, header)))
3417
0
    {
3418
0
      iterator->current = top;
3419
0
      break;
3420
0
    }
3421
0
  }
3422
3423
0
  NODE_UNLOCK(nlock, &nlocktype);
3424
3425
0
  if (iterator->current == NULL) {
3426
0
    return ISC_R_NOMORE;
3427
0
  }
3428
3429
0
  return ISC_R_SUCCESS;
3430
0
}
3431
3432
static isc_result_t
3433
0
rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) {
3434
0
  qpc_rditer_t *iterator = (qpc_rditer_t *)it;
3435
0
  qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
3436
0
  qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node;
3437
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3438
0
  isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
3439
0
  dns_slabtop_t *from = NULL;
3440
3441
0
  if (iterator->current == NULL) {
3442
0
    return ISC_R_NOMORE;
3443
0
  }
3444
3445
0
  NODE_RDLOCK(nlock, &nlocktype);
3446
3447
0
  from = cds_list_entry(iterator->current->types_link.next, dns_slabtop_t,
3448
0
            types_link);
3449
0
  iterator->current = NULL;
3450
3451
0
  if (from != NULL) {
3452
0
    DNS_SLABTOP_FOREACH_FROM(top, qpnode->data, from) {
3453
0
      dns_slabheader_t *header = first_existing_header(top);
3454
3455
0
      if (EXPIREDOK(iterator) ||
3456
0
          (header != NULL &&
3457
0
           iterator_active(qpdb, iterator, header)))
3458
0
      {
3459
0
        iterator->current = top;
3460
0
        break;
3461
0
      }
3462
0
    }
3463
0
  }
3464
3465
0
  NODE_UNLOCK(nlock, &nlocktype);
3466
3467
0
  if (iterator->current == NULL) {
3468
0
    return ISC_R_NOMORE;
3469
0
  }
3470
3471
0
  return ISC_R_SUCCESS;
3472
0
}
3473
3474
static void
3475
rdatasetiter_current(dns_rdatasetiter_t *it,
3476
0
         dns_rdataset_t *rdataset DNS__DB_FLARG) {
3477
0
  qpc_rditer_t *iterator = (qpc_rditer_t *)it;
3478
0
  qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
3479
0
  qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node;
3480
0
  dns_slabtop_t *top = NULL;
3481
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3482
0
  isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
3483
3484
0
  top = iterator->current;
3485
0
  REQUIRE(top != NULL);
3486
3487
0
  NODE_RDLOCK(nlock, &nlocktype);
3488
3489
0
  dns_slabheader_t *header = first_existing_header(top);
3490
0
  INSIST(header != NULL);
3491
3492
0
  bindrdataset(qpdb, qpnode, header, iterator->common.now, nlocktype,
3493
0
         isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS);
3494
3495
0
  NODE_UNLOCK(nlock, &nlocktype);
3496
0
}
3497
3498
/*
3499
 * Database Iterator Methods
3500
 */
3501
3502
static void
3503
0
reference_iter_node(qpc_dbit_t *qpdbiter DNS__DB_FLARG) {
3504
0
  qpcache_t *qpdb = (qpcache_t *)qpdbiter->common.db;
3505
0
  qpcnode_t *node = qpdbiter->node;
3506
3507
0
  if (node == NULL) {
3508
0
    return;
3509
0
  }
3510
3511
0
  INSIST(qpdbiter->tree_locked != isc_rwlocktype_none);
3512
0
  reactivate_node(qpdb, node, qpdbiter->tree_locked DNS__DB_FLARG_PASS);
3513
0
}
3514
3515
static void
3516
0
dereference_iter_node(qpc_dbit_t *qpdbiter DNS__DB_FLARG) {
3517
0
  qpcache_t *qpdb = (qpcache_t *)qpdbiter->common.db;
3518
0
  qpcnode_t *node = qpdbiter->node;
3519
0
  isc_rwlock_t *nlock = NULL;
3520
0
  isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3521
0
  isc_rwlocktype_t tlocktype = qpdbiter->tree_locked;
3522
3523
0
  if (node == NULL) {
3524
0
    return;
3525
0
  }
3526
3527
0
  REQUIRE(tlocktype != isc_rwlocktype_write);
3528
3529
0
  nlock = &qpdb->buckets[node->locknum].lock;
3530
0
  NODE_RDLOCK(nlock, &nlocktype);
3531
0
  qpcnode_release(qpdb, node, &nlocktype,
3532
0
      &qpdbiter->tree_locked DNS__DB_FLARG_PASS);
3533
0
  NODE_UNLOCK(nlock, &nlocktype);
3534
3535
0
  INSIST(qpdbiter->tree_locked == tlocktype);
3536
3537
0
  qpdbiter->node = NULL;
3538
0
}
3539
3540
static void
3541
0
resume_iteration(qpc_dbit_t *qpdbiter, bool continuing) {
3542
0
  qpcache_t *qpdb = (qpcache_t *)qpdbiter->common.db;
3543
3544
0
  REQUIRE(qpdbiter->paused);
3545
0
  REQUIRE(qpdbiter->tree_locked == isc_rwlocktype_none);
3546
3547
0
  TREE_RDLOCK(&qpdb->tree_lock, &qpdbiter->tree_locked);
3548
3549
  /*
3550
   * If we're being called from dbiterator_next, we may need
3551
   * to reinitialize the iterator to the current name. The
3552
   * tree could have changed while it was unlocked, which
3553
   * would make the iterator traversal inconsistent.
3554
   *
3555
   * As long as the iterator is holding a reference to
3556
   * qpdbiter->node, the node won't be removed from the tree,
3557
   * so the lookup should always succeed.
3558
   */
3559
0
  if (continuing && qpdbiter->node != NULL) {
3560
0
    isc_result_t result;
3561
0
    result = dns_qp_lookup(qpdb->tree, qpdbiter->name,
3562
0
               DNS_DBNAMESPACE_NORMAL, NULL,
3563
0
               &qpdbiter->iter, NULL, NULL, NULL);
3564
0
    INSIST(result == ISC_R_SUCCESS);
3565
0
  }
3566
3567
0
  qpdbiter->paused = false;
3568
0
}
3569
3570
static void
3571
0
dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG) {
3572
0
  qpc_dbit_t *qpdbiter = (qpc_dbit_t *)(*iteratorp);
3573
0
  qpcache_t *qpdb = (qpcache_t *)qpdbiter->common.db;
3574
0
  dns_db_t *db = NULL;
3575
3576
0
  if (qpdbiter->tree_locked == isc_rwlocktype_read) {
3577
0
    TREE_UNLOCK(&qpdb->tree_lock, &qpdbiter->tree_locked);
3578
0
  }
3579
0
  INSIST(qpdbiter->tree_locked == isc_rwlocktype_none);
3580
3581
0
  dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
3582
3583
0
  dns_db_attach(qpdbiter->common.db, &db);
3584
0
  dns_db_detach(&qpdbiter->common.db);
3585
3586
0
  isc_mem_put(db->mctx, qpdbiter, sizeof(*qpdbiter));
3587
0
  dns_db_detach(&db);
3588
3589
0
  *iteratorp = NULL;
3590
0
}
3591
3592
static isc_result_t
3593
0
dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG) {
3594
0
  isc_result_t result;
3595
0
  qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
3596
0
  qpcache_t *qpdb = (qpcache_t *)iterator->db;
3597
3598
0
  if (qpdbiter->result != ISC_R_SUCCESS &&
3599
0
      qpdbiter->result != ISC_R_NOTFOUND &&
3600
0
      qpdbiter->result != DNS_R_PARTIALMATCH &&
3601
0
      qpdbiter->result != ISC_R_NOMORE)
3602
0
  {
3603
0
    return qpdbiter->result;
3604
0
  }
3605
3606
0
  if (qpdbiter->paused) {
3607
0
    resume_iteration(qpdbiter, false);
3608
0
  }
3609
3610
0
  dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
3611
3612
0
  dns_qpiter_init(qpdb->tree, &qpdbiter->iter);
3613
0
  result = dns_qpiter_next(&qpdbiter->iter, NULL,
3614
0
         (void **)&qpdbiter->node, NULL);
3615
3616
0
  if (result == ISC_R_SUCCESS &&
3617
0
      qpdbiter->node->nspace == DNS_DBNAMESPACE_NORMAL)
3618
0
  {
3619
0
    dns_name_copy(&qpdbiter->node->name, qpdbiter->name);
3620
0
    reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
3621
0
  } else if (result == ISC_R_SUCCESS) {
3622
0
    result = ISC_R_NOMORE;
3623
0
    qpdbiter->node = NULL;
3624
0
  } else {
3625
    /* The tree is empty. */
3626
0
    INSIST(result == ISC_R_NOMORE);
3627
0
    qpdbiter->node = NULL;
3628
0
  }
3629
3630
0
  qpdbiter->result = result;
3631
3632
0
  if (result != ISC_R_SUCCESS) {
3633
0
    ENSURE(!qpdbiter->paused);
3634
0
  }
3635
3636
0
  return result;
3637
0
}
3638
3639
static isc_result_t
3640
0
dbiterator_last(dns_dbiterator_t *iterator ISC_ATTR_UNUSED DNS__DB_FLARG) {
3641
0
  return ISC_R_NOTIMPLEMENTED;
3642
0
}
3643
3644
static isc_result_t
3645
dbiterator_seek(dns_dbiterator_t *iterator,
3646
0
    const dns_name_t *name DNS__DB_FLARG) {
3647
0
  isc_result_t result;
3648
0
  qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
3649
0
  qpcache_t *qpdb = (qpcache_t *)iterator->db;
3650
3651
0
  if (qpdbiter->result != ISC_R_SUCCESS &&
3652
0
      qpdbiter->result != ISC_R_NOTFOUND &&
3653
0
      qpdbiter->result != DNS_R_PARTIALMATCH &&
3654
0
      qpdbiter->result != ISC_R_NOMORE)
3655
0
  {
3656
0
    return qpdbiter->result;
3657
0
  }
3658
3659
0
  if (qpdbiter->paused) {
3660
0
    resume_iteration(qpdbiter, false);
3661
0
  }
3662
3663
0
  dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
3664
3665
0
  result = dns_qp_lookup(qpdb->tree, name, DNS_DBNAMESPACE_NORMAL, NULL,
3666
0
             &qpdbiter->iter, NULL, (void **)&qpdbiter->node,
3667
0
             NULL);
3668
3669
0
  if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
3670
0
    dns_name_copy(&qpdbiter->node->name, qpdbiter->name);
3671
0
    reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
3672
0
  } else {
3673
0
    qpdbiter->node = NULL;
3674
0
  }
3675
3676
0
  qpdbiter->result = (result == DNS_R_PARTIALMATCH) ? ISC_R_SUCCESS
3677
0
                : result;
3678
0
  return result;
3679
0
}
3680
3681
static isc_result_t
3682
0
dbiterator_prev(dns_dbiterator_t *iterator ISC_ATTR_UNUSED DNS__DB_FLARG) {
3683
0
  return ISC_R_NOTIMPLEMENTED;
3684
0
}
3685
3686
static isc_result_t
3687
0
dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG) {
3688
0
  isc_result_t result;
3689
0
  qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
3690
3691
0
  REQUIRE(qpdbiter->node != NULL);
3692
3693
0
  if (qpdbiter->result != ISC_R_SUCCESS) {
3694
0
    return qpdbiter->result;
3695
0
  }
3696
3697
0
  if (qpdbiter->paused) {
3698
0
    resume_iteration(qpdbiter, true);
3699
0
  }
3700
3701
0
  dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
3702
3703
0
  result = dns_qpiter_next(&qpdbiter->iter, NULL,
3704
0
         (void **)&qpdbiter->node, NULL);
3705
3706
0
  if (result == ISC_R_SUCCESS &&
3707
0
      qpdbiter->node->nspace == DNS_DBNAMESPACE_NORMAL)
3708
0
  {
3709
0
    dns_name_copy(&qpdbiter->node->name, qpdbiter->name);
3710
0
    reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
3711
0
  } else if (result == ISC_R_SUCCESS) {
3712
0
    result = ISC_R_NOMORE;
3713
0
    qpdbiter->node = NULL;
3714
0
  } else {
3715
0
    INSIST(result == ISC_R_NOMORE);
3716
0
    qpdbiter->node = NULL;
3717
0
  }
3718
3719
0
  qpdbiter->result = result;
3720
0
  return result;
3721
0
}
3722
3723
static isc_result_t
3724
dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
3725
0
       dns_name_t *name DNS__DB_FLARG) {
3726
0
  qpcache_t *qpdb = (qpcache_t *)iterator->db;
3727
0
  qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
3728
0
  qpcnode_t *node = qpdbiter->node;
3729
3730
0
  REQUIRE(qpdbiter->result == ISC_R_SUCCESS);
3731
0
  REQUIRE(node != NULL);
3732
3733
0
  if (qpdbiter->paused) {
3734
0
    resume_iteration(qpdbiter, false);
3735
0
  }
3736
3737
0
  if (name != NULL) {
3738
0
    dns_name_copy(&node->name, name);
3739
0
  }
3740
3741
0
  qpcnode_acquire(qpdb, node, isc_rwlocktype_none,
3742
0
      qpdbiter->tree_locked DNS__DB_FLARG_PASS);
3743
3744
0
  *nodep = (dns_dbnode_t *)qpdbiter->node;
3745
0
  return ISC_R_SUCCESS;
3746
0
}
3747
3748
static isc_result_t
3749
0
dbiterator_pause(dns_dbiterator_t *iterator) {
3750
0
  qpcache_t *qpdb = (qpcache_t *)iterator->db;
3751
0
  qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
3752
3753
0
  if (qpdbiter->result != ISC_R_SUCCESS &&
3754
0
      qpdbiter->result != ISC_R_NOTFOUND &&
3755
0
      qpdbiter->result != DNS_R_PARTIALMATCH &&
3756
0
      qpdbiter->result != ISC_R_NOMORE)
3757
0
  {
3758
0
    return qpdbiter->result;
3759
0
  }
3760
3761
0
  if (qpdbiter->paused) {
3762
0
    return ISC_R_SUCCESS;
3763
0
  }
3764
3765
0
  qpdbiter->paused = true;
3766
3767
0
  if (qpdbiter->tree_locked == isc_rwlocktype_read) {
3768
0
    TREE_UNLOCK(&qpdb->tree_lock, &qpdbiter->tree_locked);
3769
0
  }
3770
0
  INSIST(qpdbiter->tree_locked == isc_rwlocktype_none);
3771
3772
0
  return ISC_R_SUCCESS;
3773
0
}
3774
3775
static isc_result_t
3776
0
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
3777
0
  qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
3778
3779
0
  if (qpdbiter->result != ISC_R_SUCCESS) {
3780
0
    return qpdbiter->result;
3781
0
  }
3782
3783
0
  dns_name_copy(dns_rootname, name);
3784
0
  return ISC_R_SUCCESS;
3785
0
}
3786
3787
static void
3788
0
qpcnode_deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) {
3789
0
  dns_slabheader_t *header = data;
3790
0
  qpcache_t *qpdb = HEADERNODE(header)->qpdb;
3791
3792
0
  if (header->heap != NULL && header->heap_index != 0) {
3793
0
    isc_heap_delete(header->heap, header->heap_index);
3794
0
  }
3795
3796
  /*
3797
   * This place is the only place where we actually need header->typepair.
3798
   */
3799
0
  update_rrsetstats(qpdb->rrsetstats, header->typepair,
3800
0
        atomic_load_acquire(&header->attributes), false);
3801
3802
0
  if (header->noqname != NULL) {
3803
0
    dns_slabheader_freeproof(qpdb->common.mctx, &header->noqname);
3804
0
  }
3805
0
  if (header->closest != NULL) {
3806
0
    dns_slabheader_freeproof(qpdb->common.mctx, &header->closest);
3807
0
  }
3808
0
}
3809
3810
/*
3811
 * Caller must be holding the node write lock.
3812
 */
3813
static void
3814
expire_ttl_headers(qpcache_t *qpdb, unsigned int locknum,
3815
       isc_rwlocktype_t *nlocktypep, isc_rwlocktype_t *tlocktypep,
3816
0
       isc_stdtime_t now DNS__DB_FLARG) {
3817
0
  isc_heap_t *heap = qpdb->buckets[locknum].heap;
3818
3819
0
  for (size_t i = 0; i < DNS_QPDB_EXPIRE_TTL_COUNT; i++) {
3820
0
    dns_slabheader_t *header = isc_heap_element(heap, 1);
3821
3822
0
    if (header == NULL) {
3823
      /* No headers left on this TTL heap; exit cleaning */
3824
0
      return;
3825
0
    }
3826
3827
0
    dns_ttl_t ttl = header->expire + STALE_TTL(header, qpdb);
3828
3829
0
    if (ttl >= now - QPDB_VIRTUAL) {
3830
      /*
3831
       * The header at the top of this TTL heap is not yet
3832
       * eligible for expiry, so none of the other headers on
3833
       * the same heap can be eligible for expiry, either;
3834
       * exit cleaning.
3835
       */
3836
0
      return;
3837
0
    }
3838
3839
0
    (void)expireheader(header, nlocktypep, tlocktypep,
3840
0
           dns_expire_ttl DNS__DB_FLARG_PASS);
3841
0
  }
3842
0
}
3843
3844
static void
3845
0
setmaxrrperset(dns_db_t *db, uint32_t value) {
3846
0
  qpcache_t *qpdb = (qpcache_t *)db;
3847
3848
0
  REQUIRE(VALID_QPDB(qpdb));
3849
3850
0
  qpdb->maxrrperset = value;
3851
0
}
3852
3853
static void
3854
0
setmaxtypepername(dns_db_t *db, uint32_t value) {
3855
0
  qpcache_t *qpdb = (qpcache_t *)db;
3856
3857
0
  REQUIRE(VALID_QPDB(qpdb));
3858
3859
0
  qpdb->maxtypepername = value;
3860
0
}
3861
3862
static dns_dbmethods_t qpdb_cachemethods = {
3863
  .destroy = qpcache_destroy,
3864
  .findnode = qpcache_findnode,
3865
  .find = qpcache_find,
3866
  .findzonecut = qpcache_findzonecut,
3867
  .createiterator = qpcache_createiterator,
3868
  .findrdataset = qpcache_findrdataset,
3869
  .allrdatasets = qpcache_allrdatasets,
3870
  .addrdataset = qpcache_addrdataset,
3871
  .deleterdataset = qpcache_deleterdataset,
3872
  .nodecount = nodecount,
3873
  .getrrsetstats = getrrsetstats,
3874
  .setcachestats = setcachestats,
3875
  .setservestalettl = setservestalettl,
3876
  .getservestalettl = getservestalettl,
3877
  .setservestalerefresh = setservestalerefresh,
3878
  .getservestalerefresh = getservestalerefresh,
3879
  .setmaxrrperset = setmaxrrperset,
3880
  .setmaxtypepername = setmaxtypepername,
3881
};
3882
3883
static void
3884
0
qpcnode_destroy(qpcnode_t *qpnode) {
3885
0
  qpcache_t *qpdb = qpnode->qpdb;
3886
3887
0
  DNS_SLABTOP_FOREACH(top, qpnode->data) {
3888
0
    dns_slabheader_t *header = NULL, *header_next = NULL;
3889
0
    cds_list_for_each_entry_safe(header, header_next, &top->headers,
3890
0
               headers_link)
3891
0
    {
3892
0
      cds_list_del(&header->headers_link);
3893
0
      dns_slabheader_destroy(&header);
3894
0
    }
3895
3896
0
    if (ISC_SIEVE_LINKED(top, link)) {
3897
0
      ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve,
3898
0
           top, link);
3899
0
    }
3900
0
    dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top);
3901
0
  }
3902
3903
0
  dns_name_free(&qpnode->name, qpnode->mctx);
3904
0
  isc_mem_putanddetach(&qpnode->mctx, qpnode, sizeof(qpcnode_t));
3905
0
}
3906
3907
#ifdef DNS_DB_NODETRACE
3908
ISC_REFCOUNT_STATIC_TRACE_IMPL(qpcnode, qpcnode_destroy);
3909
#else
3910
0
ISC_REFCOUNT_STATIC_IMPL(qpcnode, qpcnode_destroy);
Unexecuted instantiation: qpcache.c:qpcnode_ref
Unexecuted instantiation: qpcache.c:qpcnode_detach
Unexecuted instantiation: qpcache.c:qpcnode_unref
3911
0
#endif
3912
0
3913
0
#ifdef DNS_DB_NODETRACE
3914
0
ISC_REFCOUNT_STATIC_TRACE_IMPL(qpcache, qpcache__destroy);
3915
0
#else
3916
ISC_REFCOUNT_STATIC_IMPL(qpcache, qpcache__destroy);
Unexecuted instantiation: qpcache.c:qpcache_detach
Unexecuted instantiation: qpcache.c:qpcache_unref
Unexecuted instantiation: qpcache.c:qpcache_ref
3917
#endif