Home | History | Annotate | Line # | Download | only in dns
rbtdb.c revision 1.3
      1  1.2  christos /*	$NetBSD: rbtdb.c,v 1.3 2019/01/09 16:55:11 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  1.1  christos  *
      6  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      7  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  1.1  christos  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9  1.1  christos  *
     10  1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     11  1.1  christos  * information regarding copyright ownership.
     12  1.1  christos  */
     13  1.1  christos 
     14  1.1  christos /*! \file */
     15  1.1  christos 
     16  1.1  christos #include <config.h>
     17  1.1  christos 
     18  1.1  christos /* #define inline */
     19  1.1  christos 
     20  1.3  christos #include <inttypes.h>
     21  1.3  christos #include <stdbool.h>
     22  1.1  christos 
     23  1.1  christos #include <isc/crc64.h>
     24  1.1  christos #include <isc/event.h>
     25  1.1  christos #include <isc/heap.h>
     26  1.1  christos #include <isc/file.h>
     27  1.1  christos #include <isc/hex.h>
     28  1.1  christos #include <isc/mem.h>
     29  1.1  christos #include <isc/mutex.h>
     30  1.1  christos #include <isc/once.h>
     31  1.1  christos #include <isc/platform.h>
     32  1.1  christos #include <isc/print.h>
     33  1.1  christos #include <isc/random.h>
     34  1.1  christos #include <isc/refcount.h>
     35  1.1  christos #include <isc/rwlock.h>
     36  1.1  christos #include <isc/serial.h>
     37  1.1  christos #include <isc/socket.h>
     38  1.1  christos #include <isc/stdio.h>
     39  1.1  christos #include <isc/string.h>
     40  1.1  christos #include <isc/task.h>
     41  1.1  christos #include <isc/time.h>
     42  1.1  christos #include <isc/util.h>
     43  1.1  christos #include <isc/hash.h>
     44  1.1  christos 
     45  1.1  christos #include <dns/callbacks.h>
     46  1.1  christos #include <dns/db.h>
     47  1.1  christos #include <dns/dbiterator.h>
     48  1.1  christos #include <dns/events.h>
     49  1.1  christos #include <dns/fixedname.h>
     50  1.1  christos #include <dns/lib.h>
     51  1.1  christos #include <dns/log.h>
     52  1.1  christos #include <dns/masterdump.h>
     53  1.1  christos #include <dns/nsec.h>
     54  1.1  christos #include <dns/nsec3.h>
     55  1.1  christos #include <dns/rbt.h>
     56  1.1  christos #include <dns/rdata.h>
     57  1.1  christos #include <dns/rdataset.h>
     58  1.1  christos #include <dns/rdatasetiter.h>
     59  1.1  christos #include <dns/rdataslab.h>
     60  1.1  christos #include <dns/rdatastruct.h>
     61  1.1  christos #include <dns/result.h>
     62  1.1  christos #include <dns/stats.h>
     63  1.1  christos #include <dns/time.h>
     64  1.1  christos #include <dns/version.h>
     65  1.1  christos #include <dns/view.h>
     66  1.1  christos #include <dns/zone.h>
     67  1.1  christos #include <dns/zonekey.h>
     68  1.1  christos 
     69  1.1  christos #ifndef WIN32
     70  1.1  christos #include <sys/mman.h>
     71  1.1  christos #else
     72  1.1  christos #define PROT_READ	0x01
     73  1.1  christos #define PROT_WRITE	0x02
     74  1.1  christos #define MAP_PRIVATE	0x0002
     75  1.1  christos #define MAP_FAILED	((void *)-1)
     76  1.1  christos #endif
     77  1.1  christos 
     78  1.1  christos #include "rbtdb.h"
     79  1.1  christos 
     80  1.1  christos #define RBTDB_MAGIC                     ISC_MAGIC('R', 'B', 'D', '4')
     81  1.1  christos 
     82  1.1  christos #define CHECK(op) \
     83  1.1  christos 	do { result = (op); \
     84  1.1  christos 		if (result != ISC_R_SUCCESS) goto failure; \
     85  1.2  christos 	} while (/*CONSTCOND*/0)
     86  1.1  christos 
     87  1.1  christos /*
     88  1.1  christos  * This is the map file header for RBTDB images.  It is populated, and then
     89  1.1  christos  * written, as the LAST thing done to the file.  Writing this last (with
     90  1.1  christos  * zeros in the header area initially) will ensure that the header is only
     91  1.1  christos  * valid when the RBTDB image is also valid.
     92  1.1  christos  */
     93  1.1  christos typedef struct rbtdb_file_header rbtdb_file_header_t;
     94  1.1  christos 
     95  1.1  christos /* Header length, always the same size regardless of structure size */
     96  1.1  christos #define RBTDB_HEADER_LENGTH	1024
     97  1.1  christos 
     98  1.1  christos struct rbtdb_file_header {
     99  1.1  christos 	char version1[32];
    100  1.3  christos 	uint32_t ptrsize;
    101  1.1  christos 	unsigned int bigendian:1;
    102  1.3  christos 	uint64_t tree;
    103  1.3  christos 	uint64_t nsec;
    104  1.3  christos 	uint64_t nsec3;
    105  1.1  christos 
    106  1.1  christos 	char version2[32];  		/* repeated; must match version1 */
    107  1.1  christos };
    108  1.1  christos 
    109  1.1  christos 
    110  1.1  christos /*%
    111  1.1  christos  * Note that "impmagic" is not the first four bytes of the struct, so
    112  1.1  christos  * ISC_MAGIC_VALID cannot be used.
    113  1.1  christos  */
    114  1.1  christos #define VALID_RBTDB(rbtdb)      ((rbtdb) != NULL && \
    115  1.1  christos 				 (rbtdb)->common.impmagic == RBTDB_MAGIC)
    116  1.1  christos 
    117  1.3  christos typedef uint32_t                    rbtdb_serial_t;
    118  1.3  christos typedef uint32_t                    rbtdb_rdatatype_t;
    119  1.1  christos 
    120  1.1  christos #define RBTDB_RDATATYPE_BASE(type)      ((dns_rdatatype_t)((type) & 0xFFFF))
    121  1.1  christos #define RBTDB_RDATATYPE_EXT(type)       ((dns_rdatatype_t)((type) >> 16))
    122  1.3  christos #define RBTDB_RDATATYPE_VALUE(base, ext) ((rbtdb_rdatatype_t)(((uint32_t)ext) << 16) | (((uint32_t)base) & 0xffff))
    123  1.1  christos 
    124  1.1  christos #define RBTDB_RDATATYPE_SIGNSEC \
    125  1.1  christos 		RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec)
    126  1.1  christos #define RBTDB_RDATATYPE_SIGNSEC3 \
    127  1.1  christos 		RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec3)
    128  1.1  christos #define RBTDB_RDATATYPE_SIGNS \
    129  1.1  christos 		RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ns)
    130  1.1  christos #define RBTDB_RDATATYPE_SIGCNAME \
    131  1.1  christos 		RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname)
    132  1.1  christos #define RBTDB_RDATATYPE_SIGDNAME \
    133  1.1  christos 		RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname)
    134  1.1  christos #define RBTDB_RDATATYPE_SIGDDS \
    135  1.1  christos 		RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ds)
    136  1.1  christos #define RBTDB_RDATATYPE_NCACHEANY \
    137  1.1  christos 		RBTDB_RDATATYPE_VALUE(0, dns_rdatatype_any)
    138  1.1  christos 
    139  1.1  christos #define RBTDB_INITLOCK(l)       isc_rwlock_init((l), 0, 0)
    140  1.1  christos #define RBTDB_DESTROYLOCK(l)    isc_rwlock_destroy(l)
    141  1.1  christos #define RBTDB_LOCK(l, t)        RWLOCK((l), (t))
    142  1.1  christos #define RBTDB_UNLOCK(l, t)      RWUNLOCK((l), (t))
    143  1.1  christos 
    144  1.1  christos /*
    145  1.1  christos  * Since node locking is sensitive to both performance and memory footprint,
    146  1.1  christos  * we need some trick here.  If we have both high-performance rwlock and
    147  1.1  christos  * high performance and small-memory reference counters, we use rwlock for
    148  1.1  christos  * node lock and isc_refcount for node references.  In this case, we don't have
    149  1.1  christos  * to protect the access to the counters by locks.
    150  1.1  christos  * Otherwise, we simply use ordinary mutex lock for node locking, and use
    151  1.1  christos  * simple integers as reference counters which is protected by the lock.
    152  1.1  christos  * In most cases, we can simply use wrapper macros such as NODE_LOCK and
    153  1.1  christos  * NODE_UNLOCK.  In some other cases, however, we need to protect reference
    154  1.1  christos  * counters first and then protect other parts of a node as read-only data.
    155  1.1  christos  * Special additional macros, NODE_STRONGLOCK(), NODE_WEAKLOCK(), etc, are also
    156  1.1  christos  * provided for these special cases.  When we can use the efficient backend
    157  1.1  christos  * routines, we should only protect the "other members" by NODE_WEAKLOCK(read).
    158  1.1  christos  * Otherwise, we should use NODE_STRONGLOCK() to protect the entire critical
    159  1.1  christos  * section including the access to the reference counter.
    160  1.1  christos  * Note that we cannot use NODE_LOCK()/NODE_UNLOCK() wherever the protected
    161  1.1  christos  * section is also protected by NODE_STRONGLOCK().
    162  1.1  christos  */
    163  1.1  christos typedef isc_rwlock_t nodelock_t;
    164  1.1  christos 
    165  1.1  christos #define NODE_INITLOCK(l)        isc_rwlock_init((l), 0, 0)
    166  1.1  christos #define NODE_DESTROYLOCK(l)     isc_rwlock_destroy(l)
    167  1.1  christos #define NODE_LOCK(l, t)         RWLOCK((l), (t))
    168  1.1  christos #define NODE_UNLOCK(l, t)       RWUNLOCK((l), (t))
    169  1.1  christos #define NODE_TRYUPGRADE(l)      isc_rwlock_tryupgrade(l)
    170  1.3  christos #define NODE_DOWNGRADE(l)   isc_rwlock_downgrade(l)
    171  1.1  christos 
    172  1.1  christos /*%
    173  1.1  christos  * Whether to rate-limit updating the LRU to avoid possible thread contention.
    174  1.1  christos  * Our performance measurement has shown the cost is marginal, so it's defined
    175  1.1  christos  * to be 0 by default either with or without threads.
    176  1.1  christos  */
    177  1.1  christos #ifndef DNS_RBTDB_LIMITLRUUPDATE
    178  1.1  christos #define DNS_RBTDB_LIMITLRUUPDATE 0
    179  1.1  christos #endif
    180  1.1  christos 
    181  1.1  christos /*
    182  1.1  christos  * Allow clients with a virtual time of up to 5 minutes in the past to see
    183  1.1  christos  * records that would have otherwise have expired.
    184  1.1  christos  */
    185  1.1  christos #define RBTDB_VIRTUAL 300
    186  1.1  christos 
    187  1.1  christos struct noqname {
    188  1.1  christos 	dns_name_t 	name;
    189  1.1  christos 	void *     	neg;
    190  1.1  christos 	void *     	negsig;
    191  1.1  christos 	dns_rdatatype_t	type;
    192  1.1  christos };
    193  1.1  christos 
    194  1.1  christos typedef struct rdatasetheader {
    195  1.1  christos 	/*%
    196  1.1  christos 	 * Locked by the owning node's lock.
    197  1.1  christos 	 */
    198  1.1  christos 	rbtdb_serial_t                  serial;
    199  1.1  christos 	dns_ttl_t                       rdh_ttl;
    200  1.1  christos 	rbtdb_rdatatype_t               type;
    201  1.3  christos 	uint16_t                    attributes;
    202  1.1  christos 	dns_trust_t                     trust;
    203  1.1  christos 	struct noqname                  *noqname;
    204  1.1  christos 	struct noqname                  *closest;
    205  1.1  christos 	unsigned int 			is_mmapped : 1;
    206  1.1  christos 	unsigned int 			next_is_relative : 1;
    207  1.1  christos 	unsigned int 			node_is_relative : 1;
    208  1.1  christos 	unsigned int 			resign_lsb : 1;
    209  1.1  christos 	/*%<
    210  1.1  christos 	 * We don't use the LIST macros, because the LIST structure has
    211  1.1  christos 	 * both head and tail pointers, and is doubly linked.
    212  1.1  christos 	 */
    213  1.1  christos 
    214  1.1  christos 	struct rdatasetheader           *next;
    215  1.1  christos 	/*%<
    216  1.1  christos 	 * If this is the top header for an rdataset, 'next' points
    217  1.1  christos 	 * to the top header for the next rdataset (i.e., the next type).
    218  1.1  christos 	 * Otherwise, it points up to the header whose down pointer points
    219  1.1  christos 	 * at this header.
    220  1.1  christos 	 */
    221  1.1  christos 
    222  1.1  christos 	struct rdatasetheader           *down;
    223  1.1  christos 	/*%<
    224  1.1  christos 	 * Points to the header for the next older version of
    225  1.1  christos 	 * this rdataset.
    226  1.1  christos 	 */
    227  1.1  christos 
    228  1.3  christos 	uint32_t                    count;
    229  1.1  christos 	/*%<
    230  1.1  christos 	 * Monotonously increased every time this rdataset is bound so that
    231  1.1  christos 	 * it is used as the base of the starting point in DNS responses
    232  1.1  christos 	 * when the "cyclic" rrset-order is required.  Since the ordering
    233  1.1  christos 	 * should not be so crucial, no lock is set for the counter for
    234  1.1  christos 	 * performance reasons.
    235  1.1  christos 	 */
    236  1.1  christos 
    237  1.1  christos 	dns_rbtnode_t                   *node;
    238  1.1  christos 	isc_stdtime_t                   last_used;
    239  1.1  christos 	ISC_LINK(struct rdatasetheader) link;
    240  1.1  christos 
    241  1.1  christos 	unsigned int                    heap_index;
    242  1.1  christos 	/*%<
    243  1.1  christos 	 * Used for TTL-based cache cleaning.
    244  1.1  christos 	 */
    245  1.1  christos 	isc_stdtime_t                   resign;
    246  1.1  christos 	/*%<
    247  1.1  christos 	 * Case vector.  If the bit is set then the corresponding
    248  1.1  christos 	 * character in the owner name needs to be AND'd with 0x20,
    249  1.1  christos 	 * rendering that character upper case.
    250  1.1  christos 	 */
    251  1.1  christos 	unsigned char			upper[32];
    252  1.1  christos } rdatasetheader_t;
    253  1.1  christos 
    254  1.1  christos typedef ISC_LIST(rdatasetheader_t)      rdatasetheaderlist_t;
    255  1.1  christos typedef ISC_LIST(dns_rbtnode_t)         rbtnodelist_t;
    256  1.1  christos 
    257  1.1  christos #define RDATASET_ATTR_NONEXISTENT       0x0001
    258  1.1  christos /*%< May be potentially served as stale data. */
    259  1.1  christos #define RDATASET_ATTR_STALE             0x0002
    260  1.1  christos #define RDATASET_ATTR_IGNORE            0x0004
    261  1.1  christos #define RDATASET_ATTR_RETAIN            0x0008
    262  1.1  christos #define RDATASET_ATTR_NXDOMAIN          0x0010
    263  1.1  christos #define RDATASET_ATTR_RESIGN            0x0020
    264  1.1  christos #define RDATASET_ATTR_STATCOUNT         0x0040
    265  1.1  christos #define RDATASET_ATTR_OPTOUT            0x0080
    266  1.1  christos #define RDATASET_ATTR_NEGATIVE          0x0100
    267  1.1  christos #define RDATASET_ATTR_PREFETCH          0x0200
    268  1.1  christos #define RDATASET_ATTR_CASESET           0x0400
    269  1.1  christos #define RDATASET_ATTR_ZEROTTL           0x0800
    270  1.1  christos #define RDATASET_ATTR_CASEFULLYLOWER    0x1000
    271  1.1  christos /*%< Ancient - awaiting cleanup. */
    272  1.1  christos #define RDATASET_ATTR_ANCIENT           0x2000
    273  1.1  christos 
    274  1.1  christos /*
    275  1.1  christos  * XXX
    276  1.1  christos  * When the cache will pre-expire data (due to memory low or other
    277  1.1  christos  * situations) before the rdataset's TTL has expired, it MUST
    278  1.1  christos  * respect the RETAIN bit and not expire the data until its TTL is
    279  1.1  christos  * expired.
    280  1.1  christos  */
    281  1.1  christos 
    282  1.1  christos #undef IGNORE                   /* WIN32 winbase.h defines this. */
    283  1.1  christos 
    284  1.1  christos #define EXISTS(header) \
    285  1.1  christos 	(((header)->attributes & RDATASET_ATTR_NONEXISTENT) == 0)
    286  1.1  christos #define NONEXISTENT(header) \
    287  1.1  christos 	(((header)->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
    288  1.1  christos #define IGNORE(header) \
    289  1.1  christos 	(((header)->attributes & RDATASET_ATTR_IGNORE) != 0)
    290  1.1  christos #define RETAIN(header) \
    291  1.1  christos 	(((header)->attributes & RDATASET_ATTR_RETAIN) != 0)
    292  1.1  christos #define NXDOMAIN(header) \
    293  1.1  christos 	(((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
    294  1.1  christos #define STALE(header) \
    295  1.1  christos 	(((header)->attributes & RDATASET_ATTR_STALE) != 0)
    296  1.1  christos #define RESIGN(header) \
    297  1.1  christos 	(((header)->attributes & RDATASET_ATTR_RESIGN) != 0)
    298  1.1  christos #define OPTOUT(header) \
    299  1.1  christos 	(((header)->attributes & RDATASET_ATTR_OPTOUT) != 0)
    300  1.1  christos #define NEGATIVE(header) \
    301  1.1  christos 	(((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0)
    302  1.1  christos #define PREFETCH(header) \
    303  1.1  christos 	(((header)->attributes & RDATASET_ATTR_PREFETCH) != 0)
    304  1.1  christos #define CASESET(header) \
    305  1.1  christos 	(((header)->attributes & RDATASET_ATTR_CASESET) != 0)
    306  1.1  christos #define ZEROTTL(header) \
    307  1.1  christos 	(((header)->attributes & RDATASET_ATTR_ZEROTTL) != 0)
    308  1.1  christos #define CASEFULLYLOWER(header) \
    309  1.1  christos 	(((header)->attributes & RDATASET_ATTR_CASEFULLYLOWER) != 0)
    310  1.1  christos #define ANCIENT(header) \
    311  1.1  christos 	(((header)->attributes & RDATASET_ATTR_ANCIENT) != 0)
    312  1.1  christos 
    313  1.1  christos #define ACTIVE(header, now) \
    314  1.1  christos 	(((header)->rdh_ttl > (now)) || \
    315  1.1  christos 	 ((header)->rdh_ttl == (now) && ZEROTTL(header)))
    316  1.1  christos 
    317  1.1  christos #define DEFAULT_NODE_LOCK_COUNT         7       /*%< Should be prime. */
    318  1.1  christos #define RBTDB_GLUE_TABLE_INIT_SIZE     2U
    319  1.1  christos 
    320  1.1  christos /*%
    321  1.1  christos  * Number of buckets for cache DB entries (locks, LRU lists, TTL heaps).
    322  1.1  christos  * There is a tradeoff issue about configuring this value: if this is too
    323  1.1  christos  * small, it may cause heavier contention between threads; if this is too large,
    324  1.1  christos  * LRU purge algorithm won't work well (entries tend to be purged prematurely).
    325  1.1  christos  * The default value should work well for most environments, but this can
    326  1.1  christos  * also be configurable at compilation time via the
    327  1.1  christos  * DNS_RBTDB_CACHE_NODE_LOCK_COUNT variable.  This value must be larger than
    328  1.1  christos  * 1 due to the assumption of overmem_purge().
    329  1.1  christos  */
    330  1.1  christos #ifdef DNS_RBTDB_CACHE_NODE_LOCK_COUNT
    331  1.1  christos #if DNS_RBTDB_CACHE_NODE_LOCK_COUNT <= 1
    332  1.1  christos #error "DNS_RBTDB_CACHE_NODE_LOCK_COUNT must be larger than 1"
    333  1.1  christos #else
    334  1.1  christos #define DEFAULT_CACHE_NODE_LOCK_COUNT DNS_RBTDB_CACHE_NODE_LOCK_COUNT
    335  1.1  christos #endif
    336  1.1  christos #else
    337  1.1  christos #define DEFAULT_CACHE_NODE_LOCK_COUNT   16
    338  1.1  christos #endif	/* DNS_RBTDB_CACHE_NODE_LOCK_COUNT */
    339  1.1  christos 
    340  1.1  christos typedef struct {
    341  1.1  christos 	nodelock_t                      lock;
    342  1.1  christos 	/* Protected in the refcount routines. */
    343  1.1  christos 	isc_refcount_t                  references;
    344  1.1  christos 	/* Locked by lock. */
    345  1.3  christos 	bool                   exiting;
    346  1.1  christos } rbtdb_nodelock_t;
    347  1.1  christos 
    348  1.1  christos typedef struct rbtdb_changed {
    349  1.1  christos 	dns_rbtnode_t *                 node;
    350  1.3  christos 	bool                   dirty;
    351  1.1  christos 	ISC_LINK(struct rbtdb_changed)  link;
    352  1.1  christos } rbtdb_changed_t;
    353  1.1  christos 
    354  1.1  christos typedef ISC_LIST(rbtdb_changed_t)       rbtdb_changedlist_t;
    355  1.1  christos 
    356  1.1  christos typedef enum {
    357  1.1  christos 	dns_db_insecure,
    358  1.1  christos 	dns_db_partial,
    359  1.1  christos 	dns_db_secure
    360  1.1  christos } dns_db_secure_t;
    361  1.1  christos 
    362  1.1  christos typedef struct dns_rbtdb dns_rbtdb_t;
    363  1.1  christos 
    364  1.1  christos /* Reason for expiring a record from cache */
    365  1.1  christos typedef enum {
    366  1.1  christos 	expire_lru,
    367  1.1  christos 	expire_ttl,
    368  1.1  christos 	expire_flush
    369  1.1  christos } expire_t;
    370  1.1  christos 
    371  1.1  christos typedef struct rbtdb_glue rbtdb_glue_t;
    372  1.1  christos 
    373  1.1  christos typedef struct rbtdb_glue_table_node {
    374  1.1  christos 	struct rbtdb_glue_table_node *next;
    375  1.1  christos 	dns_rbtnode_t		     *node;
    376  1.1  christos 	rbtdb_glue_t		     *glue_list;
    377  1.1  christos } rbtdb_glue_table_node_t;
    378  1.1  christos 
    379  1.1  christos typedef enum {
    380  1.1  christos 	rdataset_ttl_fresh,
    381  1.1  christos 	rdataset_ttl_stale,
    382  1.1  christos 	rdataset_ttl_ancient
    383  1.1  christos } rdataset_ttl_t;
    384  1.1  christos 
    385  1.1  christos typedef struct rbtdb_version {
    386  1.1  christos 	/* Not locked */
    387  1.1  christos 	rbtdb_serial_t                  serial;
    388  1.1  christos 	dns_rbtdb_t *			rbtdb;
    389  1.1  christos 	/*
    390  1.1  christos 	 * Protected in the refcount routines.
    391  1.1  christos 	 * XXXJT: should we change the lock policy based on the refcount
    392  1.1  christos 	 * performance?
    393  1.1  christos 	 */
    394  1.1  christos 	isc_refcount_t                  references;
    395  1.1  christos 	/* Locked by database lock. */
    396  1.3  christos 	bool                   writer;
    397  1.3  christos 	bool                   commit_ok;
    398  1.1  christos 	rbtdb_changedlist_t             changed_list;
    399  1.1  christos 	rdatasetheaderlist_t		resigned_list;
    400  1.1  christos 	ISC_LINK(struct rbtdb_version)  link;
    401  1.1  christos 	dns_db_secure_t			secure;
    402  1.3  christos 	bool			havensec3;
    403  1.1  christos 	/* NSEC3 parameters */
    404  1.1  christos 	dns_hash_t			hash;
    405  1.3  christos 	uint8_t			flags;
    406  1.3  christos 	uint16_t			iterations;
    407  1.3  christos 	uint8_t			salt_length;
    408  1.1  christos 	unsigned char			salt[DNS_NSEC3_SALTSIZE];
    409  1.1  christos 
    410  1.1  christos 	/*
    411  1.1  christos 	 * records and bytes are covered by rwlock.
    412  1.1  christos 	 */
    413  1.1  christos 	isc_rwlock_t                    rwlock;
    414  1.3  christos 	uint64_t			records;
    415  1.3  christos 	uint64_t			bytes;
    416  1.1  christos 
    417  1.1  christos 	isc_rwlock_t                    glue_rwlock;
    418  1.1  christos 	size_t                          glue_table_size;
    419  1.1  christos 	size_t                          glue_table_nodecount;
    420  1.1  christos 	rbtdb_glue_table_node_t         **glue_table;
    421  1.1  christos } rbtdb_version_t;
    422  1.1  christos 
    423  1.1  christos typedef ISC_LIST(rbtdb_version_t)       rbtdb_versionlist_t;
    424  1.1  christos 
    425  1.1  christos struct dns_rbtdb {
    426  1.1  christos 	/* Unlocked. */
    427  1.1  christos 	dns_db_t                        common;
    428  1.1  christos 	/* Locks the data in this struct */
    429  1.1  christos 	isc_rwlock_t                    lock;
    430  1.1  christos 	/* Locks the tree structure (prevents nodes appearing/disappearing) */
    431  1.1  christos 	isc_rwlock_t                    tree_lock;
    432  1.1  christos 	/* Locks for individual tree nodes */
    433  1.1  christos 	unsigned int                    node_lock_count;
    434  1.1  christos 	rbtdb_nodelock_t *              node_locks;
    435  1.1  christos 	dns_rbtnode_t *                 origin_node;
    436  1.1  christos 	dns_rbtnode_t *			nsec3_origin_node;
    437  1.1  christos 	dns_stats_t *			rrsetstats; /* cache DB only */
    438  1.1  christos 	isc_stats_t *			cachestats; /* cache DB only */
    439  1.1  christos 	isc_stats_t *			gluecachestats; /* zone DB only */
    440  1.1  christos 	/* Locked by lock. */
    441  1.1  christos 	unsigned int                    active;
    442  1.1  christos 	isc_refcount_t                  references;
    443  1.1  christos 	unsigned int                    attributes;
    444  1.1  christos 	rbtdb_serial_t                  current_serial;
    445  1.1  christos 	rbtdb_serial_t                  least_serial;
    446  1.1  christos 	rbtdb_serial_t                  next_serial;
    447  1.1  christos 	rbtdb_version_t *               current_version;
    448  1.1  christos 	rbtdb_version_t *               future_version;
    449  1.1  christos 	rbtdb_versionlist_t             open_versions;
    450  1.1  christos 	isc_task_t *                    task;
    451  1.1  christos 	dns_dbnode_t                    *soanode;
    452  1.1  christos 	dns_dbnode_t                    *nsnode;
    453  1.1  christos 
    454  1.1  christos 	/*
    455  1.1  christos 	 * Maximum length of time to keep using a stale answer past its
    456  1.1  christos 	 * normal TTL expiry.
    457  1.1  christos 	*/
    458  1.1  christos 	dns_ttl_t			serve_stale_ttl;
    459  1.1  christos 
    460  1.1  christos 	/*
    461  1.1  christos 	 * This is a linked list used to implement the LRU cache.  There will
    462  1.1  christos 	 * be node_lock_count linked lists here.  Nodes in bucket 1 will be
    463  1.1  christos 	 * placed on the linked list rdatasets[1].
    464  1.1  christos 	 */
    465  1.1  christos 	rdatasetheaderlist_t            *rdatasets;
    466  1.1  christos 
    467  1.1  christos 	/*%
    468  1.1  christos 	 * Temporary storage for stale cache nodes and dynamically deleted
    469  1.1  christos 	 * nodes that await being cleaned up.
    470  1.1  christos 	 */
    471  1.1  christos 	rbtnodelist_t                   *deadnodes;
    472  1.1  christos 
    473  1.1  christos 	/*
    474  1.1  christos 	 * Heaps.  These are used for TTL based expiry in a cache,
    475  1.1  christos 	 * or for zone resigning in a zone DB.  hmctx is the memory
    476  1.1  christos 	 * context to use for the heap (which differs from the main
    477  1.1  christos 	 * database memory context in the case of a cache).
    478  1.1  christos 	 */
    479  1.1  christos 	isc_mem_t			*hmctx;
    480  1.1  christos 	isc_heap_t                      **heaps;
    481  1.1  christos 
    482  1.1  christos 	/*
    483  1.1  christos 	 * Base values for the mmap() code.
    484  1.1  christos 	 */
    485  1.1  christos 	void *				mmap_location;
    486  1.1  christos 	size_t				mmap_size;
    487  1.1  christos 
    488  1.1  christos 	/* Locked by tree_lock. */
    489  1.1  christos 	dns_rbt_t *                     tree;
    490  1.1  christos 	dns_rbt_t *			nsec;
    491  1.1  christos 	dns_rbt_t *			nsec3;
    492  1.1  christos 
    493  1.1  christos 	/* Unlocked */
    494  1.1  christos 	unsigned int                    quantum;
    495  1.1  christos };
    496  1.1  christos 
    497  1.1  christos #define RBTDB_ATTR_LOADED               0x01
    498  1.1  christos #define RBTDB_ATTR_LOADING              0x02
    499  1.1  christos 
    500  1.1  christos #define KEEPSTALE(rbtdb) ((rbtdb)->serve_stale_ttl > 0)
    501  1.1  christos 
    502  1.1  christos /*%
    503  1.1  christos  * Search Context
    504  1.1  christos  */
    505  1.1  christos typedef struct {
    506  1.1  christos 	dns_rbtdb_t *           rbtdb;
    507  1.1  christos 	rbtdb_version_t *       rbtversion;
    508  1.1  christos 	rbtdb_serial_t          serial;
    509  1.1  christos 	unsigned int            options;
    510  1.1  christos 	dns_rbtnodechain_t      chain;
    511  1.3  christos 	bool           copy_name;
    512  1.3  christos 	bool           need_cleanup;
    513  1.3  christos 	bool           wild;
    514  1.1  christos 	dns_rbtnode_t *         zonecut;
    515  1.1  christos 	rdatasetheader_t *      zonecut_rdataset;
    516  1.1  christos 	rdatasetheader_t *      zonecut_sigrdataset;
    517  1.1  christos 	dns_fixedname_t         zonecut_name;
    518  1.1  christos 	isc_stdtime_t           now;
    519  1.1  christos } rbtdb_search_t;
    520  1.1  christos 
    521  1.1  christos /*%
    522  1.1  christos  * Load Context
    523  1.1  christos  */
    524  1.1  christos typedef struct {
    525  1.1  christos 	dns_rbtdb_t *           rbtdb;
    526  1.1  christos 	isc_stdtime_t           now;
    527  1.1  christos } rbtdb_load_t;
    528  1.1  christos 
    529  1.1  christos static void delete_callback(void *data, void *arg);
    530  1.1  christos static void rdataset_disassociate(dns_rdataset_t *rdataset);
    531  1.1  christos static isc_result_t rdataset_first(dns_rdataset_t *rdataset);
    532  1.1  christos static isc_result_t rdataset_next(dns_rdataset_t *rdataset);
    533  1.1  christos static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
    534  1.1  christos static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
    535  1.1  christos static unsigned int rdataset_count(dns_rdataset_t *rdataset);
    536  1.1  christos static isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset,
    537  1.1  christos 					dns_name_t *name,
    538  1.1  christos 					dns_rdataset_t *neg,
    539  1.1  christos 					dns_rdataset_t *negsig);
    540  1.1  christos static isc_result_t rdataset_getclosest(dns_rdataset_t *rdataset,
    541  1.1  christos 					dns_name_t *name,
    542  1.1  christos 					dns_rdataset_t *neg,
    543  1.1  christos 					dns_rdataset_t *negsig);
    544  1.3  christos static inline bool need_headerupdate(rdatasetheader_t *header,
    545  1.1  christos 					      isc_stdtime_t now);
    546  1.1  christos static void update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
    547  1.1  christos 			  isc_stdtime_t now);
    548  1.1  christos static void expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
    549  1.3  christos 			  bool tree_locked, expire_t reason);
    550  1.1  christos static void overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start,
    551  1.3  christos 			  isc_stdtime_t now, bool tree_locked);
    552  1.1  christos static isc_result_t resign_insert(dns_rbtdb_t *rbtdb, int idx,
    553  1.1  christos 				  rdatasetheader_t *newheader);
    554  1.1  christos static void resign_delete(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
    555  1.1  christos 			  rdatasetheader_t *header);
    556  1.1  christos static void prune_tree(isc_task_t *task, isc_event_t *event);
    557  1.1  christos static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
    558  1.1  christos static void rdataset_expire(dns_rdataset_t *rdataset);
    559  1.1  christos static void rdataset_clearprefetch(dns_rdataset_t *rdataset);
    560  1.1  christos static void rdataset_setownercase(dns_rdataset_t *rdataset,
    561  1.1  christos 				  const dns_name_t *name);
    562  1.1  christos static void rdataset_getownercase(const dns_rdataset_t *rdataset,
    563  1.1  christos 				  dns_name_t *name);
    564  1.1  christos static isc_result_t rdataset_addglue(dns_rdataset_t *rdataset,
    565  1.1  christos 				     dns_dbversion_t *version,
    566  1.1  christos 				     dns_message_t *msg);
    567  1.1  christos static void free_gluetable(rbtdb_version_t *version);
    568  1.1  christos 
    569  1.1  christos static dns_rdatasetmethods_t rdataset_methods = {
    570  1.1  christos 	rdataset_disassociate,
    571  1.1  christos 	rdataset_first,
    572  1.1  christos 	rdataset_next,
    573  1.1  christos 	rdataset_current,
    574  1.1  christos 	rdataset_clone,
    575  1.1  christos 	rdataset_count,
    576  1.1  christos 	NULL, /* addnoqname */
    577  1.1  christos 	rdataset_getnoqname,
    578  1.1  christos 	NULL, /* addclosest */
    579  1.1  christos 	rdataset_getclosest,
    580  1.1  christos 	rdataset_settrust,
    581  1.1  christos 	rdataset_expire,
    582  1.1  christos 	rdataset_clearprefetch,
    583  1.1  christos 	rdataset_setownercase,
    584  1.1  christos 	rdataset_getownercase,
    585  1.1  christos 	rdataset_addglue
    586  1.1  christos };
    587  1.1  christos 
    588  1.1  christos static dns_rdatasetmethods_t slab_methods = {
    589  1.1  christos 	rdataset_disassociate,
    590  1.1  christos 	rdataset_first,
    591  1.1  christos 	rdataset_next,
    592  1.1  christos 	rdataset_current,
    593  1.1  christos 	rdataset_clone,
    594  1.1  christos 	rdataset_count,
    595  1.1  christos 	NULL, /* addnoqname */
    596  1.1  christos 	NULL, /* getnoqname */
    597  1.1  christos 	NULL, /* addclosest */
    598  1.1  christos 	NULL, /* getclosest */
    599  1.1  christos 	NULL, /* settrust */
    600  1.1  christos 	NULL, /* expire */
    601  1.1  christos 	NULL, /* clearprefetch */
    602  1.1  christos 	NULL, /* setownercase */
    603  1.1  christos 	NULL, /* getownercase */
    604  1.1  christos 	NULL  /* addglue */
    605  1.1  christos };
    606  1.1  christos 
    607  1.1  christos static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
    608  1.1  christos static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);
    609  1.1  christos static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);
    610  1.1  christos static void rdatasetiter_current(dns_rdatasetiter_t *iterator,
    611  1.1  christos 				 dns_rdataset_t *rdataset);
    612  1.1  christos 
    613  1.1  christos static dns_rdatasetitermethods_t rdatasetiter_methods = {
    614  1.1  christos 	rdatasetiter_destroy,
    615  1.1  christos 	rdatasetiter_first,
    616  1.1  christos 	rdatasetiter_next,
    617  1.1  christos 	rdatasetiter_current
    618  1.1  christos };
    619  1.1  christos 
    620  1.1  christos typedef struct rbtdb_rdatasetiter {
    621  1.1  christos 	dns_rdatasetiter_t              common;
    622  1.1  christos 	rdatasetheader_t *              current;
    623  1.1  christos } rbtdb_rdatasetiter_t;
    624  1.1  christos 
    625  1.1  christos /*
    626  1.1  christos  * Note that these iterators, unless created with either DNS_DB_NSEC3ONLY or
    627  1.1  christos  * DNS_DB_NONSEC3, will transparently move between the last node of the
    628  1.1  christos  * "regular" RBT ("chain" field) and the root node of the NSEC3 RBT
    629  1.1  christos  * ("nsec3chain" field) of the database in question, as if the latter was a
    630  1.1  christos  * successor to the former in lexical order.  The "current" field always holds
    631  1.1  christos  * the address of either "chain" or "nsec3chain", depending on which RBT is
    632  1.1  christos  * being traversed at given time.
    633  1.1  christos  */
    634  1.1  christos static void             dbiterator_destroy(dns_dbiterator_t **iteratorp);
    635  1.1  christos static isc_result_t     dbiterator_first(dns_dbiterator_t *iterator);
    636  1.1  christos static isc_result_t     dbiterator_last(dns_dbiterator_t *iterator);
    637  1.1  christos static isc_result_t     dbiterator_seek(dns_dbiterator_t *iterator,
    638  1.1  christos 					const dns_name_t *name);
    639  1.1  christos static isc_result_t     dbiterator_prev(dns_dbiterator_t *iterator);
    640  1.1  christos static isc_result_t     dbiterator_next(dns_dbiterator_t *iterator);
    641  1.1  christos static isc_result_t     dbiterator_current(dns_dbiterator_t *iterator,
    642  1.1  christos 					   dns_dbnode_t **nodep,
    643  1.1  christos 					   dns_name_t *name);
    644  1.1  christos static isc_result_t     dbiterator_pause(dns_dbiterator_t *iterator);
    645  1.1  christos static isc_result_t     dbiterator_origin(dns_dbiterator_t *iterator,
    646  1.1  christos 					  dns_name_t *name);
    647  1.1  christos 
    648  1.1  christos static dns_dbiteratormethods_t dbiterator_methods = {
    649  1.1  christos 	dbiterator_destroy,
    650  1.1  christos 	dbiterator_first,
    651  1.1  christos 	dbiterator_last,
    652  1.1  christos 	dbiterator_seek,
    653  1.1  christos 	dbiterator_prev,
    654  1.1  christos 	dbiterator_next,
    655  1.1  christos 	dbiterator_current,
    656  1.1  christos 	dbiterator_pause,
    657  1.1  christos 	dbiterator_origin
    658  1.1  christos };
    659  1.1  christos 
    660  1.1  christos #define DELETION_BATCH_MAX 64
    661  1.1  christos 
    662  1.1  christos /*
    663  1.3  christos  * If 'paused' is true, then the tree lock is not being held.
    664  1.1  christos  */
    665  1.1  christos typedef struct rbtdb_dbiterator {
    666  1.1  christos 	dns_dbiterator_t                common;
    667  1.3  christos 	bool                   paused;
    668  1.3  christos 	bool                   new_origin;
    669  1.1  christos 	isc_rwlocktype_t                tree_locked;
    670  1.1  christos 	isc_result_t                    result;
    671  1.1  christos 	dns_fixedname_t                 name;
    672  1.1  christos 	dns_fixedname_t                 origin;
    673  1.1  christos 	dns_rbtnodechain_t              chain;
    674  1.1  christos 	dns_rbtnodechain_t		nsec3chain;
    675  1.1  christos 	dns_rbtnodechain_t		*current;
    676  1.1  christos 	dns_rbtnode_t                   *node;
    677  1.1  christos 	dns_rbtnode_t                   *deletions[DELETION_BATCH_MAX];
    678  1.1  christos 	int                             delcnt;
    679  1.3  christos 	bool			nsec3only;
    680  1.3  christos 	bool			nonsec3;
    681  1.1  christos } rbtdb_dbiterator_t;
    682  1.1  christos 
    683  1.1  christos 
    684  1.1  christos #define IS_STUB(rbtdb)  (((rbtdb)->common.attributes & DNS_DBATTR_STUB)  != 0)
    685  1.1  christos #define IS_CACHE(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_CACHE) != 0)
    686  1.1  christos 
    687  1.3  christos static void free_rbtdb(dns_rbtdb_t *rbtdb, bool log,
    688  1.1  christos 		       isc_event_t *event);
    689  1.3  christos static void overmem(dns_db_t *db, bool over);
    690  1.1  christos static void setnsec3parameters(dns_db_t *db, rbtdb_version_t *version);
    691  1.1  christos static void setownercase(rdatasetheader_t *header, const dns_name_t *name);
    692  1.1  christos 
    693  1.3  christos static bool match_header_version(rbtdb_file_header_t *header);
    694  1.1  christos 
    695  1.1  christos /* Pad to 32 bytes */
    696  1.1  christos static char FILE_VERSION[32] = "\0";
    697  1.1  christos 
    698  1.1  christos /*%
    699  1.1  christos  * 'init_count' is used to initialize 'newheader->count' which inturn
    700  1.1  christos  * is used to determine where in the cycle rrset-order cyclic starts.
    701  1.1  christos  * We don't lock this as we don't care about simultaneous updates.
    702  1.1  christos  *
    703  1.1  christos  * Note:
    704  1.3  christos  *      Both init_count and header->count can be UINT32_MAX.
    705  1.1  christos  *      The count on the returned rdataset however can't be as
    706  1.1  christos  *      that indicates that the database does not implement cyclic
    707  1.1  christos  *      processing.
    708  1.1  christos  */
    709  1.1  christos static unsigned int init_count;
    710  1.1  christos 
    711  1.1  christos /*
    712  1.1  christos  * Locking
    713  1.1  christos  *
    714  1.1  christos  * If a routine is going to lock more than one lock in this module, then
    715  1.1  christos  * the locking must be done in the following order:
    716  1.1  christos  *
    717  1.1  christos  *      Tree Lock
    718  1.1  christos  *
    719  1.1  christos  *      Node Lock       (Only one from the set may be locked at one time by
    720  1.1  christos  *                       any caller)
    721  1.1  christos  *
    722  1.1  christos  *      Database Lock
    723  1.1  christos  *
    724  1.1  christos  * Failure to follow this hierarchy can result in deadlock.
    725  1.1  christos  */
    726  1.1  christos 
    727  1.1  christos /*
    728  1.1  christos  * Deleting Nodes
    729  1.1  christos  *
    730  1.1  christos  * For zone databases the node for the origin of the zone MUST NOT be deleted.
    731  1.1  christos  */
    732  1.1  christos 
    733  1.1  christos /*
    734  1.1  christos  * Debugging routines
    735  1.1  christos  */
    736  1.1  christos #ifdef DEBUG
    737  1.1  christos static void
    738  1.1  christos hexdump(const char *desc, unsigned char *data, size_t size) {
    739  1.1  christos 	char hexdump[BUFSIZ * 2 + 1];
    740  1.1  christos 	isc_buffer_t b;
    741  1.1  christos 	isc_region_t r;
    742  1.1  christos 	isc_result_t result;
    743  1.1  christos 	size_t bytes;
    744  1.1  christos 
    745  1.1  christos 	fprintf(stderr, "%s: ", desc);
    746  1.1  christos 	do {
    747  1.1  christos 		isc_buffer_init(&b, hexdump, sizeof(hexdump));
    748  1.1  christos 		r.base = data;
    749  1.1  christos 		r.length = bytes = (size > BUFSIZ) ? BUFSIZ : size;
    750  1.1  christos 		result = isc_hex_totext(&r, 0, "", &b);
    751  1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
    752  1.1  christos 		isc_buffer_putuint8(&b, 0);
    753  1.1  christos 		fprintf(stderr, "%s", hexdump);
    754  1.1  christos 		data += bytes;
    755  1.1  christos 		size -= bytes;
    756  1.1  christos 	} while (size > 0);
    757  1.1  christos 	fprintf(stderr, "\n");
    758  1.1  christos }
    759  1.1  christos #endif
    760  1.1  christos 
    761  1.1  christos 
    762  1.1  christos /*
    763  1.1  christos  * DB Routines
    764  1.1  christos  */
    765  1.1  christos 
    766  1.1  christos static void
    767  1.1  christos attach(dns_db_t *source, dns_db_t **targetp) {
    768  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)source;
    769  1.1  christos 
    770  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
    771  1.1  christos 
    772  1.3  christos 	isc_refcount_increment(&rbtdb->references);
    773  1.1  christos 
    774  1.1  christos 	*targetp = source;
    775  1.1  christos }
    776  1.1  christos 
    777  1.1  christos static void
    778  1.1  christos free_rbtdb_callback(isc_task_t *task, isc_event_t *event) {
    779  1.1  christos 	dns_rbtdb_t *rbtdb = event->ev_arg;
    780  1.1  christos 
    781  1.1  christos 	UNUSED(task);
    782  1.1  christos 
    783  1.3  christos 	free_rbtdb(rbtdb, true, event);
    784  1.1  christos }
    785  1.1  christos 
    786  1.1  christos static void
    787  1.1  christos update_cachestats(dns_rbtdb_t *rbtdb, isc_result_t result) {
    788  1.1  christos 	INSIST(IS_CACHE(rbtdb));
    789  1.1  christos 
    790  1.1  christos 	if (rbtdb->cachestats == NULL)
    791  1.1  christos 		return;
    792  1.1  christos 
    793  1.1  christos 	switch (result) {
    794  1.1  christos 	case ISC_R_SUCCESS:
    795  1.1  christos 	case DNS_R_CNAME:
    796  1.1  christos 	case DNS_R_DNAME:
    797  1.1  christos 	case DNS_R_DELEGATION:
    798  1.1  christos 	case DNS_R_NCACHENXDOMAIN:
    799  1.1  christos 	case DNS_R_NCACHENXRRSET:
    800  1.1  christos 		isc_stats_increment(rbtdb->cachestats,
    801  1.1  christos 				    dns_cachestatscounter_hits);
    802  1.1  christos 		break;
    803  1.1  christos 	default:
    804  1.1  christos 		isc_stats_increment(rbtdb->cachestats,
    805  1.1  christos 				    dns_cachestatscounter_misses);
    806  1.1  christos 	}
    807  1.1  christos }
    808  1.1  christos 
    809  1.1  christos static void
    810  1.1  christos update_rrsetstats(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
    811  1.3  christos 		  bool increment)
    812  1.1  christos {
    813  1.1  christos 	dns_rdatastatstype_t statattributes = 0;
    814  1.1  christos 	dns_rdatastatstype_t base = 0;
    815  1.1  christos 	dns_rdatastatstype_t type;
    816  1.1  christos 
    817  1.1  christos 	/* At the moment we count statistics only for cache DB */
    818  1.1  christos 	INSIST(IS_CACHE(rbtdb));
    819  1.1  christos 
    820  1.1  christos 	if (NEGATIVE(header)) {
    821  1.1  christos 		if (NXDOMAIN(header))
    822  1.1  christos 			statattributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN;
    823  1.1  christos 		else {
    824  1.1  christos 			statattributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
    825  1.1  christos 			base = RBTDB_RDATATYPE_EXT(header->type);
    826  1.1  christos 		}
    827  1.1  christos 	} else
    828  1.1  christos 		base = RBTDB_RDATATYPE_BASE(header->type);
    829  1.1  christos 
    830  1.1  christos 	if (STALE(header))
    831  1.1  christos 		statattributes |= DNS_RDATASTATSTYPE_ATTR_STALE;
    832  1.1  christos 
    833  1.1  christos 	type = DNS_RDATASTATSTYPE_VALUE(base, statattributes);
    834  1.1  christos 	if (increment)
    835  1.1  christos 		dns_rdatasetstats_increment(rbtdb->rrsetstats, type);
    836  1.1  christos 	else
    837  1.1  christos 		dns_rdatasetstats_decrement(rbtdb->rrsetstats, type);
    838  1.1  christos }
    839  1.1  christos 
    840  1.1  christos static void
    841  1.1  christos set_ttl(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, dns_ttl_t newttl) {
    842  1.1  christos 	int idx;
    843  1.1  christos 	isc_heap_t *heap;
    844  1.1  christos 	dns_ttl_t oldttl;
    845  1.1  christos 
    846  1.1  christos 
    847  1.1  christos 	if (!IS_CACHE(rbtdb)) {
    848  1.1  christos 		header->rdh_ttl = newttl;
    849  1.1  christos 		return;
    850  1.1  christos 	}
    851  1.1  christos 
    852  1.1  christos 	oldttl = header->rdh_ttl;
    853  1.1  christos 	header->rdh_ttl = newttl;
    854  1.1  christos 
    855  1.1  christos 	/*
    856  1.1  christos 	 * It's possible the rbtdb is not a cache.  If this is the case,
    857  1.1  christos 	 * we will not have a heap, and we move on.  If we do, though,
    858  1.1  christos 	 * we might need to adjust things.
    859  1.1  christos 	 */
    860  1.1  christos 	if (header->heap_index == 0 || newttl == oldttl)
    861  1.1  christos 		return;
    862  1.1  christos 	idx = header->node->locknum;
    863  1.1  christos 	if (rbtdb->heaps == NULL || rbtdb->heaps[idx] == NULL)
    864  1.1  christos 	    return;
    865  1.1  christos 	heap = rbtdb->heaps[idx];
    866  1.1  christos 
    867  1.1  christos 	if (newttl < oldttl)
    868  1.1  christos 		isc_heap_increased(heap, header->heap_index);
    869  1.1  christos 	else
    870  1.1  christos 		isc_heap_decreased(heap, header->heap_index);
    871  1.1  christos }
    872  1.1  christos 
    873  1.1  christos /*%
    874  1.1  christos  * These functions allow the heap code to rank the priority of each
    875  1.3  christos  * element.  It returns true if v1 happens "sooner" than v2.
    876  1.1  christos  */
    877  1.3  christos static bool
    878  1.1  christos ttl_sooner(void *v1, void *v2) {
    879  1.1  christos 	rdatasetheader_t *h1 = v1;
    880  1.1  christos 	rdatasetheader_t *h2 = v2;
    881  1.1  christos 
    882  1.3  christos 	return (h1->rdh_ttl < h2->rdh_ttl);
    883  1.1  christos }
    884  1.1  christos 
    885  1.3  christos static bool
    886  1.1  christos resign_sooner(void *v1, void *v2) {
    887  1.1  christos 	rdatasetheader_t *h1 = v1;
    888  1.1  christos 	rdatasetheader_t *h2 = v2;
    889  1.1  christos 
    890  1.3  christos 	return (h1->resign < h2->resign ||
    891  1.3  christos 		(h1->resign == h2->resign &&
    892  1.3  christos 		 h1->resign_lsb < h2->resign_lsb));
    893  1.1  christos }
    894  1.1  christos 
    895  1.1  christos /*%
    896  1.1  christos  * This function sets the heap index into the header.
    897  1.1  christos  */
    898  1.1  christos static void
    899  1.1  christos set_index(void *what, unsigned int idx) {
    900  1.1  christos 	rdatasetheader_t *h = what;
    901  1.1  christos 
    902  1.1  christos 	h->heap_index = idx;
    903  1.1  christos }
    904  1.1  christos 
    905  1.1  christos /*%
    906  1.1  christos  * Work out how many nodes can be deleted in the time between two
    907  1.1  christos  * requests to the nameserver.  Smooth the resulting number and use it
    908  1.1  christos  * as a estimate for the number of nodes to be deleted in the next
    909  1.1  christos  * iteration.
    910  1.1  christos  */
    911  1.1  christos static unsigned int
    912  1.1  christos adjust_quantum(unsigned int old, isc_time_t *start) {
    913  1.1  christos 	unsigned int pps = dns_pps;     /* packets per second */
    914  1.1  christos 	unsigned int interval;
    915  1.3  christos 	uint64_t usecs;
    916  1.1  christos 	isc_time_t end;
    917  1.1  christos 	unsigned int nodes;
    918  1.1  christos 
    919  1.1  christos 	if (pps < 100)
    920  1.1  christos 		pps = 100;
    921  1.1  christos 	isc_time_now(&end);
    922  1.1  christos 
    923  1.1  christos 	interval = 1000000 / pps;       /* interval in usec */
    924  1.1  christos 	if (interval == 0)
    925  1.1  christos 		interval = 1;
    926  1.1  christos 	usecs = isc_time_microdiff(&end, start);
    927  1.1  christos 	if (usecs == 0) {
    928  1.1  christos 		/*
    929  1.1  christos 		 * We were unable to measure the amount of time taken.
    930  1.1  christos 		 * Double the nodes deleted next time.
    931  1.1  christos 		 */
    932  1.1  christos 		old *= 2;
    933  1.1  christos 		if (old > 1000)
    934  1.1  christos 			old = 1000;
    935  1.1  christos 		return (old);
    936  1.1  christos 	}
    937  1.1  christos 	nodes = old * interval;
    938  1.1  christos 	nodes /= (unsigned int)usecs;
    939  1.1  christos 	if (nodes == 0)
    940  1.1  christos 		nodes = 1;
    941  1.1  christos 	else if (nodes > 1000)
    942  1.1  christos 		nodes = 1000;
    943  1.1  christos 
    944  1.1  christos 	/* Smooth */
    945  1.1  christos 	nodes = (nodes + old * 3) / 4;
    946  1.1  christos 
    947  1.1  christos 	if (nodes != old)
    948  1.1  christos 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
    949  1.1  christos 			      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
    950  1.1  christos 			      "adjust_quantum: old=%d, new=%d", old, nodes);
    951  1.1  christos 
    952  1.1  christos 	return (nodes);
    953  1.1  christos }
    954  1.1  christos 
    955  1.1  christos static void
    956  1.3  christos free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) {
    957  1.1  christos 	unsigned int i;
    958  1.1  christos 	isc_result_t result;
    959  1.1  christos 	char buf[DNS_NAME_FORMATSIZE];
    960  1.1  christos 	dns_rbt_t **treep;
    961  1.1  christos 	isc_time_t start;
    962  1.1  christos 	dns_dbonupdatelistener_t *listener, *listener_next;
    963  1.1  christos 
    964  1.1  christos 	if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in)
    965  1.3  christos 		overmem((dns_db_t *)rbtdb, (bool)-1);
    966  1.1  christos 
    967  1.1  christos 	REQUIRE(rbtdb->current_version != NULL || EMPTY(rbtdb->open_versions));
    968  1.1  christos 	REQUIRE(rbtdb->future_version == NULL);
    969  1.1  christos 
    970  1.1  christos 	if (rbtdb->current_version != NULL) {
    971  1.1  christos 
    972  1.3  christos 		INSIST(isc_refcount_decrement(
    973  1.3  christos 			       &rbtdb->current_version->references)
    974  1.3  christos 		       == 1);
    975  1.3  christos 
    976  1.1  christos 		UNLINK(rbtdb->open_versions, rbtdb->current_version, link);
    977  1.1  christos 		isc_rwlock_destroy(&rbtdb->current_version->glue_rwlock);
    978  1.1  christos 		isc_refcount_destroy(&rbtdb->current_version->references);
    979  1.1  christos 		isc_rwlock_destroy(&rbtdb->current_version->rwlock);
    980  1.1  christos 		isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
    981  1.1  christos 			    sizeof(rbtdb_version_t));
    982  1.1  christos 	}
    983  1.1  christos 
    984  1.1  christos 	/*
    985  1.1  christos 	 * We assume the number of remaining dead nodes is reasonably small;
    986  1.1  christos 	 * the overhead of unlinking all nodes here should be negligible.
    987  1.1  christos 	 */
    988  1.1  christos 	for (i = 0; i < rbtdb->node_lock_count; i++) {
    989  1.1  christos 		dns_rbtnode_t *node;
    990  1.1  christos 
    991  1.1  christos 		node = ISC_LIST_HEAD(rbtdb->deadnodes[i]);
    992  1.1  christos 		while (node != NULL) {
    993  1.1  christos 			ISC_LIST_UNLINK(rbtdb->deadnodes[i], node, deadlink);
    994  1.1  christos 			node = ISC_LIST_HEAD(rbtdb->deadnodes[i]);
    995  1.1  christos 		}
    996  1.1  christos 	}
    997  1.1  christos 
    998  1.1  christos 	if (event == NULL)
    999  1.1  christos 		rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0;
   1000  1.1  christos 
   1001  1.1  christos 	for (;;) {
   1002  1.1  christos 		/*
   1003  1.1  christos 		 * pick the next tree to (start to) destroy
   1004  1.1  christos 		 */
   1005  1.1  christos 		treep = &rbtdb->tree;
   1006  1.1  christos 		if (*treep == NULL) {
   1007  1.1  christos 			treep = &rbtdb->nsec;
   1008  1.1  christos 			if (*treep == NULL) {
   1009  1.1  christos 				treep = &rbtdb->nsec3;
   1010  1.1  christos 				/*
   1011  1.1  christos 				 * we're finished after clear cutting
   1012  1.1  christos 				 */
   1013  1.1  christos 				if (*treep == NULL)
   1014  1.1  christos 					break;
   1015  1.1  christos 			}
   1016  1.1  christos 		}
   1017  1.1  christos 
   1018  1.1  christos 		isc_time_now(&start);
   1019  1.1  christos 		result = dns_rbt_destroy2(treep, rbtdb->quantum);
   1020  1.1  christos 		if (result == ISC_R_QUOTA) {
   1021  1.1  christos 			INSIST(rbtdb->task != NULL);
   1022  1.1  christos 			if (rbtdb->quantum != 0)
   1023  1.1  christos 				rbtdb->quantum = adjust_quantum(rbtdb->quantum,
   1024  1.1  christos 								&start);
   1025  1.1  christos 			if (event == NULL)
   1026  1.1  christos 				event = isc_event_allocate(rbtdb->common.mctx,
   1027  1.1  christos 							   NULL,
   1028  1.1  christos 							 DNS_EVENT_FREESTORAGE,
   1029  1.1  christos 							   free_rbtdb_callback,
   1030  1.1  christos 							   rbtdb,
   1031  1.1  christos 							   sizeof(isc_event_t));
   1032  1.1  christos 			if (event == NULL)
   1033  1.1  christos 				continue;
   1034  1.1  christos 			isc_task_send(rbtdb->task, &event);
   1035  1.1  christos 			return;
   1036  1.1  christos 		}
   1037  1.1  christos 		INSIST(result == ISC_R_SUCCESS && *treep == NULL);
   1038  1.1  christos 	}
   1039  1.1  christos 
   1040  1.1  christos 	if (event != NULL)
   1041  1.1  christos 		isc_event_free(&event);
   1042  1.1  christos 	if (log) {
   1043  1.1  christos 		if (dns_name_dynamic(&rbtdb->common.origin))
   1044  1.1  christos 			dns_name_format(&rbtdb->common.origin, buf,
   1045  1.1  christos 					sizeof(buf));
   1046  1.1  christos 		else
   1047  1.1  christos 			strlcpy(buf, "<UNKNOWN>", sizeof(buf));
   1048  1.1  christos 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
   1049  1.1  christos 			      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
   1050  1.1  christos 			      "done free_rbtdb(%s)", buf);
   1051  1.1  christos 	}
   1052  1.1  christos 	if (dns_name_dynamic(&rbtdb->common.origin))
   1053  1.1  christos 		dns_name_free(&rbtdb->common.origin, rbtdb->common.mctx);
   1054  1.1  christos 	for (i = 0; i < rbtdb->node_lock_count; i++) {
   1055  1.1  christos 		isc_refcount_destroy(&rbtdb->node_locks[i].references);
   1056  1.1  christos 		NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
   1057  1.1  christos 	}
   1058  1.1  christos 
   1059  1.1  christos 	/*
   1060  1.1  christos 	 * Clean up LRU / re-signing order lists.
   1061  1.1  christos 	 */
   1062  1.1  christos 	if (rbtdb->rdatasets != NULL) {
   1063  1.1  christos 		for (i = 0; i < rbtdb->node_lock_count; i++)
   1064  1.1  christos 			INSIST(ISC_LIST_EMPTY(rbtdb->rdatasets[i]));
   1065  1.1  christos 		isc_mem_put(rbtdb->common.mctx, rbtdb->rdatasets,
   1066  1.1  christos 			    rbtdb->node_lock_count *
   1067  1.1  christos 			    sizeof(rdatasetheaderlist_t));
   1068  1.1  christos 	}
   1069  1.1  christos 	/*
   1070  1.1  christos 	 * Clean up dead node buckets.
   1071  1.1  christos 	 */
   1072  1.1  christos 	if (rbtdb->deadnodes != NULL) {
   1073  1.1  christos 		for (i = 0; i < rbtdb->node_lock_count; i++)
   1074  1.1  christos 			INSIST(ISC_LIST_EMPTY(rbtdb->deadnodes[i]));
   1075  1.1  christos 		isc_mem_put(rbtdb->common.mctx, rbtdb->deadnodes,
   1076  1.1  christos 		    rbtdb->node_lock_count * sizeof(rbtnodelist_t));
   1077  1.1  christos 	}
   1078  1.1  christos 	/*
   1079  1.1  christos 	 * Clean up heap objects.
   1080  1.1  christos 	 */
   1081  1.1  christos 	if (rbtdb->heaps != NULL) {
   1082  1.1  christos 		for (i = 0; i < rbtdb->node_lock_count; i++)
   1083  1.1  christos 			isc_heap_destroy(&rbtdb->heaps[i]);
   1084  1.1  christos 		isc_mem_put(rbtdb->hmctx, rbtdb->heaps,
   1085  1.1  christos 			    rbtdb->node_lock_count * sizeof(isc_heap_t *));
   1086  1.1  christos 	}
   1087  1.1  christos 
   1088  1.1  christos 	if (rbtdb->rrsetstats != NULL)
   1089  1.1  christos 		dns_stats_detach(&rbtdb->rrsetstats);
   1090  1.1  christos 	if (rbtdb->cachestats != NULL)
   1091  1.1  christos 		isc_stats_detach(&rbtdb->cachestats);
   1092  1.1  christos 	if (rbtdb->gluecachestats != NULL)
   1093  1.1  christos 		isc_stats_detach(&rbtdb->gluecachestats);
   1094  1.1  christos 
   1095  1.1  christos 	isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks,
   1096  1.1  christos 		    rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));
   1097  1.1  christos 	isc_rwlock_destroy(&rbtdb->tree_lock);
   1098  1.1  christos 	isc_refcount_destroy(&rbtdb->references);
   1099  1.1  christos 	if (rbtdb->task != NULL)
   1100  1.1  christos 		isc_task_detach(&rbtdb->task);
   1101  1.1  christos 
   1102  1.1  christos 	RBTDB_DESTROYLOCK(&rbtdb->lock);
   1103  1.1  christos 	rbtdb->common.magic = 0;
   1104  1.1  christos 	rbtdb->common.impmagic = 0;
   1105  1.1  christos 	isc_mem_detach(&rbtdb->hmctx);
   1106  1.1  christos 
   1107  1.1  christos 	if (rbtdb->mmap_location != NULL)
   1108  1.1  christos 		isc_file_munmap(rbtdb->mmap_location,
   1109  1.1  christos 				(size_t) rbtdb->mmap_size);
   1110  1.1  christos 
   1111  1.1  christos 	for (listener = ISC_LIST_HEAD(rbtdb->common.update_listeners);
   1112  1.1  christos 	     listener != NULL;
   1113  1.1  christos 	     listener = listener_next)
   1114  1.1  christos 	{
   1115  1.1  christos 		listener_next = ISC_LIST_NEXT(listener, link);
   1116  1.1  christos 		ISC_LIST_UNLINK(rbtdb->common.update_listeners, listener, link);
   1117  1.1  christos 		isc_mem_put(rbtdb->common.mctx, listener,
   1118  1.1  christos 			    sizeof(dns_dbonupdatelistener_t));
   1119  1.1  christos 	}
   1120  1.1  christos 
   1121  1.1  christos 	isc_mem_putanddetach(&rbtdb->common.mctx, rbtdb, sizeof(*rbtdb));
   1122  1.1  christos }
   1123  1.1  christos 
   1124  1.1  christos static inline void
   1125  1.1  christos maybe_free_rbtdb(dns_rbtdb_t *rbtdb) {
   1126  1.3  christos 	bool want_free = false;
   1127  1.1  christos 	unsigned int i;
   1128  1.1  christos 	unsigned int inactive = 0;
   1129  1.1  christos 
   1130  1.1  christos 	/* XXX check for open versions here */
   1131  1.1  christos 
   1132  1.1  christos 	if (rbtdb->soanode != NULL)
   1133  1.1  christos 		dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->soanode);
   1134  1.1  christos 	if (rbtdb->nsnode != NULL)
   1135  1.1  christos 		dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->nsnode);
   1136  1.1  christos 
   1137  1.1  christos 	/*
   1138  1.1  christos 	 * The current version's glue table needs to be freed early
   1139  1.1  christos 	 * so the nodes are dereferenced before we check the active
   1140  1.1  christos 	 * node count below.
   1141  1.1  christos 	 */
   1142  1.1  christos 	if (rbtdb->current_version != NULL) {
   1143  1.1  christos 		free_gluetable(rbtdb->current_version);
   1144  1.1  christos 	}
   1145  1.1  christos 
   1146  1.1  christos 	/*
   1147  1.1  christos 	 * Even though there are no external direct references, there still
   1148  1.1  christos 	 * may be nodes in use.
   1149  1.1  christos 	 */
   1150  1.1  christos 	for (i = 0; i < rbtdb->node_lock_count; i++) {
   1151  1.1  christos 		NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
   1152  1.3  christos 		rbtdb->node_locks[i].exiting = true;
   1153  1.1  christos 		NODE_UNLOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
   1154  1.1  christos 		if (isc_refcount_current(&rbtdb->node_locks[i].references) == 0)
   1155  1.1  christos 		{
   1156  1.1  christos 			inactive++;
   1157  1.1  christos 		}
   1158  1.1  christos 	}
   1159  1.1  christos 
   1160  1.1  christos 	if (inactive != 0) {
   1161  1.1  christos 		RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
   1162  1.1  christos 		rbtdb->active -= inactive;
   1163  1.1  christos 		if (rbtdb->active == 0) {
   1164  1.3  christos 			want_free = true;
   1165  1.1  christos 		}
   1166  1.1  christos 		RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
   1167  1.1  christos 		if (want_free) {
   1168  1.1  christos 			char buf[DNS_NAME_FORMATSIZE];
   1169  1.1  christos 			if (dns_name_dynamic(&rbtdb->common.origin)) {
   1170  1.1  christos 				dns_name_format(&rbtdb->common.origin, buf,
   1171  1.1  christos 						sizeof(buf));
   1172  1.1  christos 			} else {
   1173  1.1  christos 				strlcpy(buf, "<UNKNOWN>", sizeof(buf));
   1174  1.1  christos 			}
   1175  1.1  christos 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
   1176  1.1  christos 				      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
   1177  1.1  christos 				      "calling free_rbtdb(%s)", buf);
   1178  1.3  christos 			free_rbtdb(rbtdb, true, NULL);
   1179  1.1  christos 		}
   1180  1.1  christos 	}
   1181  1.1  christos }
   1182  1.1  christos 
   1183  1.1  christos static void
   1184  1.1  christos detach(dns_db_t **dbp) {
   1185  1.3  christos 	REQUIRE(dbp != NULL && VALID_RBTDB((dns_rbtdb_t *)(*dbp)));
   1186  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(*dbp);
   1187  1.3  christos 	*dbp = NULL;
   1188  1.1  christos 
   1189  1.3  christos 	if (isc_refcount_decrement(&rbtdb->references) == 1) {
   1190  1.3  christos 		(void)isc_refcount_current(&rbtdb->references);
   1191  1.1  christos 		maybe_free_rbtdb(rbtdb);
   1192  1.3  christos 	}
   1193  1.1  christos }
   1194  1.1  christos 
   1195  1.1  christos static void
   1196  1.1  christos currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
   1197  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   1198  1.1  christos 	rbtdb_version_t *version;
   1199  1.1  christos 
   1200  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   1201  1.1  christos 
   1202  1.3  christos 	/* XXXOND: Is the lock needed here? */
   1203  1.1  christos 	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
   1204  1.1  christos 	version = rbtdb->current_version;
   1205  1.3  christos 	isc_refcount_increment(&version->references);
   1206  1.1  christos 	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
   1207  1.1  christos 
   1208  1.1  christos 	*versionp = (dns_dbversion_t *)version;
   1209  1.1  christos }
   1210  1.1  christos 
   1211  1.1  christos static inline rbtdb_version_t *
   1212  1.1  christos allocate_version(isc_mem_t *mctx, rbtdb_serial_t serial,
   1213  1.3  christos 		 unsigned int references, bool writer)
   1214  1.1  christos {
   1215  1.1  christos 	isc_result_t result;
   1216  1.1  christos 	rbtdb_version_t *version;
   1217  1.1  christos 	size_t i;
   1218  1.1  christos 
   1219  1.1  christos 	version = isc_mem_get(mctx, sizeof(*version));
   1220  1.1  christos 	if (version == NULL)
   1221  1.1  christos 		return (NULL);
   1222  1.1  christos 	version->serial = serial;
   1223  1.3  christos 
   1224  1.3  christos 	isc_refcount_init(&version->references, references);
   1225  1.3  christos 
   1226  1.1  christos 	result = isc_rwlock_init(&version->glue_rwlock, 0, 0);
   1227  1.1  christos 	if (result != ISC_R_SUCCESS) {
   1228  1.1  christos 		isc_refcount_destroy(&version->references);
   1229  1.1  christos 		isc_mem_put(mctx, version, sizeof(*version));
   1230  1.1  christos 		return (NULL);
   1231  1.1  christos 	}
   1232  1.1  christos 
   1233  1.1  christos 	version->glue_table_size = RBTDB_GLUE_TABLE_INIT_SIZE;
   1234  1.1  christos 	version->glue_table_nodecount = 0U;
   1235  1.1  christos 	version->glue_table = (rbtdb_glue_table_node_t **)
   1236  1.1  christos 		isc_mem_get(mctx, (version->glue_table_size *
   1237  1.1  christos 				   sizeof(*version->glue_table)));
   1238  1.1  christos 	if (version->glue_table == NULL) {
   1239  1.1  christos 		isc_rwlock_destroy(&version->glue_rwlock);
   1240  1.1  christos 		isc_refcount_destroy(&version->references);
   1241  1.1  christos 		isc_mem_put(mctx, version, sizeof(*version));
   1242  1.1  christos 		return (NULL);
   1243  1.1  christos 	}
   1244  1.1  christos 
   1245  1.1  christos 	version->writer = writer;
   1246  1.3  christos 	version->commit_ok = false;
   1247  1.1  christos 	ISC_LIST_INIT(version->changed_list);
   1248  1.1  christos 	ISC_LIST_INIT(version->resigned_list);
   1249  1.1  christos 	ISC_LINK_INIT(version, link);
   1250  1.1  christos 
   1251  1.1  christos 	for (i = 0; i < version->glue_table_size; i++)
   1252  1.1  christos 		version->glue_table[i] = NULL;
   1253  1.1  christos 
   1254  1.1  christos 	return (version);
   1255  1.1  christos }
   1256  1.1  christos 
   1257  1.1  christos static isc_result_t
   1258  1.1  christos newversion(dns_db_t *db, dns_dbversion_t **versionp) {
   1259  1.1  christos 	isc_result_t result;
   1260  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   1261  1.1  christos 	rbtdb_version_t *version;
   1262  1.1  christos 
   1263  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   1264  1.1  christos 	REQUIRE(versionp != NULL && *versionp == NULL);
   1265  1.1  christos 	REQUIRE(rbtdb->future_version == NULL);
   1266  1.1  christos 
   1267  1.1  christos 	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
   1268  1.1  christos 	RUNTIME_CHECK(rbtdb->next_serial != 0);         /* XXX Error? */
   1269  1.1  christos 	version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1,
   1270  1.3  christos 				   true);
   1271  1.1  christos 	if (version != NULL) {
   1272  1.1  christos 		version->rbtdb = rbtdb;
   1273  1.3  christos 		version->commit_ok = true;
   1274  1.1  christos 		version->secure = rbtdb->current_version->secure;
   1275  1.1  christos 		version->havensec3 = rbtdb->current_version->havensec3;
   1276  1.1  christos 		if (version->havensec3) {
   1277  1.1  christos 			version->flags = rbtdb->current_version->flags;
   1278  1.1  christos 			version->iterations =
   1279  1.1  christos 				rbtdb->current_version->iterations;
   1280  1.1  christos 			version->hash = rbtdb->current_version->hash;
   1281  1.1  christos 			version->salt_length =
   1282  1.1  christos 				rbtdb->current_version->salt_length;
   1283  1.1  christos 			memmove(version->salt, rbtdb->current_version->salt,
   1284  1.1  christos 				version->salt_length);
   1285  1.1  christos 		} else {
   1286  1.1  christos 			version->flags = 0;
   1287  1.1  christos 			version->iterations = 0;
   1288  1.1  christos 			version->hash = 0;
   1289  1.1  christos 			version->salt_length = 0;
   1290  1.1  christos 			memset(version->salt, 0, sizeof(version->salt));
   1291  1.1  christos 		}
   1292  1.1  christos 		result = isc_rwlock_init(&version->rwlock, 0, 0);
   1293  1.1  christos 		if (result != ISC_R_SUCCESS) {
   1294  1.1  christos 			free_gluetable(version);
   1295  1.1  christos 			isc_rwlock_destroy(&version->glue_rwlock);
   1296  1.1  christos 			isc_refcount_destroy(&version->references);
   1297  1.1  christos 			isc_mem_put(rbtdb->common.mctx, version,
   1298  1.1  christos 				    sizeof(*version));
   1299  1.1  christos 			version = NULL;
   1300  1.1  christos 		} else {
   1301  1.1  christos 			RWLOCK(&rbtdb->current_version->rwlock,
   1302  1.1  christos 			       isc_rwlocktype_read);
   1303  1.1  christos 			version->records = rbtdb->current_version->records;
   1304  1.1  christos 			version->bytes = rbtdb->current_version->bytes;
   1305  1.1  christos 			RWUNLOCK(&rbtdb->current_version->rwlock,
   1306  1.1  christos 				 isc_rwlocktype_read);
   1307  1.1  christos 			rbtdb->next_serial++;
   1308  1.1  christos 			rbtdb->future_version = version;
   1309  1.1  christos 		}
   1310  1.1  christos 	} else
   1311  1.1  christos 		result = ISC_R_NOMEMORY;
   1312  1.1  christos 	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
   1313  1.1  christos 
   1314  1.1  christos 	if (version == NULL)
   1315  1.1  christos 		return (result);
   1316  1.1  christos 
   1317  1.1  christos 	*versionp = version;
   1318  1.1  christos 
   1319  1.1  christos 	return (ISC_R_SUCCESS);
   1320  1.1  christos }
   1321  1.1  christos 
   1322  1.1  christos static void
   1323  1.1  christos attachversion(dns_db_t *db, dns_dbversion_t *source,
   1324  1.1  christos 	      dns_dbversion_t **targetp)
   1325  1.1  christos {
   1326  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   1327  1.1  christos 	rbtdb_version_t *rbtversion = source;
   1328  1.1  christos 
   1329  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   1330  1.1  christos 	INSIST(rbtversion != NULL && rbtversion->rbtdb == rbtdb);
   1331  1.1  christos 
   1332  1.3  christos 	isc_refcount_increment(&rbtversion->references);
   1333  1.1  christos 
   1334  1.1  christos 	*targetp = rbtversion;
   1335  1.1  christos }
   1336  1.1  christos 
   1337  1.1  christos static rbtdb_changed_t *
   1338  1.1  christos add_changed(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
   1339  1.1  christos 	    dns_rbtnode_t *node)
   1340  1.1  christos {
   1341  1.1  christos 	rbtdb_changed_t *changed;
   1342  1.1  christos 
   1343  1.1  christos 	/*
   1344  1.1  christos 	 * Caller must be holding the node lock if its reference must be
   1345  1.1  christos 	 * protected by the lock.
   1346  1.1  christos 	 */
   1347  1.1  christos 
   1348  1.1  christos 	changed = isc_mem_get(rbtdb->common.mctx, sizeof(*changed));
   1349  1.1  christos 
   1350  1.1  christos 	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
   1351  1.1  christos 
   1352  1.1  christos 	REQUIRE(version->writer);
   1353  1.1  christos 
   1354  1.1  christos 	if (changed != NULL) {
   1355  1.3  christos 		isc_refcount_increment(&node->references);
   1356  1.1  christos 		changed->node = node;
   1357  1.3  christos 		changed->dirty = false;
   1358  1.1  christos 		ISC_LIST_INITANDAPPEND(version->changed_list, changed, link);
   1359  1.1  christos 	} else
   1360  1.3  christos 		version->commit_ok = false;
   1361  1.1  christos 
   1362  1.1  christos 	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
   1363  1.1  christos 
   1364  1.1  christos 	return (changed);
   1365  1.1  christos }
   1366  1.1  christos 
   1367  1.1  christos static inline void
   1368  1.1  christos free_noqname(isc_mem_t *mctx, struct noqname **noqname) {
   1369  1.1  christos 
   1370  1.1  christos 	if (dns_name_dynamic(&(*noqname)->name))
   1371  1.1  christos 		dns_name_free(&(*noqname)->name, mctx);
   1372  1.1  christos 	if ((*noqname)->neg != NULL)
   1373  1.1  christos 		isc_mem_put(mctx, (*noqname)->neg,
   1374  1.1  christos 			    dns_rdataslab_size((*noqname)->neg, 0));
   1375  1.1  christos 	if ((*noqname)->negsig != NULL)
   1376  1.1  christos 		isc_mem_put(mctx, (*noqname)->negsig,
   1377  1.1  christos 			    dns_rdataslab_size((*noqname)->negsig, 0));
   1378  1.1  christos 	isc_mem_put(mctx, *noqname, sizeof(**noqname));
   1379  1.1  christos 	*noqname = NULL;
   1380  1.1  christos }
   1381  1.1  christos 
   1382  1.1  christos static inline void
   1383  1.1  christos init_rdataset(dns_rbtdb_t *rbtdb, rdatasetheader_t *h) {
   1384  1.1  christos 	ISC_LINK_INIT(h, link);
   1385  1.1  christos 	h->heap_index = 0;
   1386  1.1  christos 	h->is_mmapped = 0;
   1387  1.1  christos 	h->next_is_relative = 0;
   1388  1.1  christos 	h->node_is_relative = 0;
   1389  1.1  christos 
   1390  1.1  christos #if TRACE_HEADER
   1391  1.1  christos 	if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in)
   1392  1.1  christos 		fprintf(stderr, "initialized header: %p\n", h);
   1393  1.1  christos #else
   1394  1.1  christos 	UNUSED(rbtdb);
   1395  1.1  christos #endif
   1396  1.1  christos }
   1397  1.1  christos 
   1398  1.1  christos /*
   1399  1.1  christos  * Update the copied values of 'next' and 'node' if they are relative.
   1400  1.1  christos  */
   1401  1.1  christos static void
   1402  1.1  christos update_newheader(rdatasetheader_t *newh, rdatasetheader_t *old) {
   1403  1.1  christos 	char *p;
   1404  1.1  christos 
   1405  1.1  christos 	if (old->next_is_relative) {
   1406  1.1  christos 		p = (char *) old;
   1407  1.1  christos 		p += (uintptr_t)old->next;
   1408  1.1  christos 		newh->next = (rdatasetheader_t *)p;
   1409  1.1  christos 	}
   1410  1.1  christos 	if (old->node_is_relative) {
   1411  1.1  christos 		p = (char *) old;
   1412  1.1  christos 		p += (uintptr_t)old->node;
   1413  1.1  christos 		newh->node = (dns_rbtnode_t *)p;
   1414  1.1  christos 	}
   1415  1.1  christos 	if (CASESET(old)) {
   1416  1.3  christos 		uint16_t attr;
   1417  1.1  christos 
   1418  1.1  christos 		memmove(newh->upper, old->upper, sizeof(old->upper));
   1419  1.1  christos 		attr = old->attributes & (RDATASET_ATTR_CASESET |
   1420  1.1  christos 					  RDATASET_ATTR_CASEFULLYLOWER);
   1421  1.1  christos 		newh->attributes |= attr;
   1422  1.1  christos 	}
   1423  1.1  christos }
   1424  1.1  christos 
   1425  1.1  christos static inline rdatasetheader_t *
   1426  1.1  christos new_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx) {
   1427  1.1  christos 	rdatasetheader_t *h;
   1428  1.1  christos 
   1429  1.1  christos 	h = isc_mem_get(mctx, sizeof(*h));
   1430  1.1  christos 	if (h == NULL)
   1431  1.1  christos 		return (NULL);
   1432  1.1  christos 
   1433  1.1  christos #if TRACE_HEADER
   1434  1.1  christos 	if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in)
   1435  1.1  christos 		fprintf(stderr, "allocated header: %p\n", h);
   1436  1.1  christos #endif
   1437  1.1  christos 	memset(h->upper, 0xeb, sizeof(h->upper));
   1438  1.1  christos 	init_rdataset(rbtdb, h);
   1439  1.1  christos 	h->rdh_ttl = 0;
   1440  1.1  christos 	return (h);
   1441  1.1  christos }
   1442  1.1  christos 
   1443  1.1  christos static inline void
   1444  1.1  christos free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *rdataset) {
   1445  1.1  christos 	unsigned int size;
   1446  1.1  christos 	int idx;
   1447  1.1  christos 
   1448  1.1  christos 	if (EXISTS(rdataset) &&
   1449  1.1  christos 	    (rdataset->attributes & RDATASET_ATTR_STATCOUNT) != 0) {
   1450  1.3  christos 		update_rrsetstats(rbtdb, rdataset, false);
   1451  1.1  christos 	}
   1452  1.1  christos 
   1453  1.1  christos 	idx = rdataset->node->locknum;
   1454  1.1  christos 	if (ISC_LINK_LINKED(rdataset, link)) {
   1455  1.1  christos 		INSIST(IS_CACHE(rbtdb));
   1456  1.1  christos 		ISC_LIST_UNLINK(rbtdb->rdatasets[idx], rdataset, link);
   1457  1.1  christos 	}
   1458  1.1  christos 
   1459  1.1  christos 	if (rdataset->heap_index != 0)
   1460  1.1  christos 		isc_heap_delete(rbtdb->heaps[idx], rdataset->heap_index);
   1461  1.1  christos 	rdataset->heap_index = 0;
   1462  1.1  christos 
   1463  1.1  christos 	if (rdataset->noqname != NULL)
   1464  1.1  christos 		free_noqname(mctx, &rdataset->noqname);
   1465  1.1  christos 	if (rdataset->closest != NULL)
   1466  1.1  christos 		free_noqname(mctx, &rdataset->closest);
   1467  1.1  christos 
   1468  1.1  christos 	if (NONEXISTENT(rdataset))
   1469  1.1  christos 		size = sizeof(*rdataset);
   1470  1.1  christos 	else
   1471  1.1  christos 		size = dns_rdataslab_size((unsigned char *)rdataset,
   1472  1.1  christos 					  sizeof(*rdataset));
   1473  1.1  christos 
   1474  1.1  christos 	if (rdataset->is_mmapped == 1)
   1475  1.1  christos 		return;
   1476  1.1  christos 
   1477  1.1  christos 	isc_mem_put(mctx, rdataset, size);
   1478  1.1  christos }
   1479  1.1  christos 
   1480  1.1  christos static inline void
   1481  1.1  christos rollback_node(dns_rbtnode_t *node, rbtdb_serial_t serial) {
   1482  1.1  christos 	rdatasetheader_t *header, *dcurrent;
   1483  1.3  christos 	bool make_dirty = false;
   1484  1.1  christos 
   1485  1.1  christos 	/*
   1486  1.1  christos 	 * Caller must hold the node lock.
   1487  1.1  christos 	 */
   1488  1.1  christos 
   1489  1.1  christos 	/*
   1490  1.1  christos 	 * We set the IGNORE attribute on rdatasets with serial number
   1491  1.1  christos 	 * 'serial'.  When the reference count goes to zero, these rdatasets
   1492  1.1  christos 	 * will be cleaned up; until that time, they will be ignored.
   1493  1.1  christos 	 */
   1494  1.1  christos 	for (header = node->data; header != NULL; header = header->next) {
   1495  1.1  christos 		if (header->serial == serial) {
   1496  1.1  christos 			header->attributes |= RDATASET_ATTR_IGNORE;
   1497  1.3  christos 			make_dirty = true;
   1498  1.1  christos 		}
   1499  1.1  christos 		for (dcurrent = header->down;
   1500  1.1  christos 		     dcurrent != NULL;
   1501  1.1  christos 		     dcurrent = dcurrent->down) {
   1502  1.1  christos 			if (dcurrent->serial == serial) {
   1503  1.1  christos 				dcurrent->attributes |= RDATASET_ATTR_IGNORE;
   1504  1.3  christos 				make_dirty = true;
   1505  1.1  christos 			}
   1506  1.1  christos 		}
   1507  1.1  christos 	}
   1508  1.1  christos 	if (make_dirty)
   1509  1.1  christos 		node->dirty = 1;
   1510  1.1  christos }
   1511  1.1  christos 
   1512  1.1  christos static inline void
   1513  1.1  christos mark_header_ancient(dns_rbtdb_t *rbtdb, rdatasetheader_t *header) {
   1514  1.1  christos 
   1515  1.1  christos 	/*
   1516  1.1  christos 	 * If we are already ancient there is nothing to do.
   1517  1.1  christos 	 */
   1518  1.1  christos 	if (ANCIENT(header))
   1519  1.1  christos 		return;
   1520  1.1  christos 
   1521  1.1  christos 	header->attributes |= RDATASET_ATTR_ANCIENT;
   1522  1.1  christos 	header->node->dirty = 1;
   1523  1.1  christos 
   1524  1.1  christos 	/*
   1525  1.1  christos 	 * If we have not been counted then there is nothing to do.
   1526  1.1  christos 	 */
   1527  1.1  christos 	if ((header->attributes & RDATASET_ATTR_STATCOUNT) == 0)
   1528  1.1  christos 		return;
   1529  1.1  christos 
   1530  1.1  christos 	if (EXISTS(header))
   1531  1.3  christos 		update_rrsetstats(rbtdb, header, true);
   1532  1.1  christos }
   1533  1.1  christos 
   1534  1.1  christos static inline void
   1535  1.1  christos clean_stale_headers(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *top)
   1536  1.1  christos {
   1537  1.1  christos 	rdatasetheader_t *d, *down_next;
   1538  1.1  christos 
   1539  1.1  christos 	for (d = top->down; d != NULL; d = down_next) {
   1540  1.1  christos 		down_next = d->down;
   1541  1.1  christos 		free_rdataset(rbtdb, mctx, d);
   1542  1.1  christos 	}
   1543  1.1  christos 	top->down = NULL;
   1544  1.1  christos }
   1545  1.1  christos 
   1546  1.1  christos static inline void
   1547  1.1  christos clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
   1548  1.1  christos 	rdatasetheader_t *current, *top_prev, *top_next;
   1549  1.1  christos 	isc_mem_t *mctx = rbtdb->common.mctx;
   1550  1.1  christos 
   1551  1.1  christos 	/*
   1552  1.1  christos 	 * Caller must be holding the node lock.
   1553  1.1  christos 	 */
   1554  1.1  christos 
   1555  1.1  christos 	top_prev = NULL;
   1556  1.1  christos 	for (current = node->data; current != NULL; current = top_next) {
   1557  1.1  christos 		top_next = current->next;
   1558  1.1  christos 		clean_stale_headers(rbtdb, mctx, current);
   1559  1.1  christos 		/*
   1560  1.1  christos 		 * If current is nonexistent or stale, we can clean it up.
   1561  1.1  christos 		 */
   1562  1.1  christos 		if (NONEXISTENT(current) || ANCIENT(current) ||
   1563  1.1  christos 		    (STALE(current) && ! KEEPSTALE(rbtdb))) {
   1564  1.1  christos 			if (top_prev != NULL)
   1565  1.1  christos 				top_prev->next = current->next;
   1566  1.1  christos 			else
   1567  1.1  christos 				node->data = current->next;
   1568  1.1  christos 			free_rdataset(rbtdb, mctx, current);
   1569  1.1  christos 		} else
   1570  1.1  christos 			top_prev = current;
   1571  1.1  christos 	}
   1572  1.1  christos 	node->dirty = 0;
   1573  1.1  christos }
   1574  1.1  christos 
   1575  1.1  christos static inline void
   1576  1.1  christos clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
   1577  1.1  christos 		rbtdb_serial_t least_serial)
   1578  1.1  christos {
   1579  1.1  christos 	rdatasetheader_t *current, *dcurrent, *down_next, *dparent;
   1580  1.1  christos 	rdatasetheader_t *top_prev, *top_next;
   1581  1.1  christos 	isc_mem_t *mctx = rbtdb->common.mctx;
   1582  1.3  christos 	bool still_dirty = false;
   1583  1.1  christos 
   1584  1.1  christos 	/*
   1585  1.1  christos 	 * Caller must be holding the node lock.
   1586  1.1  christos 	 */
   1587  1.1  christos 	REQUIRE(least_serial != 0);
   1588  1.1  christos 
   1589  1.1  christos 	top_prev = NULL;
   1590  1.1  christos 	for (current = node->data; current != NULL; current = top_next) {
   1591  1.1  christos 		top_next = current->next;
   1592  1.1  christos 
   1593  1.1  christos 		/*
   1594  1.1  christos 		 * First, we clean up any instances of multiple rdatasets
   1595  1.1  christos 		 * with the same serial number, or that have the IGNORE
   1596  1.1  christos 		 * attribute.
   1597  1.1  christos 		 */
   1598  1.1  christos 		dparent = current;
   1599  1.1  christos 		for (dcurrent = current->down;
   1600  1.1  christos 		     dcurrent != NULL;
   1601  1.1  christos 		     dcurrent = down_next) {
   1602  1.1  christos 			down_next = dcurrent->down;
   1603  1.1  christos 			INSIST(dcurrent->serial <= dparent->serial);
   1604  1.1  christos 			if (dcurrent->serial == dparent->serial ||
   1605  1.1  christos 			    IGNORE(dcurrent)) {
   1606  1.1  christos 				if (down_next != NULL)
   1607  1.1  christos 					down_next->next = dparent;
   1608  1.1  christos 				dparent->down = down_next;
   1609  1.1  christos 				free_rdataset(rbtdb, mctx, dcurrent);
   1610  1.1  christos 			} else
   1611  1.1  christos 				dparent = dcurrent;
   1612  1.1  christos 		}
   1613  1.1  christos 
   1614  1.1  christos 		/*
   1615  1.1  christos 		 * We've now eliminated all IGNORE datasets with the possible
   1616  1.1  christos 		 * exception of current, which we now check.
   1617  1.1  christos 		 */
   1618  1.1  christos 		if (IGNORE(current)) {
   1619  1.1  christos 			down_next = current->down;
   1620  1.1  christos 			if (down_next == NULL) {
   1621  1.1  christos 				if (top_prev != NULL)
   1622  1.1  christos 					top_prev->next = current->next;
   1623  1.1  christos 				else
   1624  1.1  christos 					node->data = current->next;
   1625  1.1  christos 				free_rdataset(rbtdb, mctx, current);
   1626  1.1  christos 				/*
   1627  1.1  christos 				 * current no longer exists, so we can
   1628  1.1  christos 				 * just continue with the loop.
   1629  1.1  christos 				 */
   1630  1.1  christos 				continue;
   1631  1.1  christos 			} else {
   1632  1.1  christos 				/*
   1633  1.1  christos 				 * Pull up current->down, making it the new
   1634  1.1  christos 				 * current.
   1635  1.1  christos 				 */
   1636  1.1  christos 				if (top_prev != NULL)
   1637  1.1  christos 					top_prev->next = down_next;
   1638  1.1  christos 				else
   1639  1.1  christos 					node->data = down_next;
   1640  1.1  christos 				down_next->next = top_next;
   1641  1.1  christos 				free_rdataset(rbtdb, mctx, current);
   1642  1.1  christos 				current = down_next;
   1643  1.1  christos 			}
   1644  1.1  christos 		}
   1645  1.1  christos 
   1646  1.1  christos 		/*
   1647  1.1  christos 		 * We now try to find the first down node less than the
   1648  1.1  christos 		 * least serial.
   1649  1.1  christos 		 */
   1650  1.1  christos 		dparent = current;
   1651  1.1  christos 		for (dcurrent = current->down;
   1652  1.1  christos 		     dcurrent != NULL;
   1653  1.1  christos 		     dcurrent = down_next) {
   1654  1.1  christos 			down_next = dcurrent->down;
   1655  1.1  christos 			if (dcurrent->serial < least_serial)
   1656  1.1  christos 				break;
   1657  1.1  christos 			dparent = dcurrent;
   1658  1.1  christos 		}
   1659  1.1  christos 
   1660  1.1  christos 		/*
   1661  1.1  christos 		 * If there is a such an rdataset, delete it and any older
   1662  1.1  christos 		 * versions.
   1663  1.1  christos 		 */
   1664  1.1  christos 		if (dcurrent != NULL) {
   1665  1.1  christos 			do {
   1666  1.1  christos 				down_next = dcurrent->down;
   1667  1.1  christos 				INSIST(dcurrent->serial <= least_serial);
   1668  1.1  christos 				free_rdataset(rbtdb, mctx, dcurrent);
   1669  1.1  christos 				dcurrent = down_next;
   1670  1.1  christos 			} while (dcurrent != NULL);
   1671  1.1  christos 			dparent->down = NULL;
   1672  1.1  christos 		}
   1673  1.1  christos 
   1674  1.1  christos 		/*
   1675  1.1  christos 		 * Note.  The serial number of 'current' might be less than
   1676  1.1  christos 		 * least_serial too, but we cannot delete it because it is
   1677  1.1  christos 		 * the most recent version, unless it is a NONEXISTENT
   1678  1.1  christos 		 * rdataset.
   1679  1.1  christos 		 */
   1680  1.1  christos 		if (current->down != NULL) {
   1681  1.3  christos 			still_dirty = true;
   1682  1.1  christos 			top_prev = current;
   1683  1.1  christos 		} else {
   1684  1.1  christos 			/*
   1685  1.1  christos 			 * If this is a NONEXISTENT rdataset, we can delete it.
   1686  1.1  christos 			 */
   1687  1.1  christos 			if (NONEXISTENT(current)) {
   1688  1.1  christos 				if (top_prev != NULL)
   1689  1.1  christos 					top_prev->next = current->next;
   1690  1.1  christos 				else
   1691  1.1  christos 					node->data = current->next;
   1692  1.1  christos 				free_rdataset(rbtdb, mctx, current);
   1693  1.1  christos 			} else
   1694  1.1  christos 				top_prev = current;
   1695  1.1  christos 		}
   1696  1.1  christos 	}
   1697  1.1  christos 	if (!still_dirty)
   1698  1.1  christos 		node->dirty = 0;
   1699  1.1  christos }
   1700  1.1  christos 
   1701  1.1  christos static void
   1702  1.1  christos delete_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
   1703  1.1  christos 	dns_rbtnode_t *nsecnode;
   1704  1.1  christos 	dns_fixedname_t fname;
   1705  1.1  christos 	dns_name_t *name;
   1706  1.1  christos 	isc_result_t result = ISC_R_UNEXPECTED;
   1707  1.1  christos 
   1708  1.1  christos 	INSIST(!ISC_LINK_LINKED(node, deadlink));
   1709  1.1  christos 
   1710  1.1  christos 	if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
   1711  1.1  christos 		char printname[DNS_NAME_FORMATSIZE];
   1712  1.1  christos 		isc_log_write(dns_lctx,
   1713  1.1  christos 			      DNS_LOGCATEGORY_DATABASE,
   1714  1.1  christos 			      DNS_LOGMODULE_CACHE,
   1715  1.1  christos 			      ISC_LOG_DEBUG(1),
   1716  1.1  christos 			      "delete_node(): %p %s (bucket %d)",
   1717  1.1  christos 			      node,
   1718  1.1  christos 			      dns_rbt_formatnodename(node,
   1719  1.1  christos 					printname, sizeof(printname)),
   1720  1.1  christos 			      node->locknum);
   1721  1.1  christos 	}
   1722  1.1  christos 
   1723  1.1  christos 	switch (node->nsec) {
   1724  1.1  christos 	case DNS_RBT_NSEC_NORMAL:
   1725  1.1  christos 		/*
   1726  1.1  christos 		 * Though this may be wasteful, it has to be done before
   1727  1.1  christos 		 * node is deleted.
   1728  1.1  christos 		 */
   1729  1.1  christos 		name = dns_fixedname_initname(&fname);
   1730  1.1  christos 		dns_rbt_fullnamefromnode(node, name);
   1731  1.1  christos 
   1732  1.3  christos 		result = dns_rbt_deletenode(rbtdb->tree, node, false);
   1733  1.1  christos 		break;
   1734  1.1  christos 	case DNS_RBT_NSEC_HAS_NSEC:
   1735  1.1  christos 		name = dns_fixedname_initname(&fname);
   1736  1.1  christos 		dns_rbt_fullnamefromnode(node, name);
   1737  1.1  christos 		/*
   1738  1.1  christos 		 * Delete the corresponding node from the auxiliary NSEC
   1739  1.1  christos 		 * tree before deleting from the main tree.
   1740  1.1  christos 		 */
   1741  1.1  christos 		nsecnode = NULL;
   1742  1.1  christos 		result = dns_rbt_findnode(rbtdb->nsec, name, NULL, &nsecnode,
   1743  1.1  christos 					  NULL, DNS_RBTFIND_EMPTYDATA,
   1744  1.1  christos 					  NULL, NULL);
   1745  1.1  christos 		if (result != ISC_R_SUCCESS) {
   1746  1.1  christos 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
   1747  1.1  christos 				      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
   1748  1.1  christos 				      "delete_node: "
   1749  1.1  christos 				      "dns_rbt_findnode(nsec): %s",
   1750  1.1  christos 				      isc_result_totext(result));
   1751  1.1  christos 		} else {
   1752  1.1  christos 			result = dns_rbt_deletenode(rbtdb->nsec, nsecnode,
   1753  1.3  christos 						    false);
   1754  1.1  christos 			if (result != ISC_R_SUCCESS) {
   1755  1.1  christos 				isc_log_write(dns_lctx,
   1756  1.1  christos 					      DNS_LOGCATEGORY_DATABASE,
   1757  1.1  christos 					      DNS_LOGMODULE_CACHE,
   1758  1.1  christos 					      ISC_LOG_WARNING,
   1759  1.1  christos 					      "delete_node(): "
   1760  1.1  christos 					      "dns_rbt_deletenode(nsecnode): %s",
   1761  1.1  christos 					      isc_result_totext(result));
   1762  1.1  christos 			}
   1763  1.1  christos 		}
   1764  1.3  christos 		result = dns_rbt_deletenode(rbtdb->tree, node, false);
   1765  1.1  christos 		break;
   1766  1.1  christos 	case DNS_RBT_NSEC_NSEC:
   1767  1.3  christos 		result = dns_rbt_deletenode(rbtdb->nsec, node, false);
   1768  1.1  christos 		break;
   1769  1.1  christos 	case DNS_RBT_NSEC_NSEC3:
   1770  1.3  christos 		result = dns_rbt_deletenode(rbtdb->nsec3, node, false);
   1771  1.1  christos 		break;
   1772  1.1  christos 	}
   1773  1.1  christos 	if (result != ISC_R_SUCCESS) {
   1774  1.1  christos 		isc_log_write(dns_lctx,
   1775  1.1  christos 			      DNS_LOGCATEGORY_DATABASE,
   1776  1.1  christos 			      DNS_LOGMODULE_CACHE,
   1777  1.1  christos 			      ISC_LOG_WARNING,
   1778  1.1  christos 			      "delete_node(): "
   1779  1.1  christos 			      "dns_rbt_deletenode: %s",
   1780  1.1  christos 			      isc_result_totext(result));
   1781  1.1  christos 	}
   1782  1.1  christos }
   1783  1.1  christos 
   1784  1.1  christos /*
   1785  1.1  christos  * Caller must be holding the node lock.
   1786  1.1  christos  */
   1787  1.1  christos static inline void
   1788  1.1  christos new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
   1789  1.1  christos 	INSIST(!ISC_LINK_LINKED(node, deadlink));
   1790  1.3  christos 	if (isc_refcount_increment(&node->references) == 0) {
   1791  1.3  christos 		/* this is the first reference to the node */
   1792  1.3  christos 		isc_refcount_increment0(&rbtdb->node_locks[node->locknum].references);
   1793  1.1  christos 	}
   1794  1.1  christos }
   1795  1.1  christos 
   1796  1.1  christos /*%
   1797  1.1  christos  * Clean up dead nodes.  These are nodes which have no references, and
   1798  1.1  christos  * have no data.  They are dead but we could not or chose not to delete
   1799  1.1  christos  * them when we deleted all the data at that node because we did not want
   1800  1.1  christos  * to wait for the tree write lock.
   1801  1.1  christos  *
   1802  1.1  christos  * The caller must hold a tree write lock and bucketnum'th node (write) lock.
   1803  1.1  christos  */
   1804  1.1  christos static void
   1805  1.1  christos cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) {
   1806  1.1  christos 	dns_rbtnode_t *node;
   1807  1.1  christos 	int count = 10;         /* XXXJT: should be adjustable */
   1808  1.1  christos 
   1809  1.1  christos 	node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]);
   1810  1.1  christos 	while (node != NULL && count > 0) {
   1811  1.1  christos 		ISC_LIST_UNLINK(rbtdb->deadnodes[bucketnum], node, deadlink);
   1812  1.1  christos 
   1813  1.1  christos 		/*
   1814  1.1  christos 		 * Since we're holding a tree write lock, it should be
   1815  1.1  christos 		 * impossible for this node to be referenced by others.
   1816  1.1  christos 		 */
   1817  1.3  christos 		INSIST(isc_refcount_current(&node->references) == 0 &&
   1818  1.1  christos 		       node->data == NULL);
   1819  1.1  christos 
   1820  1.1  christos 		if (node->parent != NULL &&
   1821  1.1  christos 		    node->parent->down == node && node->left == NULL &&
   1822  1.1  christos 		    node->right == NULL && rbtdb->task != NULL)
   1823  1.1  christos 		{
   1824  1.1  christos 			isc_event_t *ev;
   1825  1.1  christos 			dns_db_t *db;
   1826  1.1  christos 
   1827  1.1  christos 			ev = isc_event_allocate(rbtdb->common.mctx, NULL,
   1828  1.1  christos 						DNS_EVENT_RBTPRUNE,
   1829  1.1  christos 						prune_tree, node,
   1830  1.1  christos 						sizeof(isc_event_t));
   1831  1.1  christos 			if (ev != NULL) {
   1832  1.1  christos 				new_reference(rbtdb, node);
   1833  1.1  christos 				db = NULL;
   1834  1.1  christos 				attach((dns_db_t *)rbtdb, &db);
   1835  1.1  christos 				ev->ev_sender = db;
   1836  1.1  christos 				isc_task_send(rbtdb->task, &ev);
   1837  1.1  christos 			} else {
   1838  1.1  christos 				ISC_LIST_APPEND(rbtdb->deadnodes[bucketnum],
   1839  1.1  christos 						node, deadlink);
   1840  1.1  christos 			}
   1841  1.1  christos 		} else {
   1842  1.1  christos 			delete_node(rbtdb, node);
   1843  1.1  christos 		}
   1844  1.1  christos 		node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]);
   1845  1.1  christos 		count--;
   1846  1.1  christos 	}
   1847  1.1  christos }
   1848  1.1  christos 
   1849  1.1  christos /*
   1850  1.1  christos  * This function is assumed to be called when a node is newly referenced
   1851  1.1  christos  * and can be in the deadnode list.  In that case the node must be retrieved
   1852  1.1  christos  * from the list because it is going to be used.  In addition, if the caller
   1853  1.1  christos  * happens to hold a write lock on the tree, it's a good chance to purge dead
   1854  1.1  christos  * nodes.
   1855  1.1  christos  * Note: while a new reference is gained in multiple places, there are only very
   1856  1.1  christos  * few cases where the node can be in the deadnode list (only empty nodes can
   1857  1.1  christos  * have been added to the list).
   1858  1.1  christos  */
   1859  1.1  christos static inline void
   1860  1.1  christos reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
   1861  1.1  christos 		isc_rwlocktype_t treelocktype)
   1862  1.1  christos {
   1863  1.1  christos 	isc_rwlocktype_t locktype = isc_rwlocktype_read;
   1864  1.1  christos 	nodelock_t *nodelock = &rbtdb->node_locks[node->locknum].lock;
   1865  1.3  christos 	bool maybe_cleanup = false;
   1866  1.1  christos 
   1867  1.1  christos 	POST(locktype);
   1868  1.1  christos 
   1869  1.3  christos 	NODE_LOCK(nodelock, locktype);
   1870  1.1  christos 
   1871  1.1  christos 	/*
   1872  1.1  christos 	 * Check if we can possibly cleanup the dead node.  If so, upgrade
   1873  1.1  christos 	 * the node lock below to perform the cleanup.
   1874  1.1  christos 	 */
   1875  1.1  christos 	if (!ISC_LIST_EMPTY(rbtdb->deadnodes[node->locknum]) &&
   1876  1.1  christos 	    treelocktype == isc_rwlocktype_write) {
   1877  1.3  christos 		maybe_cleanup = true;
   1878  1.1  christos 	}
   1879  1.1  christos 
   1880  1.1  christos 	if (ISC_LINK_LINKED(node, deadlink) || maybe_cleanup) {
   1881  1.1  christos 		/*
   1882  1.1  christos 		 * Upgrade the lock and test if we still need to unlink.
   1883  1.1  christos 		 */
   1884  1.3  christos 		NODE_UNLOCK(nodelock, locktype);
   1885  1.1  christos 		locktype = isc_rwlocktype_write;
   1886  1.1  christos 		POST(locktype);
   1887  1.3  christos 		NODE_LOCK(nodelock, locktype);
   1888  1.1  christos 		if (ISC_LINK_LINKED(node, deadlink))
   1889  1.1  christos 			ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum],
   1890  1.1  christos 					node, deadlink);
   1891  1.1  christos 		if (maybe_cleanup)
   1892  1.1  christos 			cleanup_dead_nodes(rbtdb, node->locknum);
   1893  1.1  christos 	}
   1894  1.1  christos 
   1895  1.1  christos 	new_reference(rbtdb, node);
   1896  1.1  christos 
   1897  1.3  christos 	NODE_UNLOCK(nodelock, locktype);
   1898  1.1  christos }
   1899  1.1  christos 
   1900  1.1  christos /*
   1901  1.1  christos  * Caller must be holding the node lock; either the "strong", read or write
   1902  1.1  christos  * lock.  Note that the lock must be held even when node references are
   1903  1.1  christos  * atomically modified; in that case the decrement operation itself does not
   1904  1.1  christos  * have to be protected, but we must avoid a race condition where multiple
   1905  1.1  christos  * threads are decreasing the reference to zero simultaneously and at least
   1906  1.1  christos  * one of them is going to free the node.
   1907  1.1  christos  *
   1908  1.3  christos  * This function returns true if and only if the node reference decreases
   1909  1.1  christos  * to zero.
   1910  1.1  christos  *
   1911  1.1  christos  * NOTE: Decrementing the reference count of a node to zero does not mean it
   1912  1.1  christos  * will be immediately freed.
   1913  1.1  christos  */
   1914  1.3  christos static bool
   1915  1.1  christos decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
   1916  1.1  christos 		    rbtdb_serial_t least_serial,
   1917  1.1  christos 		    isc_rwlocktype_t nlock, isc_rwlocktype_t tlock,
   1918  1.3  christos 		    bool pruning)
   1919  1.1  christos {
   1920  1.1  christos 	isc_result_t result;
   1921  1.3  christos 	bool write_locked;
   1922  1.1  christos 	rbtdb_nodelock_t *nodelock;
   1923  1.1  christos 	int bucket = node->locknum;
   1924  1.3  christos 	bool no_reference = true;
   1925  1.1  christos 
   1926  1.1  christos 	nodelock = &rbtdb->node_locks[bucket];
   1927  1.1  christos 
   1928  1.1  christos #define KEEP_NODE(n, r) \
   1929  1.1  christos 	((n)->data != NULL || (n)->down != NULL || \
   1930  1.1  christos 	 (n) == (r)->origin_node || (n) == (r)->nsec3_origin_node)
   1931  1.1  christos 
   1932  1.1  christos 	/* Handle easy and typical case first. */
   1933  1.1  christos 	if (!node->dirty && KEEP_NODE(node, rbtdb)) {
   1934  1.3  christos 		if (isc_refcount_decrement(&node->references) == 1) {
   1935  1.3  christos 			isc_refcount_decrement(&nodelock->references);
   1936  1.3  christos 			return (true);
   1937  1.3  christos 		} else {
   1938  1.3  christos 			return (false);
   1939  1.1  christos 		}
   1940  1.1  christos 	}
   1941  1.1  christos 
   1942  1.1  christos 	/* Upgrade the lock? */
   1943  1.1  christos 	if (nlock == isc_rwlocktype_read) {
   1944  1.3  christos 		NODE_UNLOCK(&nodelock->lock, isc_rwlocktype_read);
   1945  1.3  christos 		NODE_LOCK(&nodelock->lock, isc_rwlocktype_write);
   1946  1.1  christos 	}
   1947  1.1  christos 
   1948  1.3  christos 	if (isc_refcount_decrement(&node->references) > 1) {
   1949  1.1  christos 		/* Restore the lock? */
   1950  1.1  christos 		if (nlock == isc_rwlocktype_read)
   1951  1.3  christos 			NODE_DOWNGRADE(&nodelock->lock);
   1952  1.3  christos 		return (false);
   1953  1.1  christos 	}
   1954  1.1  christos 
   1955  1.1  christos 	if (node->dirty) {
   1956  1.1  christos 		if (IS_CACHE(rbtdb))
   1957  1.1  christos 			clean_cache_node(rbtdb, node);
   1958  1.1  christos 		else {
   1959  1.1  christos 			if (least_serial == 0) {
   1960  1.1  christos 				/*
   1961  1.1  christos 				 * Caller doesn't know the least serial.
   1962  1.1  christos 				 * Get it.
   1963  1.1  christos 				 */
   1964  1.1  christos 				RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
   1965  1.1  christos 				least_serial = rbtdb->least_serial;
   1966  1.1  christos 				RBTDB_UNLOCK(&rbtdb->lock,
   1967  1.1  christos 					     isc_rwlocktype_read);
   1968  1.1  christos 			}
   1969  1.1  christos 			clean_zone_node(rbtdb, node, least_serial);
   1970  1.1  christos 		}
   1971  1.1  christos 	}
   1972  1.1  christos 
   1973  1.1  christos 	/*
   1974  1.1  christos 	 * Attempt to switch to a write lock on the tree.  If this fails,
   1975  1.1  christos 	 * we will add this node to a linked list of nodes in this locking
   1976  1.1  christos 	 * bucket which we will free later.
   1977  1.1  christos 	 */
   1978  1.1  christos 	if (tlock != isc_rwlocktype_write) {
   1979  1.1  christos 		/*
   1980  1.1  christos 		 * Locking hierarchy notwithstanding, we don't need to free
   1981  1.1  christos 		 * the node lock before acquiring the tree write lock because
   1982  1.1  christos 		 * we only do a trylock.
   1983  1.1  christos 		 */
   1984  1.1  christos 		if (tlock == isc_rwlocktype_read)
   1985  1.1  christos 			result = isc_rwlock_tryupgrade(&rbtdb->tree_lock);
   1986  1.1  christos 		else
   1987  1.1  christos 			result = isc_rwlock_trylock(&rbtdb->tree_lock,
   1988  1.1  christos 						    isc_rwlocktype_write);
   1989  1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS ||
   1990  1.1  christos 			      result == ISC_R_LOCKBUSY);
   1991  1.1  christos 
   1992  1.3  christos 		write_locked = (result == ISC_R_SUCCESS);
   1993  1.1  christos 	} else
   1994  1.3  christos 		write_locked = true;
   1995  1.1  christos 
   1996  1.3  christos 	INSIST(isc_refcount_decrement(&nodelock->references) > 0);
   1997  1.1  christos 
   1998  1.1  christos 	if (KEEP_NODE(node, rbtdb))
   1999  1.1  christos 		goto restore_locks;
   2000  1.1  christos 
   2001  1.1  christos #undef KEEP_NODE
   2002  1.1  christos 
   2003  1.1  christos 	if (write_locked) {
   2004  1.1  christos 		/*
   2005  1.1  christos 		 * We can now delete the node.
   2006  1.1  christos 		 */
   2007  1.1  christos 
   2008  1.1  christos 		/*
   2009  1.1  christos 		 * If this node is the only one in the level it's in, deleting
   2010  1.1  christos 		 * this node may recursively make its parent the only node in
   2011  1.1  christos 		 * the parent level; if so, and if no one is currently using
   2012  1.1  christos 		 * the parent node, this is almost the only opportunity to
   2013  1.1  christos 		 * clean it up.  But the recursive cleanup is not that trivial
   2014  1.1  christos 		 * since the child and parent may be in different lock buckets,
   2015  1.1  christos 		 * which would cause a lock order reversal problem.  To avoid
   2016  1.1  christos 		 * the trouble, we'll dispatch a separate event for batch
   2017  1.1  christos 		 * cleaning.  We need to check whether we're deleting the node
   2018  1.1  christos 		 * as a result of pruning to avoid infinite dispatching.
   2019  1.1  christos 		 * Note: pruning happens only when a task has been set for the
   2020  1.1  christos 		 * rbtdb.  If the user of the rbtdb chooses not to set a task,
   2021  1.1  christos 		 * it's their responsibility to purge stale leaves (e.g. by
   2022  1.1  christos 		 * periodic walk-through).
   2023  1.1  christos 		 */
   2024  1.1  christos 		if (!pruning && node->parent != NULL &&
   2025  1.1  christos 		    node->parent->down == node && node->left == NULL &&
   2026  1.1  christos 		    node->right == NULL && rbtdb->task != NULL) {
   2027  1.1  christos 			isc_event_t *ev;
   2028  1.1  christos 			dns_db_t *db;
   2029  1.1  christos 
   2030  1.1  christos 			ev = isc_event_allocate(rbtdb->common.mctx, NULL,
   2031  1.1  christos 						DNS_EVENT_RBTPRUNE,
   2032  1.1  christos 						prune_tree, node,
   2033  1.1  christos 						sizeof(isc_event_t));
   2034  1.1  christos 			if (ev != NULL) {
   2035  1.1  christos 				new_reference(rbtdb, node);
   2036  1.1  christos 				db = NULL;
   2037  1.1  christos 				attach((dns_db_t *)rbtdb, &db);
   2038  1.1  christos 				ev->ev_sender = db;
   2039  1.1  christos 				isc_task_send(rbtdb->task, &ev);
   2040  1.3  christos 				no_reference = false;
   2041  1.1  christos 			} else {
   2042  1.1  christos 				/*
   2043  1.1  christos 				 * XXX: this is a weird situation.  We could
   2044  1.1  christos 				 * ignore this error case, but then the stale
   2045  1.1  christos 				 * node will unlikely be purged except via a
   2046  1.1  christos 				 * rare condition such as manual cleanup.  So
   2047  1.1  christos 				 * we queue it in the deadnodes list, hoping
   2048  1.1  christos 				 * the memory shortage is temporary and the node
   2049  1.1  christos 				 * will be deleted later.
   2050  1.1  christos 				 */
   2051  1.1  christos 				isc_log_write(dns_lctx,
   2052  1.1  christos 					      DNS_LOGCATEGORY_DATABASE,
   2053  1.1  christos 					      DNS_LOGMODULE_CACHE,
   2054  1.1  christos 					      ISC_LOG_INFO,
   2055  1.1  christos 					      "decrement_reference: failed to "
   2056  1.1  christos 					      "allocate pruning event");
   2057  1.1  christos 				INSIST(node->data == NULL);
   2058  1.1  christos 				INSIST(!ISC_LINK_LINKED(node, deadlink));
   2059  1.1  christos 				ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node,
   2060  1.1  christos 						deadlink);
   2061  1.1  christos 			}
   2062  1.1  christos 		} else {
   2063  1.1  christos 			delete_node(rbtdb, node);
   2064  1.1  christos 		}
   2065  1.1  christos 	} else {
   2066  1.1  christos 		INSIST(node->data == NULL);
   2067  1.1  christos 		INSIST(!ISC_LINK_LINKED(node, deadlink));
   2068  1.1  christos 		ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node, deadlink);
   2069  1.1  christos 	}
   2070  1.1  christos 
   2071  1.1  christos  restore_locks:
   2072  1.1  christos 	/* Restore the lock? */
   2073  1.1  christos 	if (nlock == isc_rwlocktype_read)
   2074  1.3  christos 		NODE_DOWNGRADE(&nodelock->lock);
   2075  1.1  christos 
   2076  1.1  christos 	/*
   2077  1.1  christos 	 * Relock a read lock, or unlock the write lock if no lock was held.
   2078  1.1  christos 	 */
   2079  1.1  christos 	if (tlock == isc_rwlocktype_none)
   2080  1.1  christos 		if (write_locked)
   2081  1.1  christos 			RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   2082  1.1  christos 
   2083  1.1  christos 	if (tlock == isc_rwlocktype_read)
   2084  1.1  christos 		if (write_locked)
   2085  1.1  christos 			isc_rwlock_downgrade(&rbtdb->tree_lock);
   2086  1.1  christos 
   2087  1.1  christos 	return (no_reference);
   2088  1.1  christos }
   2089  1.1  christos 
   2090  1.1  christos /*
   2091  1.1  christos  * Prune the tree by recursively cleaning-up single leaves.  In the worst
   2092  1.1  christos  * case, the number of iteration is the number of tree levels, which is at
   2093  1.1  christos  * most the maximum number of domain name labels, i.e, 127.  In practice, this
   2094  1.1  christos  * should be much smaller (only a few times), and even the worst case would be
   2095  1.1  christos  * acceptable for a single event.
   2096  1.1  christos  */
   2097  1.1  christos static void
   2098  1.1  christos prune_tree(isc_task_t *task, isc_event_t *event) {
   2099  1.1  christos 	dns_rbtdb_t *rbtdb = event->ev_sender;
   2100  1.1  christos 	dns_rbtnode_t *node = event->ev_arg;
   2101  1.1  christos 	dns_rbtnode_t *parent;
   2102  1.1  christos 	unsigned int locknum;
   2103  1.1  christos 
   2104  1.1  christos 	UNUSED(task);
   2105  1.1  christos 
   2106  1.1  christos 	isc_event_free(&event);
   2107  1.1  christos 
   2108  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   2109  1.1  christos 	locknum = node->locknum;
   2110  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write);
   2111  1.1  christos 	do {
   2112  1.1  christos 		parent = node->parent;
   2113  1.1  christos 		decrement_reference(rbtdb, node, 0, isc_rwlocktype_write,
   2114  1.3  christos 				    isc_rwlocktype_write, true);
   2115  1.1  christos 
   2116  1.1  christos 		if (parent != NULL && parent->down == NULL) {
   2117  1.1  christos 			/*
   2118  1.1  christos 			 * node was the only down child of the parent and has
   2119  1.1  christos 			 * just been removed.  We'll then need to examine the
   2120  1.1  christos 			 * parent.  Keep the lock if possible; otherwise,
   2121  1.1  christos 			 * release the old lock and acquire one for the parent.
   2122  1.1  christos 			 */
   2123  1.1  christos 			if (parent->locknum != locknum) {
   2124  1.1  christos 				NODE_UNLOCK(&rbtdb->node_locks[locknum].lock,
   2125  1.1  christos 					    isc_rwlocktype_write);
   2126  1.1  christos 				locknum = parent->locknum;
   2127  1.1  christos 				NODE_LOCK(&rbtdb->node_locks[locknum].lock,
   2128  1.1  christos 					  isc_rwlocktype_write);
   2129  1.1  christos 			}
   2130  1.1  christos 
   2131  1.1  christos 			/*
   2132  1.1  christos 			 * We need to gain a reference to the node before
   2133  1.1  christos 			 * decrementing it in the next iteration.  In addition,
   2134  1.1  christos 			 * if the node is in the dead-nodes list, extract it
   2135  1.1  christos 			 * from the list beforehand as we do in
   2136  1.1  christos 			 * reactivate_node().
   2137  1.1  christos 			 */
   2138  1.1  christos 			if (ISC_LINK_LINKED(parent, deadlink))
   2139  1.1  christos 				ISC_LIST_UNLINK(rbtdb->deadnodes[locknum],
   2140  1.1  christos 						parent, deadlink);
   2141  1.1  christos 			new_reference(rbtdb, parent);
   2142  1.1  christos 		} else
   2143  1.1  christos 			parent = NULL;
   2144  1.1  christos 
   2145  1.1  christos 		node = parent;
   2146  1.1  christos 	} while (node != NULL);
   2147  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write);
   2148  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   2149  1.1  christos 
   2150  1.2  christos 	detach((dns_db_t **)(void *)&rbtdb);
   2151  1.1  christos }
   2152  1.1  christos 
   2153  1.1  christos static inline void
   2154  1.1  christos make_least_version(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
   2155  1.1  christos 		   rbtdb_changedlist_t *cleanup_list)
   2156  1.1  christos {
   2157  1.1  christos 	/*
   2158  1.1  christos 	 * Caller must be holding the database lock.
   2159  1.1  christos 	 */
   2160  1.1  christos 
   2161  1.1  christos 	rbtdb->least_serial = version->serial;
   2162  1.1  christos 	*cleanup_list = version->changed_list;
   2163  1.1  christos 	ISC_LIST_INIT(version->changed_list);
   2164  1.1  christos }
   2165  1.1  christos 
   2166  1.1  christos static inline void
   2167  1.1  christos cleanup_nondirty(rbtdb_version_t *version, rbtdb_changedlist_t *cleanup_list) {
   2168  1.1  christos 	rbtdb_changed_t *changed, *next_changed;
   2169  1.1  christos 
   2170  1.1  christos 	/*
   2171  1.1  christos 	 * If the changed record is dirty, then
   2172  1.1  christos 	 * an update created multiple versions of
   2173  1.1  christos 	 * a given rdataset.  We keep this list
   2174  1.1  christos 	 * until we're the least open version, at
   2175  1.1  christos 	 * which point it's safe to get rid of any
   2176  1.1  christos 	 * older versions.
   2177  1.1  christos 	 *
   2178  1.1  christos 	 * If the changed record isn't dirty, then
   2179  1.1  christos 	 * we don't need it anymore since we're
   2180  1.1  christos 	 * committing and not rolling back.
   2181  1.1  christos 	 *
   2182  1.1  christos 	 * The caller must be holding the database lock.
   2183  1.1  christos 	 */
   2184  1.1  christos 	for (changed = HEAD(version->changed_list);
   2185  1.1  christos 	     changed != NULL;
   2186  1.1  christos 	     changed = next_changed) {
   2187  1.1  christos 		next_changed = NEXT(changed, link);
   2188  1.1  christos 		if (!changed->dirty) {
   2189  1.1  christos 			UNLINK(version->changed_list,
   2190  1.1  christos 			       changed, link);
   2191  1.1  christos 			APPEND(*cleanup_list,
   2192  1.1  christos 			       changed, link);
   2193  1.1  christos 		}
   2194  1.1  christos 	}
   2195  1.1  christos }
   2196  1.1  christos 
   2197  1.1  christos static void
   2198  1.1  christos iszonesecure(dns_db_t *db, rbtdb_version_t *version, dns_dbnode_t *origin) {
   2199  1.1  christos 	dns_rdataset_t keyset;
   2200  1.1  christos 	dns_rdataset_t nsecset, signsecset;
   2201  1.3  christos 	bool haszonekey = false;
   2202  1.3  christos 	bool hasnsec = false;
   2203  1.1  christos 	isc_result_t result;
   2204  1.1  christos 
   2205  1.1  christos 	dns_rdataset_init(&keyset);
   2206  1.1  christos 	result = dns_db_findrdataset(db, origin, version, dns_rdatatype_dnskey,
   2207  1.1  christos 				     0, 0, &keyset, NULL);
   2208  1.1  christos 	if (result == ISC_R_SUCCESS) {
   2209  1.1  christos 		result = dns_rdataset_first(&keyset);
   2210  1.1  christos 		while (result == ISC_R_SUCCESS) {
   2211  1.1  christos 			dns_rdata_t keyrdata = DNS_RDATA_INIT;
   2212  1.1  christos 			dns_rdataset_current(&keyset, &keyrdata);
   2213  1.1  christos 			if (dns_zonekey_iszonekey(&keyrdata)) {
   2214  1.3  christos 				haszonekey = true;
   2215  1.1  christos 				break;
   2216  1.1  christos 			}
   2217  1.1  christos 			result = dns_rdataset_next(&keyset);
   2218  1.1  christos 		}
   2219  1.1  christos 		dns_rdataset_disassociate(&keyset);
   2220  1.1  christos 	}
   2221  1.1  christos 	if (!haszonekey) {
   2222  1.1  christos 		version->secure = dns_db_insecure;
   2223  1.3  christos 		version->havensec3 = false;
   2224  1.1  christos 		return;
   2225  1.1  christos 	}
   2226  1.1  christos 
   2227  1.1  christos 	dns_rdataset_init(&nsecset);
   2228  1.1  christos 	dns_rdataset_init(&signsecset);
   2229  1.1  christos 	result = dns_db_findrdataset(db, origin, version, dns_rdatatype_nsec,
   2230  1.1  christos 				     0, 0, &nsecset, &signsecset);
   2231  1.1  christos 	if (result == ISC_R_SUCCESS) {
   2232  1.1  christos 		if (dns_rdataset_isassociated(&signsecset)) {
   2233  1.3  christos 			hasnsec = true;
   2234  1.1  christos 			dns_rdataset_disassociate(&signsecset);
   2235  1.1  christos 		}
   2236  1.1  christos 		dns_rdataset_disassociate(&nsecset);
   2237  1.1  christos 	}
   2238  1.1  christos 
   2239  1.1  christos 	setnsec3parameters(db, version);
   2240  1.1  christos 
   2241  1.1  christos 	/*
   2242  1.1  christos 	 * Do we have a valid NSEC/NSEC3 chain?
   2243  1.1  christos 	 */
   2244  1.1  christos 	if (version->havensec3 || hasnsec)
   2245  1.1  christos 		version->secure = dns_db_secure;
   2246  1.1  christos 	else
   2247  1.1  christos 		version->secure = dns_db_insecure;
   2248  1.1  christos }
   2249  1.1  christos 
   2250  1.1  christos /*%<
   2251  1.1  christos  * Walk the origin node looking for NSEC3PARAM records.
   2252  1.1  christos  * Cache the nsec3 parameters.
   2253  1.1  christos  */
   2254  1.1  christos static void
   2255  1.1  christos setnsec3parameters(dns_db_t *db, rbtdb_version_t *version) {
   2256  1.1  christos 	dns_rbtnode_t *node;
   2257  1.1  christos 	dns_rdata_nsec3param_t nsec3param;
   2258  1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   2259  1.1  christos 	isc_region_t region;
   2260  1.1  christos 	isc_result_t result;
   2261  1.1  christos 	rdatasetheader_t *header, *header_next;
   2262  1.1  christos 	unsigned char *raw;             /* RDATASLAB */
   2263  1.1  christos 	unsigned int count, length;
   2264  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   2265  1.1  christos 
   2266  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   2267  1.3  christos 	version->havensec3 = false;
   2268  1.1  christos 	node = rbtdb->origin_node;
   2269  1.1  christos 	NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
   2270  1.1  christos 		  isc_rwlocktype_read);
   2271  1.1  christos 	for (header = node->data;
   2272  1.1  christos 	     header != NULL;
   2273  1.1  christos 	     header = header_next) {
   2274  1.1  christos 		header_next = header->next;
   2275  1.1  christos 		do {
   2276  1.1  christos 			if (header->serial <= version->serial &&
   2277  1.1  christos 			    !IGNORE(header)) {
   2278  1.1  christos 				if (NONEXISTENT(header))
   2279  1.1  christos 					header = NULL;
   2280  1.1  christos 				break;
   2281  1.1  christos 			} else
   2282  1.1  christos 				header = header->down;
   2283  1.1  christos 		} while (header != NULL);
   2284  1.1  christos 
   2285  1.1  christos 		if (header != NULL &&
   2286  1.1  christos 		    (header->type == dns_rdatatype_nsec3param)) {
   2287  1.1  christos 			/*
   2288  1.1  christos 			 * Find A NSEC3PARAM with a supported algorithm.
   2289  1.1  christos 			 */
   2290  1.1  christos 			raw = (unsigned char *)header + sizeof(*header);
   2291  1.1  christos 			count = raw[0] * 256 + raw[1]; /* count */
   2292  1.1  christos #if DNS_RDATASET_FIXED
   2293  1.1  christos 			raw += count * 4 + 2;
   2294  1.1  christos #else
   2295  1.1  christos 			raw += 2;
   2296  1.1  christos #endif
   2297  1.1  christos 			while (count-- > 0U) {
   2298  1.1  christos 				length = raw[0] * 256 + raw[1];
   2299  1.1  christos #if DNS_RDATASET_FIXED
   2300  1.1  christos 				raw += 4;
   2301  1.1  christos #else
   2302  1.1  christos 				raw += 2;
   2303  1.1  christos #endif
   2304  1.1  christos 				region.base = raw;
   2305  1.1  christos 				region.length = length;
   2306  1.1  christos 				raw += length;
   2307  1.1  christos 				dns_rdata_fromregion(&rdata,
   2308  1.1  christos 						     rbtdb->common.rdclass,
   2309  1.1  christos 						     dns_rdatatype_nsec3param,
   2310  1.1  christos 						     &region);
   2311  1.1  christos 				result = dns_rdata_tostruct(&rdata,
   2312  1.1  christos 							    &nsec3param,
   2313  1.1  christos 							    NULL);
   2314  1.1  christos 				INSIST(result == ISC_R_SUCCESS);
   2315  1.1  christos 				dns_rdata_reset(&rdata);
   2316  1.1  christos 
   2317  1.1  christos 				if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG &&
   2318  1.1  christos 				    !dns_nsec3_supportedhash(nsec3param.hash))
   2319  1.1  christos 					continue;
   2320  1.1  christos 
   2321  1.1  christos 				if (nsec3param.flags != 0)
   2322  1.1  christos 					continue;
   2323  1.1  christos 
   2324  1.1  christos 				memmove(version->salt, nsec3param.salt,
   2325  1.1  christos 					nsec3param.salt_length);
   2326  1.1  christos 				version->hash = nsec3param.hash;
   2327  1.1  christos 				version->salt_length = nsec3param.salt_length;
   2328  1.1  christos 				version->iterations = nsec3param.iterations;
   2329  1.1  christos 				version->flags = nsec3param.flags;
   2330  1.3  christos 				version->havensec3 = true;
   2331  1.1  christos 				/*
   2332  1.1  christos 				 * Look for a better algorithm than the
   2333  1.1  christos 				 * unknown test algorithm.
   2334  1.1  christos 				 */
   2335  1.1  christos 				if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG)
   2336  1.1  christos 					goto unlock;
   2337  1.1  christos 			}
   2338  1.1  christos 		}
   2339  1.1  christos 	}
   2340  1.1  christos  unlock:
   2341  1.1  christos 	NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
   2342  1.1  christos 		    isc_rwlocktype_read);
   2343  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   2344  1.1  christos }
   2345  1.1  christos 
   2346  1.1  christos static void
   2347  1.1  christos cleanup_dead_nodes_callback(isc_task_t *task, isc_event_t *event) {
   2348  1.1  christos 	dns_rbtdb_t *rbtdb = event->ev_arg;
   2349  1.3  christos 	bool again = false;
   2350  1.1  christos 	unsigned int locknum;
   2351  1.1  christos 
   2352  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   2353  1.1  christos 	for (locknum = 0; locknum < rbtdb->node_lock_count; locknum++) {
   2354  1.1  christos 		NODE_LOCK(&rbtdb->node_locks[locknum].lock,
   2355  1.1  christos 			  isc_rwlocktype_write);
   2356  1.1  christos 		cleanup_dead_nodes(rbtdb, locknum);
   2357  1.1  christos 		if (ISC_LIST_HEAD(rbtdb->deadnodes[locknum]) != NULL)
   2358  1.3  christos 			again = true;
   2359  1.1  christos 		NODE_UNLOCK(&rbtdb->node_locks[locknum].lock,
   2360  1.1  christos 			    isc_rwlocktype_write);
   2361  1.1  christos 	}
   2362  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   2363  1.1  christos 	if (again)
   2364  1.1  christos 		isc_task_send(task, &event);
   2365  1.1  christos 	else {
   2366  1.1  christos 		isc_event_free(&event);
   2367  1.3  christos 		if (isc_refcount_decrement(&rbtdb->references) == 1) {
   2368  1.3  christos 			(void)isc_refcount_current(&rbtdb->references);
   2369  1.1  christos 			maybe_free_rbtdb(rbtdb);
   2370  1.3  christos 		}
   2371  1.1  christos 	}
   2372  1.1  christos }
   2373  1.1  christos 
   2374  1.1  christos static void
   2375  1.3  christos closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
   2376  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   2377  1.1  christos 	rbtdb_version_t *version, *cleanup_version, *least_greater;
   2378  1.3  christos 	bool rollback = false;
   2379  1.1  christos 	rbtdb_changedlist_t cleanup_list;
   2380  1.1  christos 	rdatasetheaderlist_t resigned_list;
   2381  1.1  christos 	rbtdb_changed_t *changed, *next_changed;
   2382  1.1  christos 	rbtdb_serial_t serial, least_serial;
   2383  1.1  christos 	dns_rbtnode_t *rbtnode;
   2384  1.1  christos 	rdatasetheader_t *header;
   2385  1.1  christos 
   2386  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   2387  1.1  christos 	version = (rbtdb_version_t *)*versionp;
   2388  1.1  christos 	INSIST(version->rbtdb == rbtdb);
   2389  1.1  christos 
   2390  1.1  christos 	cleanup_version = NULL;
   2391  1.1  christos 	ISC_LIST_INIT(cleanup_list);
   2392  1.1  christos 	ISC_LIST_INIT(resigned_list);
   2393  1.1  christos 
   2394  1.3  christos 	if (isc_refcount_decrement(&version->references) > 1) {
   2395  1.3  christos 		/* typical and easy case first */
   2396  1.1  christos 		if (commit) {
   2397  1.1  christos 			RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
   2398  1.1  christos 			INSIST(!version->writer);
   2399  1.1  christos 			RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
   2400  1.1  christos 		}
   2401  1.1  christos 		goto end;
   2402  1.1  christos 	}
   2403  1.1  christos 
   2404  1.1  christos 	/*
   2405  1.1  christos 	 * Update the zone's secure status in version before making
   2406  1.1  christos 	 * it the current version.
   2407  1.1  christos 	 */
   2408  1.1  christos 	if (version->writer && commit && !IS_CACHE(rbtdb))
   2409  1.1  christos 		iszonesecure(db, version, rbtdb->origin_node);
   2410  1.1  christos 
   2411  1.1  christos 	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
   2412  1.1  christos 	serial = version->serial;
   2413  1.1  christos 	if (version->writer) {
   2414  1.1  christos 		if (commit) {
   2415  1.1  christos 			unsigned cur_ref;
   2416  1.1  christos 			rbtdb_version_t *cur_version;
   2417  1.1  christos 
   2418  1.1  christos 			INSIST(version->commit_ok);
   2419  1.1  christos 			INSIST(version == rbtdb->future_version);
   2420  1.1  christos 			/*
   2421  1.1  christos 			 * The current version is going to be replaced.
   2422  1.1  christos 			 * Release the (likely last) reference to it from the
   2423  1.1  christos 			 * DB itself and unlink it from the open list.
   2424  1.1  christos 			 */
   2425  1.1  christos 			cur_version = rbtdb->current_version;
   2426  1.3  christos 			cur_ref = isc_refcount_decrement(&cur_version->references);
   2427  1.3  christos 			if (cur_ref == 1) {
   2428  1.3  christos 				(void)isc_refcount_current(&cur_version->references);
   2429  1.1  christos 				if (cur_version->serial == rbtdb->least_serial)
   2430  1.1  christos 					INSIST(EMPTY(cur_version->changed_list));
   2431  1.1  christos 				UNLINK(rbtdb->open_versions,
   2432  1.1  christos 				       cur_version, link);
   2433  1.1  christos 			}
   2434  1.1  christos 			if (EMPTY(rbtdb->open_versions)) {
   2435  1.1  christos 				/*
   2436  1.1  christos 				 * We're going to become the least open
   2437  1.1  christos 				 * version.
   2438  1.1  christos 				 */
   2439  1.1  christos 				make_least_version(rbtdb, version,
   2440  1.1  christos 						   &cleanup_list);
   2441  1.1  christos 			} else {
   2442  1.1  christos 				/*
   2443  1.1  christos 				 * Some other open version is the
   2444  1.1  christos 				 * least version.  We can't cleanup
   2445  1.1  christos 				 * records that were changed in this
   2446  1.1  christos 				 * version because the older versions
   2447  1.1  christos 				 * may still be in use by an open
   2448  1.1  christos 				 * version.
   2449  1.1  christos 				 *
   2450  1.1  christos 				 * We can, however, discard the
   2451  1.1  christos 				 * changed records for things that
   2452  1.1  christos 				 * we've added that didn't exist in
   2453  1.1  christos 				 * prior versions.
   2454  1.1  christos 				 */
   2455  1.1  christos 				cleanup_nondirty(version, &cleanup_list);
   2456  1.1  christos 			}
   2457  1.1  christos 			/*
   2458  1.1  christos 			 * If the (soon to be former) current version
   2459  1.1  christos 			 * isn't being used by anyone, we can clean
   2460  1.1  christos 			 * it up.
   2461  1.1  christos 			 */
   2462  1.3  christos 			if (cur_ref == 1) {
   2463  1.1  christos 				cleanup_version = cur_version;
   2464  1.1  christos 				APPENDLIST(version->changed_list,
   2465  1.1  christos 					   cleanup_version->changed_list,
   2466  1.1  christos 					   link);
   2467  1.1  christos 			}
   2468  1.1  christos 			/*
   2469  1.1  christos 			 * Become the current version.
   2470  1.1  christos 			 */
   2471  1.3  christos 			version->writer = false;
   2472  1.1  christos 			rbtdb->current_version = version;
   2473  1.1  christos 			rbtdb->current_serial = version->serial;
   2474  1.1  christos 			rbtdb->future_version = NULL;
   2475  1.1  christos 
   2476  1.1  christos 			/*
   2477  1.1  christos 			 * Keep the current version in the open list, and
   2478  1.1  christos 			 * gain a reference for the DB itself (see the DB
   2479  1.1  christos 			 * creation function below).  This must be the only
   2480  1.1  christos 			 * case where we need to increment the counter from
   2481  1.1  christos 			 * zero and need to use isc_refcount_increment0().
   2482  1.1  christos 			 */
   2483  1.3  christos 			INSIST(isc_refcount_increment0(&version->references) == 0);
   2484  1.1  christos 			PREPEND(rbtdb->open_versions,
   2485  1.1  christos 				rbtdb->current_version, link);
   2486  1.1  christos 			resigned_list = version->resigned_list;
   2487  1.1  christos 			ISC_LIST_INIT(version->resigned_list);
   2488  1.1  christos 		} else {
   2489  1.1  christos 			/*
   2490  1.1  christos 			 * We're rolling back this transaction.
   2491  1.1  christos 			 */
   2492  1.1  christos 			cleanup_list = version->changed_list;
   2493  1.1  christos 			ISC_LIST_INIT(version->changed_list);
   2494  1.1  christos 			resigned_list = version->resigned_list;
   2495  1.1  christos 			ISC_LIST_INIT(version->resigned_list);
   2496  1.3  christos 			rollback = true;
   2497  1.1  christos 			cleanup_version = version;
   2498  1.1  christos 			rbtdb->future_version = NULL;
   2499  1.1  christos 		}
   2500  1.1  christos 	} else {
   2501  1.1  christos 		if (version != rbtdb->current_version) {
   2502  1.1  christos 			/*
   2503  1.1  christos 			 * There are no external or internal references
   2504  1.1  christos 			 * to this version and it can be cleaned up.
   2505  1.1  christos 			 */
   2506  1.1  christos 			cleanup_version = version;
   2507  1.1  christos 
   2508  1.1  christos 			/*
   2509  1.1  christos 			 * Find the version with the least serial
   2510  1.1  christos 			 * number greater than ours.
   2511  1.1  christos 			 */
   2512  1.1  christos 			least_greater = PREV(version, link);
   2513  1.1  christos 			if (least_greater == NULL)
   2514  1.1  christos 				least_greater = rbtdb->current_version;
   2515  1.1  christos 
   2516  1.1  christos 			INSIST(version->serial < least_greater->serial);
   2517  1.1  christos 			/*
   2518  1.1  christos 			 * Is this the least open version?
   2519  1.1  christos 			 */
   2520  1.1  christos 			if (version->serial == rbtdb->least_serial) {
   2521  1.1  christos 				/*
   2522  1.1  christos 				 * Yes.  Install the new least open
   2523  1.1  christos 				 * version.
   2524  1.1  christos 				 */
   2525  1.1  christos 				make_least_version(rbtdb,
   2526  1.1  christos 						   least_greater,
   2527  1.1  christos 						   &cleanup_list);
   2528  1.1  christos 			} else {
   2529  1.1  christos 				/*
   2530  1.1  christos 				 * Add any unexecuted cleanups to
   2531  1.1  christos 				 * those of the least greater version.
   2532  1.1  christos 				 */
   2533  1.1  christos 				APPENDLIST(least_greater->changed_list,
   2534  1.1  christos 					   version->changed_list,
   2535  1.1  christos 					   link);
   2536  1.1  christos 			}
   2537  1.1  christos 		} else if (version->serial == rbtdb->least_serial)
   2538  1.1  christos 			INSIST(EMPTY(version->changed_list));
   2539  1.1  christos 		UNLINK(rbtdb->open_versions, version, link);
   2540  1.1  christos 	}
   2541  1.1  christos 	least_serial = rbtdb->least_serial;
   2542  1.1  christos 	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
   2543  1.1  christos 
   2544  1.1  christos 	if (cleanup_version != NULL) {
   2545  1.1  christos 		INSIST(EMPTY(cleanup_version->changed_list));
   2546  1.1  christos 		free_gluetable(cleanup_version);
   2547  1.1  christos 		isc_rwlock_destroy(&cleanup_version->glue_rwlock);
   2548  1.1  christos 		isc_rwlock_destroy(&cleanup_version->rwlock);
   2549  1.1  christos 		isc_mem_put(rbtdb->common.mctx, cleanup_version,
   2550  1.1  christos 			    sizeof(*cleanup_version));
   2551  1.1  christos 	}
   2552  1.1  christos 
   2553  1.1  christos 	/*
   2554  1.1  christos 	 * Commit/rollback re-signed headers.
   2555  1.1  christos 	 */
   2556  1.1  christos 	for (header = HEAD(resigned_list);
   2557  1.1  christos 	     header != NULL;
   2558  1.1  christos 	     header = HEAD(resigned_list)) {
   2559  1.1  christos 		nodelock_t *lock;
   2560  1.1  christos 
   2561  1.1  christos 		ISC_LIST_UNLINK(resigned_list, header, link);
   2562  1.1  christos 
   2563  1.1  christos 		lock = &rbtdb->node_locks[header->node->locknum].lock;
   2564  1.1  christos 		NODE_LOCK(lock, isc_rwlocktype_write);
   2565  1.1  christos 		if (rollback && !IGNORE(header)) {
   2566  1.1  christos 			isc_result_t result;
   2567  1.1  christos 			result = resign_insert(rbtdb, header->node->locknum,
   2568  1.1  christos 					       header);
   2569  1.1  christos 			if (result != ISC_R_SUCCESS)
   2570  1.1  christos 				isc_log_write(dns_lctx,
   2571  1.1  christos 					      DNS_LOGCATEGORY_DATABASE,
   2572  1.1  christos 					      DNS_LOGMODULE_ZONE, ISC_LOG_ERROR,
   2573  1.1  christos 					      "Unable to reinsert header to "
   2574  1.1  christos 					      "re-signing heap: %s",
   2575  1.1  christos 				dns_result_totext(result));
   2576  1.1  christos 		}
   2577  1.1  christos 		decrement_reference(rbtdb, header->node, least_serial,
   2578  1.1  christos 				    isc_rwlocktype_write, isc_rwlocktype_none,
   2579  1.3  christos 				    false);
   2580  1.1  christos 		NODE_UNLOCK(lock, isc_rwlocktype_write);
   2581  1.1  christos 	}
   2582  1.1  christos 
   2583  1.1  christos 	if (!EMPTY(cleanup_list)) {
   2584  1.1  christos 		isc_event_t *event = NULL;
   2585  1.1  christos 		isc_rwlocktype_t tlock = isc_rwlocktype_none;
   2586  1.1  christos 
   2587  1.1  christos 		if (rbtdb->task != NULL)
   2588  1.1  christos 			event = isc_event_allocate(rbtdb->common.mctx, NULL,
   2589  1.1  christos 						   DNS_EVENT_RBTDEADNODES,
   2590  1.1  christos 						   cleanup_dead_nodes_callback,
   2591  1.1  christos 						   rbtdb, sizeof(isc_event_t));
   2592  1.1  christos 		if (event == NULL) {
   2593  1.1  christos 			/*
   2594  1.1  christos 			 * We acquire a tree write lock here in order to make
   2595  1.1  christos 			 * sure that stale nodes will be removed in
   2596  1.1  christos 			 * decrement_reference().  If we didn't have the lock,
   2597  1.1  christos 			 * those nodes could miss the chance to be removed
   2598  1.1  christos 			 * until the server stops.  The write lock is
   2599  1.1  christos 			 * expensive, but this event should be rare enough
   2600  1.1  christos 			 * to justify the cost.
   2601  1.1  christos 			 */
   2602  1.1  christos 			RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   2603  1.1  christos 			tlock = isc_rwlocktype_write;
   2604  1.1  christos 		}
   2605  1.1  christos 
   2606  1.1  christos 		for (changed = HEAD(cleanup_list);
   2607  1.1  christos 		     changed != NULL;
   2608  1.1  christos 		     changed = next_changed) {
   2609  1.1  christos 			nodelock_t *lock;
   2610  1.1  christos 
   2611  1.1  christos 			next_changed = NEXT(changed, link);
   2612  1.1  christos 			rbtnode = changed->node;
   2613  1.1  christos 			lock = &rbtdb->node_locks[rbtnode->locknum].lock;
   2614  1.1  christos 
   2615  1.1  christos 			NODE_LOCK(lock, isc_rwlocktype_write);
   2616  1.1  christos 			/*
   2617  1.1  christos 			 * This is a good opportunity to purge any dead nodes,
   2618  1.1  christos 			 * so use it.
   2619  1.1  christos 			 */
   2620  1.1  christos 			if (event == NULL)
   2621  1.1  christos 				cleanup_dead_nodes(rbtdb, rbtnode->locknum);
   2622  1.1  christos 
   2623  1.1  christos 			if (rollback)
   2624  1.1  christos 				rollback_node(rbtnode, serial);
   2625  1.1  christos 			decrement_reference(rbtdb, rbtnode, least_serial,
   2626  1.1  christos 					    isc_rwlocktype_write, tlock,
   2627  1.3  christos 					    false);
   2628  1.1  christos 
   2629  1.1  christos 			NODE_UNLOCK(lock, isc_rwlocktype_write);
   2630  1.1  christos 
   2631  1.1  christos 			isc_mem_put(rbtdb->common.mctx, changed,
   2632  1.1  christos 				    sizeof(*changed));
   2633  1.1  christos 		}
   2634  1.1  christos 		if (event != NULL) {
   2635  1.3  christos 			isc_refcount_increment(&rbtdb->references);
   2636  1.1  christos 			isc_task_send(rbtdb->task, &event);
   2637  1.1  christos 		} else
   2638  1.1  christos 			RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   2639  1.1  christos 	}
   2640  1.1  christos 
   2641  1.1  christos  end:
   2642  1.1  christos 	*versionp = NULL;
   2643  1.1  christos }
   2644  1.1  christos 
   2645  1.1  christos /*
   2646  1.1  christos  * Add the necessary magic for the wildcard name 'name'
   2647  1.1  christos  * to be found in 'rbtdb'.
   2648  1.1  christos  *
   2649  1.1  christos  * In order for wildcard matching to work correctly in
   2650  1.1  christos  * zone_find(), we must ensure that a node for the wildcarding
   2651  1.1  christos  * level exists in the database, and has its 'find_callback'
   2652  1.1  christos  * and 'wild' bits set.
   2653  1.1  christos  *
   2654  1.1  christos  * E.g. if the wildcard name is "*.sub.example." then we
   2655  1.1  christos  * must ensure that "sub.example." exists and is marked as
   2656  1.1  christos  * a wildcard level.
   2657  1.1  christos  */
   2658  1.1  christos static isc_result_t
   2659  1.1  christos add_wildcard_magic(dns_rbtdb_t *rbtdb, const dns_name_t *name) {
   2660  1.1  christos 	isc_result_t result;
   2661  1.1  christos 	dns_name_t foundname;
   2662  1.1  christos 	dns_offsets_t offsets;
   2663  1.1  christos 	unsigned int n;
   2664  1.1  christos 	dns_rbtnode_t *node = NULL;
   2665  1.1  christos 
   2666  1.1  christos 	dns_name_init(&foundname, offsets);
   2667  1.1  christos 	n = dns_name_countlabels(name);
   2668  1.1  christos 	INSIST(n >= 2);
   2669  1.1  christos 	n--;
   2670  1.1  christos 	dns_name_getlabelsequence(name, 1, n, &foundname);
   2671  1.1  christos 	result = dns_rbt_addnode(rbtdb->tree, &foundname, &node);
   2672  1.1  christos 	if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
   2673  1.1  christos 		return (result);
   2674  1.1  christos 	if (result == ISC_R_SUCCESS)
   2675  1.1  christos 		node->nsec = DNS_RBT_NSEC_NORMAL;
   2676  1.1  christos 	node->find_callback = 1;
   2677  1.1  christos 	node->wild = 1;
   2678  1.1  christos 	return (ISC_R_SUCCESS);
   2679  1.1  christos }
   2680  1.1  christos 
   2681  1.1  christos static isc_result_t
   2682  1.1  christos add_empty_wildcards(dns_rbtdb_t *rbtdb, const dns_name_t *name) {
   2683  1.1  christos 	isc_result_t result;
   2684  1.1  christos 	dns_name_t foundname;
   2685  1.1  christos 	dns_offsets_t offsets;
   2686  1.1  christos 	unsigned int n, l, i;
   2687  1.1  christos 
   2688  1.1  christos 	dns_name_init(&foundname, offsets);
   2689  1.1  christos 	n = dns_name_countlabels(name);
   2690  1.1  christos 	l = dns_name_countlabels(&rbtdb->common.origin);
   2691  1.1  christos 	i = l + 1;
   2692  1.1  christos 	while (i < n) {
   2693  1.1  christos 		dns_rbtnode_t *node = NULL;     /* dummy */
   2694  1.1  christos 		dns_name_getlabelsequence(name, n - i, i, &foundname);
   2695  1.1  christos 		if (dns_name_iswildcard(&foundname)) {
   2696  1.1  christos 			result = add_wildcard_magic(rbtdb, &foundname);
   2697  1.1  christos 			if (result != ISC_R_SUCCESS)
   2698  1.1  christos 				return (result);
   2699  1.1  christos 			result = dns_rbt_addnode(rbtdb->tree, &foundname,
   2700  1.1  christos 						 &node);
   2701  1.1  christos 			if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
   2702  1.1  christos 				return (result);
   2703  1.1  christos 			if (result == ISC_R_SUCCESS)
   2704  1.1  christos 				node->nsec = DNS_RBT_NSEC_NORMAL;
   2705  1.1  christos 		}
   2706  1.1  christos 		i++;
   2707  1.1  christos 	}
   2708  1.1  christos 	return (ISC_R_SUCCESS);
   2709  1.1  christos }
   2710  1.1  christos 
   2711  1.1  christos static isc_result_t
   2712  1.1  christos findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, const dns_name_t *name,
   2713  1.3  christos 	       bool create, dns_dbnode_t **nodep)
   2714  1.1  christos {
   2715  1.1  christos 	dns_rbtnode_t *node = NULL;
   2716  1.1  christos 	dns_name_t nodename;
   2717  1.1  christos 	isc_result_t result;
   2718  1.1  christos 	isc_rwlocktype_t locktype = isc_rwlocktype_read;
   2719  1.1  christos 
   2720  1.1  christos 	INSIST(tree == rbtdb->tree || tree == rbtdb->nsec3);
   2721  1.1  christos 
   2722  1.1  christos 	dns_name_init(&nodename, NULL);
   2723  1.1  christos 	RWLOCK(&rbtdb->tree_lock, locktype);
   2724  1.1  christos 	result = dns_rbt_findnode(tree, name, NULL, &node, NULL,
   2725  1.1  christos 				  DNS_RBTFIND_EMPTYDATA, NULL, NULL);
   2726  1.1  christos 	if (result != ISC_R_SUCCESS) {
   2727  1.1  christos 		RWUNLOCK(&rbtdb->tree_lock, locktype);
   2728  1.1  christos 		if (!create) {
   2729  1.1  christos 			if (result == DNS_R_PARTIALMATCH)
   2730  1.1  christos 				result = ISC_R_NOTFOUND;
   2731  1.1  christos 			return (result);
   2732  1.1  christos 		}
   2733  1.1  christos 		/*
   2734  1.1  christos 		 * It would be nice to try to upgrade the lock instead of
   2735  1.1  christos 		 * unlocking then relocking.
   2736  1.1  christos 		 */
   2737  1.1  christos 		locktype = isc_rwlocktype_write;
   2738  1.1  christos 		RWLOCK(&rbtdb->tree_lock, locktype);
   2739  1.1  christos 		node = NULL;
   2740  1.1  christos 		result = dns_rbt_addnode(tree, name, &node);
   2741  1.1  christos 		if (result == ISC_R_SUCCESS) {
   2742  1.1  christos 			dns_rbt_namefromnode(node, &nodename);
   2743  1.1  christos 			node->locknum = node->hashval % rbtdb->node_lock_count;
   2744  1.1  christos 			if (tree == rbtdb->tree) {
   2745  1.1  christos 				add_empty_wildcards(rbtdb, name);
   2746  1.1  christos 
   2747  1.1  christos 				if (dns_name_iswildcard(name)) {
   2748  1.3  christos 					result = add_wildcard_magic(rbtdb,
   2749  1.3  christos 								    name);
   2750  1.1  christos 					if (result != ISC_R_SUCCESS) {
   2751  1.3  christos 						RWUNLOCK(&rbtdb->tree_lock,
   2752  1.3  christos 							 locktype);
   2753  1.1  christos 						return (result);
   2754  1.1  christos 					}
   2755  1.1  christos 				}
   2756  1.1  christos 			}
   2757  1.1  christos 			if (tree == rbtdb->nsec3)
   2758  1.1  christos 				node->nsec = DNS_RBT_NSEC_NSEC3;
   2759  1.1  christos 		} else if (result != ISC_R_EXISTS) {
   2760  1.1  christos 			RWUNLOCK(&rbtdb->tree_lock, locktype);
   2761  1.1  christos 			return (result);
   2762  1.1  christos 		}
   2763  1.1  christos 	}
   2764  1.1  christos 
   2765  1.1  christos 	if (tree == rbtdb->nsec3)
   2766  1.1  christos 		INSIST(node->nsec == DNS_RBT_NSEC_NSEC3);
   2767  1.1  christos 
   2768  1.1  christos 	reactivate_node(rbtdb, node, locktype);
   2769  1.1  christos 
   2770  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, locktype);
   2771  1.1  christos 
   2772  1.1  christos 	*nodep = (dns_dbnode_t *)node;
   2773  1.1  christos 
   2774  1.1  christos 	return (ISC_R_SUCCESS);
   2775  1.1  christos }
   2776  1.1  christos 
   2777  1.1  christos static isc_result_t
   2778  1.3  christos findnode(dns_db_t *db, const dns_name_t *name, bool create,
   2779  1.1  christos 	 dns_dbnode_t **nodep)
   2780  1.1  christos {
   2781  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   2782  1.1  christos 
   2783  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   2784  1.1  christos 
   2785  1.1  christos 	return (findnodeintree(rbtdb, rbtdb->tree, name, create, nodep));
   2786  1.1  christos }
   2787  1.1  christos 
   2788  1.1  christos static isc_result_t
   2789  1.3  christos findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
   2790  1.1  christos 	      dns_dbnode_t **nodep)
   2791  1.1  christos {
   2792  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   2793  1.1  christos 
   2794  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   2795  1.1  christos 
   2796  1.1  christos 	return (findnodeintree(rbtdb, rbtdb->nsec3, name, create, nodep));
   2797  1.1  christos }
   2798  1.1  christos 
   2799  1.1  christos static isc_result_t
   2800  1.1  christos zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
   2801  1.1  christos 	rbtdb_search_t *search = arg;
   2802  1.1  christos 	rdatasetheader_t *header, *header_next;
   2803  1.1  christos 	rdatasetheader_t *dname_header, *sigdname_header, *ns_header;
   2804  1.1  christos 	rdatasetheader_t *found;
   2805  1.1  christos 	isc_result_t result;
   2806  1.1  christos 	dns_rbtnode_t *onode;
   2807  1.1  christos 
   2808  1.1  christos 	/*
   2809  1.1  christos 	 * We only want to remember the topmost zone cut, since it's the one
   2810  1.1  christos 	 * that counts, so we'll just continue if we've already found a
   2811  1.1  christos 	 * zonecut.
   2812  1.1  christos 	 */
   2813  1.1  christos 	if (search->zonecut != NULL)
   2814  1.1  christos 		return (DNS_R_CONTINUE);
   2815  1.1  christos 
   2816  1.1  christos 	found = NULL;
   2817  1.1  christos 	result = DNS_R_CONTINUE;
   2818  1.1  christos 	onode = search->rbtdb->origin_node;
   2819  1.1  christos 
   2820  1.1  christos 	NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
   2821  1.1  christos 		  isc_rwlocktype_read);
   2822  1.1  christos 
   2823  1.1  christos 	/*
   2824  1.1  christos 	 * Look for an NS or DNAME rdataset active in our version.
   2825  1.1  christos 	 */
   2826  1.1  christos 	ns_header = NULL;
   2827  1.1  christos 	dname_header = NULL;
   2828  1.1  christos 	sigdname_header = NULL;
   2829  1.1  christos 	for (header = node->data; header != NULL; header = header_next) {
   2830  1.1  christos 		header_next = header->next;
   2831  1.1  christos 		if (header->type == dns_rdatatype_ns ||
   2832  1.1  christos 		    header->type == dns_rdatatype_dname ||
   2833  1.1  christos 		    header->type == RBTDB_RDATATYPE_SIGDNAME) {
   2834  1.1  christos 			do {
   2835  1.1  christos 				if (header->serial <= search->serial &&
   2836  1.1  christos 				    !IGNORE(header)) {
   2837  1.1  christos 					/*
   2838  1.1  christos 					 * Is this a "this rdataset doesn't
   2839  1.1  christos 					 * exist" record?
   2840  1.1  christos 					 */
   2841  1.1  christos 					if (NONEXISTENT(header))
   2842  1.1  christos 						header = NULL;
   2843  1.1  christos 					break;
   2844  1.1  christos 				} else
   2845  1.1  christos 					header = header->down;
   2846  1.1  christos 			} while (header != NULL);
   2847  1.1  christos 			if (header != NULL) {
   2848  1.1  christos 				if (header->type == dns_rdatatype_dname)
   2849  1.1  christos 					dname_header = header;
   2850  1.1  christos 				else if (header->type ==
   2851  1.1  christos 					   RBTDB_RDATATYPE_SIGDNAME)
   2852  1.1  christos 					sigdname_header = header;
   2853  1.1  christos 				else if (node != onode ||
   2854  1.1  christos 					 IS_STUB(search->rbtdb)) {
   2855  1.1  christos 					/*
   2856  1.1  christos 					 * We've found an NS rdataset that
   2857  1.1  christos 					 * isn't at the origin node.  We check
   2858  1.1  christos 					 * that they're not at the origin node,
   2859  1.1  christos 					 * because otherwise we'd erroneously
   2860  1.1  christos 					 * treat the zone top as if it were
   2861  1.1  christos 					 * a delegation.
   2862  1.1  christos 					 */
   2863  1.1  christos 					ns_header = header;
   2864  1.1  christos 				}
   2865  1.1  christos 			}
   2866  1.1  christos 		}
   2867  1.1  christos 	}
   2868  1.1  christos 
   2869  1.1  christos 	/*
   2870  1.1  christos 	 * Did we find anything?
   2871  1.1  christos 	 */
   2872  1.1  christos 	if (!IS_CACHE(search->rbtdb) && !IS_STUB(search->rbtdb) &&
   2873  1.1  christos 	    ns_header != NULL) {
   2874  1.1  christos 		/*
   2875  1.1  christos 		 * Note that NS has precedence over DNAME if both exist
   2876  1.1  christos 		 * in a zone.  Otherwise DNAME take precedence over NS.
   2877  1.1  christos 		 */
   2878  1.1  christos 		found = ns_header;
   2879  1.1  christos 		search->zonecut_sigrdataset = NULL;
   2880  1.1  christos 	} else if (dname_header != NULL) {
   2881  1.1  christos 		found = dname_header;
   2882  1.1  christos 		search->zonecut_sigrdataset = sigdname_header;
   2883  1.1  christos 	} else if (ns_header != NULL) {
   2884  1.1  christos 		found = ns_header;
   2885  1.1  christos 		search->zonecut_sigrdataset = NULL;
   2886  1.1  christos 	}
   2887  1.1  christos 
   2888  1.1  christos 	if (found != NULL) {
   2889  1.1  christos 		/*
   2890  1.1  christos 		 * We increment the reference count on node to ensure that
   2891  1.1  christos 		 * search->zonecut_rdataset will still be valid later.
   2892  1.1  christos 		 */
   2893  1.1  christos 		new_reference(search->rbtdb, node);
   2894  1.1  christos 		search->zonecut = node;
   2895  1.1  christos 		search->zonecut_rdataset = found;
   2896  1.3  christos 		search->need_cleanup = true;
   2897  1.1  christos 		/*
   2898  1.1  christos 		 * Since we've found a zonecut, anything beneath it is
   2899  1.1  christos 		 * glue and is not subject to wildcard matching, so we
   2900  1.1  christos 		 * may clear search->wild.
   2901  1.1  christos 		 */
   2902  1.3  christos 		search->wild = false;
   2903  1.1  christos 		if ((search->options & DNS_DBFIND_GLUEOK) == 0) {
   2904  1.1  christos 			/*
   2905  1.1  christos 			 * If the caller does not want to find glue, then
   2906  1.1  christos 			 * this is the best answer and the search should
   2907  1.1  christos 			 * stop now.
   2908  1.1  christos 			 */
   2909  1.1  christos 			result = DNS_R_PARTIALMATCH;
   2910  1.1  christos 		} else {
   2911  1.1  christos 			dns_name_t *zcname;
   2912  1.1  christos 
   2913  1.1  christos 			/*
   2914  1.1  christos 			 * The search will continue beneath the zone cut.
   2915  1.1  christos 			 * This may or may not be the best match.  In case it
   2916  1.1  christos 			 * is, we need to remember the node name.
   2917  1.1  christos 			 */
   2918  1.1  christos 			zcname = dns_fixedname_name(&search->zonecut_name);
   2919  1.1  christos 			RUNTIME_CHECK(dns_name_copy(name, zcname, NULL) ==
   2920  1.1  christos 				      ISC_R_SUCCESS);
   2921  1.3  christos 			search->copy_name = true;
   2922  1.1  christos 		}
   2923  1.1  christos 	} else {
   2924  1.1  christos 		/*
   2925  1.1  christos 		 * There is no zonecut at this node which is active in this
   2926  1.1  christos 		 * version.
   2927  1.1  christos 		 *
   2928  1.1  christos 		 * If this is a "wild" node and the caller hasn't disabled
   2929  1.1  christos 		 * wildcard matching, remember that we've seen a wild node
   2930  1.1  christos 		 * in case we need to go searching for wildcard matches
   2931  1.1  christos 		 * later on.
   2932  1.1  christos 		 */
   2933  1.1  christos 		if (node->wild && (search->options & DNS_DBFIND_NOWILD) == 0)
   2934  1.3  christos 			search->wild = true;
   2935  1.1  christos 	}
   2936  1.1  christos 
   2937  1.1  christos 	NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
   2938  1.1  christos 		    isc_rwlocktype_read);
   2939  1.1  christos 
   2940  1.1  christos 	return (result);
   2941  1.1  christos }
   2942  1.1  christos 
   2943  1.1  christos static inline void
   2944  1.1  christos bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
   2945  1.1  christos 	      rdatasetheader_t *header, isc_stdtime_t now,
   2946  1.1  christos 	      dns_rdataset_t *rdataset)
   2947  1.1  christos {
   2948  1.1  christos 	unsigned char *raw;     /* RDATASLAB */
   2949  1.1  christos 
   2950  1.1  christos 	/*
   2951  1.1  christos 	 * Caller must be holding the node reader lock.
   2952  1.1  christos 	 * XXXJT: technically, we need a writer lock, since we'll increment
   2953  1.1  christos 	 * the header count below.  However, since the actual counter value
   2954  1.1  christos 	 * doesn't matter, we prioritize performance here.  (We may want to
   2955  1.1  christos 	 * use atomic increment when available).
   2956  1.1  christos 	 */
   2957  1.1  christos 
   2958  1.1  christos 	if (rdataset == NULL)
   2959  1.1  christos 		return;
   2960  1.1  christos 
   2961  1.1  christos 	new_reference(rbtdb, node);
   2962  1.1  christos 
   2963  1.1  christos 	INSIST(rdataset->methods == NULL);      /* We must be disassociated. */
   2964  1.1  christos 
   2965  1.1  christos 	rdataset->methods = &rdataset_methods;
   2966  1.1  christos 	rdataset->rdclass = rbtdb->common.rdclass;
   2967  1.1  christos 	rdataset->type = RBTDB_RDATATYPE_BASE(header->type);
   2968  1.1  christos 	rdataset->covers = RBTDB_RDATATYPE_EXT(header->type);
   2969  1.1  christos 	rdataset->ttl = header->rdh_ttl - now;
   2970  1.1  christos 	rdataset->trust = header->trust;
   2971  1.1  christos 	if (NEGATIVE(header))
   2972  1.1  christos 		rdataset->attributes |= DNS_RDATASETATTR_NEGATIVE;
   2973  1.1  christos 	if (NXDOMAIN(header))
   2974  1.1  christos 		rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
   2975  1.1  christos 	if (OPTOUT(header))
   2976  1.1  christos 		rdataset->attributes |= DNS_RDATASETATTR_OPTOUT;
   2977  1.1  christos 	if (PREFETCH(header))
   2978  1.1  christos 		rdataset->attributes |= DNS_RDATASETATTR_PREFETCH;
   2979  1.1  christos 	if (STALE(header)) {
   2980  1.1  christos 		rdataset->attributes |= DNS_RDATASETATTR_STALE;
   2981  1.1  christos 		rdataset->ttl = 0;
   2982  1.1  christos 	}
   2983  1.1  christos 	rdataset->private1 = rbtdb;
   2984  1.1  christos 	rdataset->private2 = node;
   2985  1.1  christos 	raw = (unsigned char *)header + sizeof(*header);
   2986  1.1  christos 	rdataset->private3 = raw;
   2987  1.1  christos 	rdataset->count = header->count++;
   2988  1.3  christos 	if (rdataset->count == UINT32_MAX)
   2989  1.1  christos 		rdataset->count = 0;
   2990  1.1  christos 
   2991  1.1  christos 	/*
   2992  1.1  christos 	 * Reset iterator state.
   2993  1.1  christos 	 */
   2994  1.1  christos 	rdataset->privateuint4 = 0;
   2995  1.1  christos 	rdataset->private5 = NULL;
   2996  1.1  christos 
   2997  1.1  christos 	/*
   2998  1.1  christos 	 * Add noqname proof.
   2999  1.1  christos 	 */
   3000  1.1  christos 	rdataset->private6 = header->noqname;
   3001  1.1  christos 	if (rdataset->private6 != NULL)
   3002  1.1  christos 		rdataset->attributes |=  DNS_RDATASETATTR_NOQNAME;
   3003  1.1  christos 	rdataset->private7 = header->closest;
   3004  1.1  christos 	if (rdataset->private7 != NULL)
   3005  1.1  christos 		rdataset->attributes |=  DNS_RDATASETATTR_CLOSEST;
   3006  1.1  christos 
   3007  1.1  christos 	/*
   3008  1.1  christos 	 * Copy out re-signing information.
   3009  1.1  christos 	 */
   3010  1.1  christos 	if (RESIGN(header)) {
   3011  1.1  christos 		rdataset->attributes |=  DNS_RDATASETATTR_RESIGN;
   3012  1.1  christos 		rdataset->resign = (header->resign << 1) | header->resign_lsb;
   3013  1.1  christos 	} else
   3014  1.1  christos 		rdataset->resign = 0;
   3015  1.1  christos }
   3016  1.1  christos 
   3017  1.1  christos static inline isc_result_t
   3018  1.1  christos setup_delegation(rbtdb_search_t *search, dns_dbnode_t **nodep,
   3019  1.1  christos 		 dns_name_t *foundname, dns_rdataset_t *rdataset,
   3020  1.1  christos 		 dns_rdataset_t *sigrdataset)
   3021  1.1  christos {
   3022  1.1  christos 	isc_result_t result;
   3023  1.1  christos 	dns_name_t *zcname;
   3024  1.1  christos 	rbtdb_rdatatype_t type;
   3025  1.1  christos 	dns_rbtnode_t *node;
   3026  1.1  christos 
   3027  1.1  christos 	/*
   3028  1.1  christos 	 * The caller MUST NOT be holding any node locks.
   3029  1.1  christos 	 */
   3030  1.1  christos 
   3031  1.1  christos 	node = search->zonecut;
   3032  1.1  christos 	type = search->zonecut_rdataset->type;
   3033  1.1  christos 
   3034  1.1  christos 	/*
   3035  1.1  christos 	 * If we have to set foundname, we do it before anything else.
   3036  1.1  christos 	 * If we were to set foundname after we had set nodep or bound the
   3037  1.1  christos 	 * rdataset, then we'd have to undo that work if dns_name_copy()
   3038  1.1  christos 	 * failed.  By setting foundname first, there's nothing to undo if
   3039  1.1  christos 	 * we have trouble.
   3040  1.1  christos 	 */
   3041  1.1  christos 	if (foundname != NULL && search->copy_name) {
   3042  1.1  christos 		zcname = dns_fixedname_name(&search->zonecut_name);
   3043  1.1  christos 		result = dns_name_copy(zcname, foundname, NULL);
   3044  1.1  christos 		if (result != ISC_R_SUCCESS)
   3045  1.1  christos 			return (result);
   3046  1.1  christos 	}
   3047  1.1  christos 	if (nodep != NULL) {
   3048  1.1  christos 		/*
   3049  1.1  christos 		 * Note that we don't have to increment the node's reference
   3050  1.1  christos 		 * count here because we're going to use the reference we
   3051  1.1  christos 		 * already have in the search block.
   3052  1.1  christos 		 */
   3053  1.1  christos 		*nodep = node;
   3054  1.3  christos 		search->need_cleanup = false;
   3055  1.1  christos 	}
   3056  1.1  christos 	if (rdataset != NULL) {
   3057  1.1  christos 		NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
   3058  1.1  christos 			  isc_rwlocktype_read);
   3059  1.1  christos 		bind_rdataset(search->rbtdb, node, search->zonecut_rdataset,
   3060  1.1  christos 			      search->now, rdataset);
   3061  1.1  christos 		if (sigrdataset != NULL && search->zonecut_sigrdataset != NULL)
   3062  1.1  christos 			bind_rdataset(search->rbtdb, node,
   3063  1.1  christos 				      search->zonecut_sigrdataset,
   3064  1.1  christos 				      search->now, sigrdataset);
   3065  1.1  christos 		NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
   3066  1.1  christos 			    isc_rwlocktype_read);
   3067  1.1  christos 	}
   3068  1.1  christos 
   3069  1.1  christos 	if (type == dns_rdatatype_dname)
   3070  1.1  christos 		return (DNS_R_DNAME);
   3071  1.1  christos 	return (DNS_R_DELEGATION);
   3072  1.1  christos }
   3073  1.1  christos 
   3074  1.3  christos static inline bool
   3075  1.1  christos valid_glue(rbtdb_search_t *search, dns_name_t *name, rbtdb_rdatatype_t type,
   3076  1.1  christos 	   dns_rbtnode_t *node)
   3077  1.1  christos {
   3078  1.1  christos 	unsigned char *raw;     /* RDATASLAB */
   3079  1.1  christos 	unsigned int count, size;
   3080  1.1  christos 	dns_name_t ns_name;
   3081  1.3  christos 	bool valid = false;
   3082  1.1  christos 	dns_offsets_t offsets;
   3083  1.1  christos 	isc_region_t region;
   3084  1.1  christos 	rdatasetheader_t *header;
   3085  1.1  christos 
   3086  1.1  christos 	/*
   3087  1.1  christos 	 * No additional locking is required.
   3088  1.1  christos 	 */
   3089  1.1  christos 
   3090  1.1  christos 	/*
   3091  1.1  christos 	 * Valid glue types are A, AAAA, A6.  NS is also a valid glue type
   3092  1.1  christos 	 * if it occurs at a zone cut, but is not valid below it.
   3093  1.1  christos 	 */
   3094  1.1  christos 	if (type == dns_rdatatype_ns) {
   3095  1.1  christos 		if (node != search->zonecut) {
   3096  1.3  christos 			return (false);
   3097  1.1  christos 		}
   3098  1.1  christos 	} else if (type != dns_rdatatype_a &&
   3099  1.1  christos 		   type != dns_rdatatype_aaaa &&
   3100  1.1  christos 		   type != dns_rdatatype_a6) {
   3101  1.3  christos 		return (false);
   3102  1.1  christos 	}
   3103  1.1  christos 
   3104  1.1  christos 	header = search->zonecut_rdataset;
   3105  1.1  christos 	raw = (unsigned char *)header + sizeof(*header);
   3106  1.1  christos 	count = raw[0] * 256 + raw[1];
   3107  1.1  christos #if DNS_RDATASET_FIXED
   3108  1.1  christos 	raw += 2 + (4 * count);
   3109  1.1  christos #else
   3110  1.1  christos 	raw += 2;
   3111  1.1  christos #endif
   3112  1.1  christos 
   3113  1.1  christos 	while (count > 0) {
   3114  1.1  christos 		count--;
   3115  1.1  christos 		size = raw[0] * 256 + raw[1];
   3116  1.1  christos #if DNS_RDATASET_FIXED
   3117  1.1  christos 		raw += 4;
   3118  1.1  christos #else
   3119  1.1  christos 		raw += 2;
   3120  1.1  christos #endif
   3121  1.1  christos 		region.base = raw;
   3122  1.1  christos 		region.length = size;
   3123  1.1  christos 		raw += size;
   3124  1.1  christos 		/*
   3125  1.1  christos 		 * XXX Until we have rdata structures, we have no choice but
   3126  1.1  christos 		 * to directly access the rdata format.
   3127  1.1  christos 		 */
   3128  1.1  christos 		dns_name_init(&ns_name, offsets);
   3129  1.1  christos 		dns_name_fromregion(&ns_name, &region);
   3130  1.1  christos 		if (dns_name_compare(&ns_name, name) == 0) {
   3131  1.3  christos 			valid = true;
   3132  1.1  christos 			break;
   3133  1.1  christos 		}
   3134  1.1  christos 	}
   3135  1.1  christos 
   3136  1.1  christos 	return (valid);
   3137  1.1  christos }
   3138  1.1  christos 
   3139  1.3  christos static inline bool
   3140  1.1  christos activeempty(rbtdb_search_t *search, dns_rbtnodechain_t *chain,
   3141  1.1  christos 	    const dns_name_t *name)
   3142  1.1  christos {
   3143  1.1  christos 	dns_fixedname_t fnext;
   3144  1.1  christos 	dns_fixedname_t forigin;
   3145  1.1  christos 	dns_name_t *next;
   3146  1.1  christos 	dns_name_t *origin;
   3147  1.1  christos 	dns_name_t prefix;
   3148  1.1  christos 	dns_rbtdb_t *rbtdb;
   3149  1.1  christos 	dns_rbtnode_t *node;
   3150  1.1  christos 	isc_result_t result;
   3151  1.3  christos 	bool answer = false;
   3152  1.1  christos 	rdatasetheader_t *header;
   3153  1.1  christos 
   3154  1.1  christos 	rbtdb = search->rbtdb;
   3155  1.1  christos 
   3156  1.1  christos 	dns_name_init(&prefix, NULL);
   3157  1.1  christos 	next = dns_fixedname_initname(&fnext);
   3158  1.1  christos 	origin = dns_fixedname_initname(&forigin);
   3159  1.1  christos 
   3160  1.1  christos 	result = dns_rbtnodechain_next(chain, NULL, NULL);
   3161  1.1  christos 	while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
   3162  1.1  christos 		node = NULL;
   3163  1.1  christos 		result = dns_rbtnodechain_current(chain, &prefix,
   3164  1.1  christos 						  origin, &node);
   3165  1.1  christos 		if (result != ISC_R_SUCCESS)
   3166  1.1  christos 			break;
   3167  1.1  christos 		NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
   3168  1.1  christos 			  isc_rwlocktype_read);
   3169  1.1  christos 		for (header = node->data;
   3170  1.1  christos 		     header != NULL;
   3171  1.1  christos 		     header = header->next) {
   3172  1.1  christos 			if (header->serial <= search->serial &&
   3173  1.1  christos 			    !IGNORE(header) && EXISTS(header))
   3174  1.1  christos 				break;
   3175  1.1  christos 		}
   3176  1.1  christos 		NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
   3177  1.1  christos 			    isc_rwlocktype_read);
   3178  1.1  christos 		if (header != NULL)
   3179  1.1  christos 			break;
   3180  1.1  christos 		result = dns_rbtnodechain_next(chain, NULL, NULL);
   3181  1.1  christos 	}
   3182  1.1  christos 	if (result == ISC_R_SUCCESS)
   3183  1.1  christos 		result = dns_name_concatenate(&prefix, origin, next, NULL);
   3184  1.1  christos 	if (result == ISC_R_SUCCESS && dns_name_issubdomain(next, name))
   3185  1.3  christos 		answer = true;
   3186  1.1  christos 	return (answer);
   3187  1.1  christos }
   3188  1.1  christos 
   3189  1.3  christos static inline bool
   3190  1.1  christos activeemtpynode(rbtdb_search_t *search, const dns_name_t *qname,
   3191  1.1  christos 		dns_name_t *wname)
   3192  1.1  christos {
   3193  1.1  christos 	dns_fixedname_t fnext;
   3194  1.1  christos 	dns_fixedname_t forigin;
   3195  1.1  christos 	dns_fixedname_t fprev;
   3196  1.1  christos 	dns_name_t *next;
   3197  1.1  christos 	dns_name_t *origin;
   3198  1.1  christos 	dns_name_t *prev;
   3199  1.1  christos 	dns_name_t name;
   3200  1.1  christos 	dns_name_t rname;
   3201  1.1  christos 	dns_name_t tname;
   3202  1.1  christos 	dns_rbtdb_t *rbtdb;
   3203  1.1  christos 	dns_rbtnode_t *node;
   3204  1.1  christos 	dns_rbtnodechain_t chain;
   3205  1.3  christos 	bool check_next = true;
   3206  1.3  christos 	bool check_prev = true;
   3207  1.3  christos 	bool answer = false;
   3208  1.1  christos 	isc_result_t result;
   3209  1.1  christos 	rdatasetheader_t *header;
   3210  1.1  christos 	unsigned int n;
   3211  1.1  christos 
   3212  1.1  christos 	rbtdb = search->rbtdb;
   3213  1.1  christos 
   3214  1.1  christos 	dns_name_init(&name, NULL);
   3215  1.1  christos 	dns_name_init(&tname, NULL);
   3216  1.1  christos 	dns_name_init(&rname, NULL);
   3217  1.1  christos 	next = dns_fixedname_initname(&fnext);
   3218  1.1  christos 	prev = dns_fixedname_initname(&fprev);
   3219  1.1  christos 	origin = dns_fixedname_initname(&forigin);
   3220  1.1  christos 
   3221  1.1  christos 	/*
   3222  1.1  christos 	 * Find if qname is at or below a empty node.
   3223  1.1  christos 	 * Use our own copy of the chain.
   3224  1.1  christos 	 */
   3225  1.1  christos 
   3226  1.1  christos 	chain = search->chain;
   3227  1.1  christos 	do {
   3228  1.1  christos 		node = NULL;
   3229  1.1  christos 		result = dns_rbtnodechain_current(&chain, &name,
   3230  1.1  christos 						  origin, &node);
   3231  1.1  christos 		if (result != ISC_R_SUCCESS)
   3232  1.1  christos 			break;
   3233  1.1  christos 		NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
   3234  1.1  christos 			  isc_rwlocktype_read);
   3235  1.1  christos 		for (header = node->data;
   3236  1.1  christos 		     header != NULL;
   3237  1.1  christos 		     header = header->next) {
   3238  1.1  christos 			if (header->serial <= search->serial &&
   3239  1.1  christos 			    !IGNORE(header) && EXISTS(header))
   3240  1.1  christos 				break;
   3241  1.1  christos 		}
   3242  1.1  christos 		NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
   3243  1.1  christos 			    isc_rwlocktype_read);
   3244  1.1  christos 		if (header != NULL)
   3245  1.1  christos 			break;
   3246  1.1  christos 		result = dns_rbtnodechain_prev(&chain, NULL, NULL);
   3247  1.1  christos 	} while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN);
   3248  1.1  christos 	if (result == ISC_R_SUCCESS)
   3249  1.1  christos 		result = dns_name_concatenate(&name, origin, prev, NULL);
   3250  1.1  christos 	if (result != ISC_R_SUCCESS)
   3251  1.3  christos 		check_prev = false;
   3252  1.1  christos 
   3253  1.1  christos 	result = dns_rbtnodechain_next(&chain, NULL, NULL);
   3254  1.1  christos 	while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
   3255  1.1  christos 		node = NULL;
   3256  1.1  christos 		result = dns_rbtnodechain_current(&chain, &name,
   3257  1.1  christos 						  origin, &node);
   3258  1.1  christos 		if (result != ISC_R_SUCCESS)
   3259  1.1  christos 			break;
   3260  1.1  christos 		NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
   3261  1.1  christos 			  isc_rwlocktype_read);
   3262  1.1  christos 		for (header = node->data;
   3263  1.1  christos 		     header != NULL;
   3264  1.1  christos 		     header = header->next) {
   3265  1.1  christos 			if (header->serial <= search->serial &&
   3266  1.1  christos 			    !IGNORE(header) && EXISTS(header))
   3267  1.1  christos 				break;
   3268  1.1  christos 		}
   3269  1.1  christos 		NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
   3270  1.1  christos 			    isc_rwlocktype_read);
   3271  1.1  christos 		if (header != NULL)
   3272  1.1  christos 			break;
   3273  1.1  christos 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
   3274  1.1  christos 	}
   3275  1.1  christos 	if (result == ISC_R_SUCCESS)
   3276  1.1  christos 		result = dns_name_concatenate(&name, origin, next, NULL);
   3277  1.1  christos 	if (result != ISC_R_SUCCESS)
   3278  1.3  christos 		check_next = false;
   3279  1.1  christos 
   3280  1.1  christos 	dns_name_clone(qname, &rname);
   3281  1.1  christos 
   3282  1.1  christos 	/*
   3283  1.1  christos 	 * Remove the wildcard label to find the terminal name.
   3284  1.1  christos 	 */
   3285  1.1  christos 	n = dns_name_countlabels(wname);
   3286  1.1  christos 	dns_name_getlabelsequence(wname, 1, n - 1, &tname);
   3287  1.1  christos 
   3288  1.1  christos 	do {
   3289  1.1  christos 		if ((check_prev && dns_name_issubdomain(prev, &rname)) ||
   3290  1.1  christos 		    (check_next && dns_name_issubdomain(next, &rname))) {
   3291  1.3  christos 			answer = true;
   3292  1.1  christos 			break;
   3293  1.1  christos 		}
   3294  1.1  christos 		/*
   3295  1.1  christos 		 * Remove the left hand label.
   3296  1.1  christos 		 */
   3297  1.1  christos 		n = dns_name_countlabels(&rname);
   3298  1.1  christos 		dns_name_getlabelsequence(&rname, 1, n - 1, &rname);
   3299  1.1  christos 	} while (!dns_name_equal(&rname, &tname));
   3300  1.1  christos 	return (answer);
   3301  1.1  christos }
   3302  1.1  christos 
   3303  1.1  christos static inline isc_result_t
   3304  1.1  christos find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
   3305  1.1  christos 	      const dns_name_t *qname)
   3306  1.1  christos {
   3307  1.1  christos 	unsigned int i, j;
   3308  1.1  christos 	dns_rbtnode_t *node, *level_node, *wnode;
   3309  1.1  christos 	rdatasetheader_t *header;
   3310  1.1  christos 	isc_result_t result = ISC_R_NOTFOUND;
   3311  1.1  christos 	dns_name_t name;
   3312  1.1  christos 	dns_name_t *wname;
   3313  1.1  christos 	dns_fixedname_t fwname;
   3314  1.1  christos 	dns_rbtdb_t *rbtdb;
   3315  1.3  christos 	bool done, wild, active;
   3316  1.1  christos 	dns_rbtnodechain_t wchain;
   3317  1.1  christos 
   3318  1.1  christos 	/*
   3319  1.1  christos 	 * Caller must be holding the tree lock and MUST NOT be holding
   3320  1.1  christos 	 * any node locks.
   3321  1.1  christos 	 */
   3322  1.1  christos 
   3323  1.1  christos 	/*
   3324  1.1  christos 	 * Examine each ancestor level.  If the level's wild bit
   3325  1.1  christos 	 * is set, then construct the corresponding wildcard name and
   3326  1.1  christos 	 * search for it.  If the wildcard node exists, and is active in
   3327  1.1  christos 	 * this version, we're done.  If not, then we next check to see
   3328  1.1  christos 	 * if the ancestor is active in this version.  If so, then there
   3329  1.1  christos 	 * can be no possible wildcard match and again we're done.  If not,
   3330  1.1  christos 	 * continue the search.
   3331  1.1  christos 	 */
   3332  1.1  christos 
   3333  1.1  christos 	rbtdb = search->rbtdb;
   3334  1.1  christos 	i = search->chain.level_matches;
   3335  1.3  christos 	done = false;
   3336  1.1  christos 	node = *nodep;
   3337  1.1  christos 	do {
   3338  1.1  christos 		NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
   3339  1.1  christos 			  isc_rwlocktype_read);
   3340  1.1  christos 
   3341  1.1  christos 		/*
   3342  1.1  christos 		 * First we try to figure out if this node is active in
   3343  1.1  christos 		 * the search's version.  We do this now, even though we
   3344  1.1  christos 		 * may not need the information, because it simplifies the
   3345  1.1  christos 		 * locking and code flow.
   3346  1.1  christos 		 */
   3347  1.1  christos 		for (header = node->data;
   3348  1.1  christos 		     header != NULL;
   3349  1.1  christos 		     header = header->next) {
   3350  1.1  christos 			if (header->serial <= search->serial &&
   3351  1.1  christos 			    !IGNORE(header) && EXISTS(header))
   3352  1.1  christos 				break;
   3353  1.1  christos 		}
   3354  1.1  christos 		if (header != NULL)
   3355  1.3  christos 			active = true;
   3356  1.1  christos 		else
   3357  1.3  christos 			active = false;
   3358  1.1  christos 
   3359  1.1  christos 		if (node->wild)
   3360  1.3  christos 			wild = true;
   3361  1.1  christos 		else
   3362  1.3  christos 			wild = false;
   3363  1.1  christos 
   3364  1.1  christos 		NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
   3365  1.1  christos 			    isc_rwlocktype_read);
   3366  1.1  christos 
   3367  1.1  christos 		if (wild) {
   3368  1.1  christos 			/*
   3369  1.1  christos 			 * Construct the wildcard name for this level.
   3370  1.1  christos 			 */
   3371  1.1  christos 			dns_name_init(&name, NULL);
   3372  1.1  christos 			dns_rbt_namefromnode(node, &name);
   3373  1.1  christos 			wname = dns_fixedname_initname(&fwname);
   3374  1.1  christos 			result = dns_name_concatenate(dns_wildcardname, &name,
   3375  1.1  christos 						      wname, NULL);
   3376  1.1  christos 			j = i;
   3377  1.1  christos 			while (result == ISC_R_SUCCESS && j != 0) {
   3378  1.1  christos 				j--;
   3379  1.1  christos 				level_node = search->chain.levels[j];
   3380  1.1  christos 				dns_name_init(&name, NULL);
   3381  1.1  christos 				dns_rbt_namefromnode(level_node, &name);
   3382  1.1  christos 				result = dns_name_concatenate(wname,
   3383  1.1  christos 							      &name,
   3384  1.1  christos 							      wname,
   3385  1.1  christos 							      NULL);
   3386  1.1  christos 			}
   3387  1.1  christos 			if (result != ISC_R_SUCCESS)
   3388  1.1  christos 				break;
   3389  1.1  christos 
   3390  1.1  christos 			wnode = NULL;
   3391  1.1  christos 			dns_rbtnodechain_init(&wchain, NULL);
   3392  1.1  christos 			result = dns_rbt_findnode(rbtdb->tree, wname,
   3393  1.1  christos 						  NULL, &wnode, &wchain,
   3394  1.1  christos 						  DNS_RBTFIND_EMPTYDATA,
   3395  1.1  christos 						  NULL, NULL);
   3396  1.1  christos 			if (result == ISC_R_SUCCESS) {
   3397  1.1  christos 				nodelock_t *lock;
   3398  1.1  christos 
   3399  1.1  christos 				/*
   3400  1.1  christos 				 * We have found the wildcard node.  If it
   3401  1.1  christos 				 * is active in the search's version, we're
   3402  1.1  christos 				 * done.
   3403  1.1  christos 				 */
   3404  1.1  christos 				lock = &rbtdb->node_locks[wnode->locknum].lock;
   3405  1.1  christos 				NODE_LOCK(lock, isc_rwlocktype_read);
   3406  1.1  christos 				for (header = wnode->data;
   3407  1.1  christos 				     header != NULL;
   3408  1.1  christos 				     header = header->next) {
   3409  1.1  christos 					if (header->serial <= search->serial &&
   3410  1.1  christos 					    !IGNORE(header) && EXISTS(header))
   3411  1.1  christos 						break;
   3412  1.1  christos 				}
   3413  1.1  christos 				NODE_UNLOCK(lock, isc_rwlocktype_read);
   3414  1.1  christos 				if (header != NULL ||
   3415  1.1  christos 				    activeempty(search, &wchain, wname)) {
   3416  1.1  christos 					if (activeemtpynode(search, qname,
   3417  1.1  christos 							    wname)) {
   3418  1.1  christos 						return (ISC_R_NOTFOUND);
   3419  1.1  christos 					}
   3420  1.1  christos 					/*
   3421  1.1  christos 					 * The wildcard node is active!
   3422  1.1  christos 					 *
   3423  1.1  christos 					 * Note: result is still ISC_R_SUCCESS
   3424  1.1  christos 					 * so we don't have to set it.
   3425  1.1  christos 					 */
   3426  1.1  christos 					*nodep = wnode;
   3427  1.1  christos 					break;
   3428  1.1  christos 				}
   3429  1.1  christos 			} else if (result != ISC_R_NOTFOUND &&
   3430  1.1  christos 				   result != DNS_R_PARTIALMATCH) {
   3431  1.1  christos 				/*
   3432  1.1  christos 				 * An error has occurred.  Bail out.
   3433  1.1  christos 				 */
   3434  1.1  christos 				break;
   3435  1.1  christos 			}
   3436  1.1  christos 		}
   3437  1.1  christos 
   3438  1.1  christos 		if (active) {
   3439  1.1  christos 			/*
   3440  1.1  christos 			 * The level node is active.  Any wildcarding
   3441  1.1  christos 			 * present at higher levels has no
   3442  1.1  christos 			 * effect and we're done.
   3443  1.1  christos 			 */
   3444  1.1  christos 			result = ISC_R_NOTFOUND;
   3445  1.1  christos 			break;
   3446  1.1  christos 		}
   3447  1.1  christos 
   3448  1.1  christos 		if (i > 0) {
   3449  1.1  christos 			i--;
   3450  1.1  christos 			node = search->chain.levels[i];
   3451  1.1  christos 		} else
   3452  1.3  christos 			done = true;
   3453  1.1  christos 	} while (!done);
   3454  1.1  christos 
   3455  1.1  christos 	return (result);
   3456  1.1  christos }
   3457  1.1  christos 
   3458  1.3  christos static bool
   3459  1.1  christos matchparams(rdatasetheader_t *header, rbtdb_search_t *search)
   3460  1.1  christos {
   3461  1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   3462  1.1  christos 	dns_rdata_nsec3_t nsec3;
   3463  1.1  christos 	unsigned char *raw;                     /* RDATASLAB */
   3464  1.1  christos 	unsigned int rdlen, count;
   3465  1.1  christos 	isc_region_t region;
   3466  1.1  christos 	isc_result_t result;
   3467  1.1  christos 
   3468  1.1  christos 	REQUIRE(header->type == dns_rdatatype_nsec3);
   3469  1.1  christos 
   3470  1.1  christos 	raw = (unsigned char *)header + sizeof(*header);
   3471  1.1  christos 	count = raw[0] * 256 + raw[1]; /* count */
   3472  1.1  christos #if DNS_RDATASET_FIXED
   3473  1.1  christos 	raw += count * 4 + 2;
   3474  1.1  christos #else
   3475  1.1  christos 	raw += 2;
   3476  1.1  christos #endif
   3477  1.1  christos 	while (count-- > 0) {
   3478  1.1  christos 		rdlen = raw[0] * 256 + raw[1];
   3479  1.1  christos #if DNS_RDATASET_FIXED
   3480  1.1  christos 		raw += 4;
   3481  1.1  christos #else
   3482  1.1  christos 		raw += 2;
   3483  1.1  christos #endif
   3484  1.1  christos 		region.base = raw;
   3485  1.1  christos 		region.length = rdlen;
   3486  1.1  christos 		dns_rdata_fromregion(&rdata, search->rbtdb->common.rdclass,
   3487  1.1  christos 				     dns_rdatatype_nsec3, &region);
   3488  1.1  christos 		raw += rdlen;
   3489  1.1  christos 		result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
   3490  1.1  christos 		INSIST(result == ISC_R_SUCCESS);
   3491  1.1  christos 		if (nsec3.hash == search->rbtversion->hash &&
   3492  1.1  christos 		    nsec3.iterations == search->rbtversion->iterations &&
   3493  1.1  christos 		    nsec3.salt_length == search->rbtversion->salt_length &&
   3494  1.1  christos 		    memcmp(nsec3.salt, search->rbtversion->salt,
   3495  1.1  christos 			   nsec3.salt_length) == 0)
   3496  1.3  christos 			return (true);
   3497  1.1  christos 		dns_rdata_reset(&rdata);
   3498  1.1  christos 	}
   3499  1.3  christos 	return (false);
   3500  1.1  christos }
   3501  1.1  christos 
   3502  1.1  christos /*
   3503  1.1  christos  * Find node of the NSEC/NSEC3 record that is 'name'.
   3504  1.1  christos  */
   3505  1.1  christos static inline isc_result_t
   3506  1.1  christos previous_closest_nsec(dns_rdatatype_t type, rbtdb_search_t *search,
   3507  1.1  christos 		      dns_name_t *name, dns_name_t *origin,
   3508  1.1  christos 		      dns_rbtnode_t **nodep, dns_rbtnodechain_t *nsecchain,
   3509  1.3  christos 		      bool *firstp)
   3510  1.1  christos {
   3511  1.1  christos 	dns_fixedname_t ftarget;
   3512  1.1  christos 	dns_name_t *target;
   3513  1.1  christos 	dns_rbtnode_t *nsecnode;
   3514  1.1  christos 	isc_result_t result;
   3515  1.1  christos 
   3516  1.1  christos 	REQUIRE(nodep != NULL && *nodep == NULL);
   3517  1.1  christos 
   3518  1.1  christos 	if (type == dns_rdatatype_nsec3) {
   3519  1.1  christos 		result = dns_rbtnodechain_prev(&search->chain, NULL, NULL);
   3520  1.1  christos 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
   3521  1.1  christos 			return (result);
   3522  1.1  christos 		result = dns_rbtnodechain_current(&search->chain, name, origin,
   3523  1.1  christos 						  nodep);
   3524  1.1  christos 		return (result);
   3525  1.1  christos 	}
   3526  1.1  christos 
   3527  1.1  christos 	target = dns_fixedname_initname(&ftarget);
   3528  1.1  christos 
   3529  1.1  christos 	for (;;) {
   3530  1.1  christos 		if (*firstp) {
   3531  1.1  christos 			/*
   3532  1.1  christos 			 * Construct the name of the second node to check.
   3533  1.1  christos 			 * It is the first node sought in the NSEC tree.
   3534  1.1  christos 			 */
   3535  1.3  christos 			*firstp = false;
   3536  1.1  christos 			dns_rbtnodechain_init(nsecchain, NULL);
   3537  1.1  christos 			result = dns_name_concatenate(name, origin,
   3538  1.1  christos 						      target, NULL);
   3539  1.1  christos 			if (result != ISC_R_SUCCESS)
   3540  1.1  christos 				return (result);
   3541  1.1  christos 			nsecnode = NULL;
   3542  1.1  christos 			result = dns_rbt_findnode(search->rbtdb->nsec,
   3543  1.1  christos 						  target, NULL,
   3544  1.1  christos 						  &nsecnode, nsecchain,
   3545  1.1  christos 						  DNS_RBTFIND_NOOPTIONS,
   3546  1.1  christos 						  NULL, NULL);
   3547  1.1  christos 			if (result == ISC_R_SUCCESS) {
   3548  1.1  christos 				/*
   3549  1.1  christos 				 * Since this was the first loop, finding the
   3550  1.1  christos 				 * name in the NSEC tree implies that the first
   3551  1.1  christos 				 * node checked in the main tree had an
   3552  1.1  christos 				 * unacceptable NSEC record.
   3553  1.1  christos 				 * Try the previous node in the NSEC tree.
   3554  1.1  christos 				 */
   3555  1.1  christos 				result = dns_rbtnodechain_prev(nsecchain,
   3556  1.1  christos 							       name, origin);
   3557  1.1  christos 				if (result == DNS_R_NEWORIGIN)
   3558  1.1  christos 					result = ISC_R_SUCCESS;
   3559  1.1  christos 			} else if (result == ISC_R_NOTFOUND ||
   3560  1.1  christos 				   result == DNS_R_PARTIALMATCH) {
   3561  1.1  christos 				result = dns_rbtnodechain_current(nsecchain,
   3562  1.1  christos 							name, origin, NULL);
   3563  1.1  christos 				if (result == ISC_R_NOTFOUND)
   3564  1.1  christos 					result = ISC_R_NOMORE;
   3565  1.1  christos 			}
   3566  1.1  christos 		} else {
   3567  1.1  christos 			/*
   3568  1.1  christos 			 * This is a second or later trip through the auxiliary
   3569  1.1  christos 			 * tree for the name of a third or earlier NSEC node in
   3570  1.1  christos 			 * the main tree.  Previous trips through the NSEC tree
   3571  1.1  christos 			 * must have found nodes in the main tree with NSEC
   3572  1.1  christos 			 * records.  Perhaps they lacked signature records.
   3573  1.1  christos 			 */
   3574  1.1  christos 			result = dns_rbtnodechain_prev(nsecchain, name, origin);
   3575  1.1  christos 			if (result == DNS_R_NEWORIGIN)
   3576  1.1  christos 				result = ISC_R_SUCCESS;
   3577  1.1  christos 		}
   3578  1.1  christos 		if (result != ISC_R_SUCCESS)
   3579  1.1  christos 			return (result);
   3580  1.1  christos 
   3581  1.1  christos 		/*
   3582  1.1  christos 		 * Construct the name to seek in the main tree.
   3583  1.1  christos 		 */
   3584  1.1  christos 		result = dns_name_concatenate(name, origin, target, NULL);
   3585  1.1  christos 		if (result != ISC_R_SUCCESS)
   3586  1.1  christos 			return (result);
   3587  1.1  christos 
   3588  1.1  christos 		*nodep = NULL;
   3589  1.1  christos 		result = dns_rbt_findnode(search->rbtdb->tree, target, NULL,
   3590  1.1  christos 					  nodep, &search->chain,
   3591  1.1  christos 					  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
   3592  1.1  christos 		if (result == ISC_R_SUCCESS)
   3593  1.1  christos 			return (result);
   3594  1.1  christos 
   3595  1.1  christos 		/*
   3596  1.1  christos 		 * There should always be a node in the main tree with the
   3597  1.1  christos 		 * same name as the node in the auxiliary NSEC tree, except for
   3598  1.1  christos 		 * nodes in the auxiliary tree that are awaiting deletion.
   3599  1.1  christos 		 */
   3600  1.1  christos 		if (result != DNS_R_PARTIALMATCH && result != ISC_R_NOTFOUND) {
   3601  1.1  christos 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
   3602  1.1  christos 				      DNS_LOGMODULE_CACHE, ISC_LOG_ERROR,
   3603  1.1  christos 				      "previous_closest_nsec(): %s",
   3604  1.1  christos 				      isc_result_totext(result));
   3605  1.1  christos 			return (DNS_R_BADDB);
   3606  1.1  christos 		}
   3607  1.1  christos 	}
   3608  1.1  christos }
   3609  1.1  christos 
   3610  1.1  christos /*
   3611  1.1  christos  * Find the NSEC/NSEC3 which is or before the current point on the
   3612  1.1  christos  * search chain.  For NSEC3 records only NSEC3 records that match the
   3613  1.1  christos  * current NSEC3PARAM record are considered.
   3614  1.1  christos  */
   3615  1.1  christos static inline isc_result_t
   3616  1.1  christos find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
   3617  1.1  christos 		  dns_name_t *foundname, dns_rdataset_t *rdataset,
   3618  1.1  christos 		  dns_rdataset_t *sigrdataset, dns_rbt_t *tree,
   3619  1.1  christos 		  dns_db_secure_t secure)
   3620  1.1  christos {
   3621  1.1  christos 	dns_rbtnode_t *node, *prevnode;
   3622  1.1  christos 	rdatasetheader_t *header, *header_next, *found, *foundsig;
   3623  1.1  christos 	dns_rbtnodechain_t nsecchain;
   3624  1.3  christos 	bool empty_node;
   3625  1.1  christos 	isc_result_t result;
   3626  1.1  christos 	dns_fixedname_t fname, forigin;
   3627  1.1  christos 	dns_name_t *name, *origin;
   3628  1.1  christos 	dns_rdatatype_t type;
   3629  1.1  christos 	rbtdb_rdatatype_t sigtype;
   3630  1.3  christos 	bool wraps;
   3631  1.3  christos 	bool first = true;
   3632  1.3  christos 	bool need_sig = (secure == dns_db_secure);
   3633  1.1  christos 
   3634  1.1  christos 	if (tree == search->rbtdb->nsec3) {
   3635  1.1  christos 		type = dns_rdatatype_nsec3;
   3636  1.1  christos 		sigtype = RBTDB_RDATATYPE_SIGNSEC3;
   3637  1.3  christos 		wraps = true;
   3638  1.1  christos 	} else {
   3639  1.1  christos 		type = dns_rdatatype_nsec;
   3640  1.1  christos 		sigtype = RBTDB_RDATATYPE_SIGNSEC;
   3641  1.3  christos 		wraps = false;
   3642  1.1  christos 	}
   3643  1.1  christos 
   3644  1.1  christos 	/*
   3645  1.1  christos 	 * Use the auxiliary tree only starting with the second node in the
   3646  1.1  christos 	 * hope that the original node will be right much of the time.
   3647  1.1  christos 	 */
   3648  1.1  christos 	name = dns_fixedname_initname(&fname);
   3649  1.1  christos 	origin = dns_fixedname_initname(&forigin);
   3650  1.1  christos  again:
   3651  1.1  christos 	node = NULL;
   3652  1.1  christos 	prevnode = NULL;
   3653  1.1  christos 	result = dns_rbtnodechain_current(&search->chain, name, origin, &node);
   3654  1.1  christos 	if (result != ISC_R_SUCCESS)
   3655  1.1  christos 		return (result);
   3656  1.1  christos 	do {
   3657  1.1  christos 		NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
   3658  1.1  christos 			  isc_rwlocktype_read);
   3659  1.1  christos 		found = NULL;
   3660  1.1  christos 		foundsig = NULL;
   3661  1.3  christos 		empty_node = true;
   3662  1.1  christos 		for (header = node->data;
   3663  1.1  christos 		     header != NULL;
   3664  1.1  christos 		     header = header_next) {
   3665  1.1  christos 			header_next = header->next;
   3666  1.1  christos 			/*
   3667  1.1  christos 			 * Look for an active, extant NSEC or RRSIG NSEC.
   3668  1.1  christos 			 */
   3669  1.1  christos 			do {
   3670  1.1  christos 				if (header->serial <= search->serial &&
   3671  1.1  christos 				    !IGNORE(header)) {
   3672  1.1  christos 					/*
   3673  1.1  christos 					 * Is this a "this rdataset doesn't
   3674  1.1  christos 					 * exist" record?
   3675  1.1  christos 					 */
   3676  1.1  christos 					if (NONEXISTENT(header))
   3677  1.1  christos 						header = NULL;
   3678  1.1  christos 					break;
   3679  1.1  christos 				} else
   3680  1.1  christos 					header = header->down;
   3681  1.1  christos 			} while (header != NULL);
   3682  1.1  christos 			if (header != NULL) {
   3683  1.1  christos 				/*
   3684  1.1  christos 				 * We now know that there is at least one
   3685  1.1  christos 				 * active rdataset at this node.
   3686  1.1  christos 				 */
   3687  1.3  christos 				empty_node = false;
   3688  1.1  christos 				if (header->type == type) {
   3689  1.1  christos 					found = header;
   3690  1.1  christos 					if (foundsig != NULL)
   3691  1.1  christos 						break;
   3692  1.1  christos 				} else if (header->type == sigtype) {
   3693  1.1  christos 					foundsig = header;
   3694  1.1  christos 					if (found != NULL)
   3695  1.1  christos 						break;
   3696  1.1  christos 				}
   3697  1.1  christos 			}
   3698  1.1  christos 		}
   3699  1.1  christos 		if (!empty_node) {
   3700  1.1  christos 			if (found != NULL && search->rbtversion->havensec3 &&
   3701  1.1  christos 			    found->type == dns_rdatatype_nsec3 &&
   3702  1.1  christos 			    !matchparams(found, search)) {
   3703  1.3  christos 				empty_node = true;
   3704  1.1  christos 				found = NULL;
   3705  1.1  christos 				foundsig = NULL;
   3706  1.1  christos 				result = previous_closest_nsec(type, search,
   3707  1.1  christos 							       name, origin,
   3708  1.1  christos 							       &prevnode, NULL,
   3709  1.1  christos 							       NULL);
   3710  1.1  christos 			} else if (found != NULL &&
   3711  1.1  christos 				   (foundsig != NULL || !need_sig)) {
   3712  1.1  christos 				/*
   3713  1.1  christos 				 * We've found the right NSEC/NSEC3 record.
   3714  1.1  christos 				 *
   3715  1.1  christos 				 * Note: for this to really be the right
   3716  1.1  christos 				 * NSEC record, it's essential that the NSEC
   3717  1.1  christos 				 * records of any nodes obscured by a zone
   3718  1.1  christos 				 * cut have been removed; we assume this is
   3719  1.1  christos 				 * the case.
   3720  1.1  christos 				 */
   3721  1.1  christos 				result = dns_name_concatenate(name, origin,
   3722  1.1  christos 							      foundname, NULL);
   3723  1.1  christos 				if (result == ISC_R_SUCCESS) {
   3724  1.1  christos 					if (nodep != NULL) {
   3725  1.1  christos 						new_reference(search->rbtdb,
   3726  1.1  christos 							      node);
   3727  1.1  christos 						*nodep = node;
   3728  1.1  christos 					}
   3729  1.1  christos 					bind_rdataset(search->rbtdb, node,
   3730  1.1  christos 						      found, search->now,
   3731  1.1  christos 						      rdataset);
   3732  1.1  christos 					if (foundsig != NULL)
   3733  1.1  christos 						bind_rdataset(search->rbtdb,
   3734  1.1  christos 							      node,
   3735  1.1  christos 							      foundsig,
   3736  1.1  christos 							      search->now,
   3737  1.1  christos 							      sigrdataset);
   3738  1.1  christos 				}
   3739  1.1  christos 			} else if (found == NULL && foundsig == NULL) {
   3740  1.1  christos 				/*
   3741  1.1  christos 				 * This node is active, but has no NSEC or
   3742  1.1  christos 				 * RRSIG NSEC.  That means it's glue or
   3743  1.1  christos 				 * other obscured zone data that isn't
   3744  1.1  christos 				 * relevant for our search.  Treat the
   3745  1.1  christos 				 * node as if it were empty and keep looking.
   3746  1.1  christos 				 */
   3747  1.3  christos 				empty_node = true;
   3748  1.1  christos 				result = previous_closest_nsec(type, search,
   3749  1.1  christos 							       name, origin,
   3750  1.1  christos 							       &prevnode,
   3751  1.1  christos 							       &nsecchain,
   3752  1.1  christos 							       &first);
   3753  1.1  christos 			} else {
   3754  1.1  christos 				/*
   3755  1.1  christos 				 * We found an active node, but either the
   3756  1.1  christos 				 * NSEC or the RRSIG NSEC is missing.  This
   3757  1.1  christos 				 * shouldn't happen.
   3758  1.1  christos 				 */
   3759  1.1  christos 				result = DNS_R_BADDB;
   3760  1.1  christos 			}
   3761  1.1  christos 		} else {
   3762  1.1  christos 			/*
   3763  1.1  christos 			 * This node isn't active.  We've got to keep
   3764  1.1  christos 			 * looking.
   3765  1.1  christos 			 */
   3766  1.1  christos 			result = previous_closest_nsec(type, search,
   3767  1.1  christos 						       name, origin, &prevnode,
   3768  1.1  christos 						       &nsecchain, &first);
   3769  1.1  christos 		}
   3770  1.1  christos 		NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
   3771  1.1  christos 			    isc_rwlocktype_read);
   3772  1.1  christos 		node = prevnode;
   3773  1.1  christos 		prevnode = NULL;
   3774  1.1  christos 	} while (empty_node && result == ISC_R_SUCCESS);
   3775  1.1  christos 
   3776  1.1  christos 	if (!first)
   3777  1.1  christos 		dns_rbtnodechain_invalidate(&nsecchain);
   3778  1.1  christos 
   3779  1.1  christos 	if (result == ISC_R_NOMORE && wraps) {
   3780  1.1  christos 		result = dns_rbtnodechain_last(&search->chain, tree,
   3781  1.1  christos 					       NULL, NULL);
   3782  1.1  christos 		if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
   3783  1.3  christos 			wraps = false;
   3784  1.1  christos 			goto again;
   3785  1.1  christos 		}
   3786  1.1  christos 	}
   3787  1.1  christos 
   3788  1.1  christos 	/*
   3789  1.1  christos 	 * If the result is ISC_R_NOMORE, then we got to the beginning of
   3790  1.1  christos 	 * the database and didn't find a NSEC record.  This shouldn't
   3791  1.1  christos 	 * happen.
   3792  1.1  christos 	 */
   3793  1.1  christos 	if (result == ISC_R_NOMORE)
   3794  1.1  christos 		result = DNS_R_BADDB;
   3795  1.1  christos 
   3796  1.1  christos 	return (result);
   3797  1.1  christos }
   3798  1.1  christos 
   3799  1.1  christos static isc_result_t
   3800  1.1  christos zone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
   3801  1.1  christos 	  dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
   3802  1.1  christos 	  dns_dbnode_t **nodep, dns_name_t *foundname,
   3803  1.1  christos 	  dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
   3804  1.1  christos {
   3805  1.1  christos 	dns_rbtnode_t *node = NULL;
   3806  1.1  christos 	isc_result_t result;
   3807  1.1  christos 	rbtdb_search_t search;
   3808  1.3  christos 	bool cname_ok = true;
   3809  1.3  christos 	bool close_version = false;
   3810  1.3  christos 	bool maybe_zonecut = false;
   3811  1.3  christos 	bool at_zonecut = false;
   3812  1.3  christos 	bool wild;
   3813  1.3  christos 	bool empty_node;
   3814  1.1  christos 	rdatasetheader_t *header, *header_next, *found, *nsecheader;
   3815  1.1  christos 	rdatasetheader_t *foundsig, *cnamesig, *nsecsig;
   3816  1.1  christos 	rbtdb_rdatatype_t sigtype;
   3817  1.3  christos 	bool active;
   3818  1.1  christos 	dns_rbtnodechain_t chain;
   3819  1.1  christos 	nodelock_t *lock;
   3820  1.1  christos 	dns_rbt_t *tree;
   3821  1.1  christos 
   3822  1.1  christos 	search.rbtdb = (dns_rbtdb_t *)db;
   3823  1.1  christos 
   3824  1.1  christos 	REQUIRE(VALID_RBTDB(search.rbtdb));
   3825  1.1  christos 	INSIST(version == NULL ||
   3826  1.1  christos 	       ((rbtdb_version_t *)version)->rbtdb == (dns_rbtdb_t *)db);
   3827  1.1  christos 
   3828  1.1  christos 	/*
   3829  1.1  christos 	 * We don't care about 'now'.
   3830  1.1  christos 	 */
   3831  1.1  christos 	UNUSED(now);
   3832  1.1  christos 
   3833  1.1  christos 	/*
   3834  1.1  christos 	 * If the caller didn't supply a version, attach to the current
   3835  1.1  christos 	 * version.
   3836  1.1  christos 	 */
   3837  1.1  christos 	if (version == NULL) {
   3838  1.1  christos 		currentversion(db, &version);
   3839  1.3  christos 		close_version = true;
   3840  1.1  christos 	}
   3841  1.1  christos 
   3842  1.1  christos 	search.rbtversion = version;
   3843  1.1  christos 	search.serial = search.rbtversion->serial;
   3844  1.1  christos 	search.options = options;
   3845  1.3  christos 	search.copy_name = false;
   3846  1.3  christos 	search.need_cleanup = false;
   3847  1.3  christos 	search.wild = false;
   3848  1.1  christos 	search.zonecut = NULL;
   3849  1.1  christos 	dns_fixedname_init(&search.zonecut_name);
   3850  1.1  christos 	dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
   3851  1.1  christos 	search.now = 0;
   3852  1.1  christos 
   3853  1.1  christos 	/*
   3854  1.1  christos 	 * 'wild' will be true iff. we've matched a wildcard.
   3855  1.1  christos 	 */
   3856  1.3  christos 	wild = false;
   3857  1.1  christos 
   3858  1.1  christos 	RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
   3859  1.1  christos 
   3860  1.1  christos 	/*
   3861  1.1  christos 	 * Search down from the root of the tree.  If, while going down, we
   3862  1.1  christos 	 * encounter a callback node, zone_zonecut_callback() will search the
   3863  1.1  christos 	 * rdatasets at the zone cut for active DNAME or NS rdatasets.
   3864  1.1  christos 	 */
   3865  1.1  christos 	tree =  (options & DNS_DBFIND_FORCENSEC3) != 0 ? search.rbtdb->nsec3 :
   3866  1.1  christos 							 search.rbtdb->tree;
   3867  1.1  christos 	result = dns_rbt_findnode(tree, name, foundname, &node,
   3868  1.1  christos 				  &search.chain, DNS_RBTFIND_EMPTYDATA,
   3869  1.1  christos 				  zone_zonecut_callback, &search);
   3870  1.1  christos 
   3871  1.1  christos 	if (result == DNS_R_PARTIALMATCH) {
   3872  1.1  christos 	partial_match:
   3873  1.1  christos 		if (search.zonecut != NULL) {
   3874  1.1  christos 		    result = setup_delegation(&search, nodep, foundname,
   3875  1.1  christos 					      rdataset, sigrdataset);
   3876  1.1  christos 		    goto tree_exit;
   3877  1.1  christos 		}
   3878  1.1  christos 
   3879  1.1  christos 		if (search.wild) {
   3880  1.1  christos 			/*
   3881  1.1  christos 			 * At least one of the levels in the search chain
   3882  1.1  christos 			 * potentially has a wildcard.  For each such level,
   3883  1.1  christos 			 * we must see if there's a matching wildcard active
   3884  1.1  christos 			 * in the current version.
   3885  1.1  christos 			 */
   3886  1.1  christos 			result = find_wildcard(&search, &node, name);
   3887  1.1  christos 			if (result == ISC_R_SUCCESS) {
   3888  1.1  christos 				result = dns_name_copy(name, foundname, NULL);
   3889  1.1  christos 				if (result != ISC_R_SUCCESS)
   3890  1.1  christos 					goto tree_exit;
   3891  1.3  christos 				wild = true;
   3892  1.1  christos 				goto found;
   3893  1.1  christos 			}
   3894  1.1  christos 			else if (result != ISC_R_NOTFOUND)
   3895  1.1  christos 				goto tree_exit;
   3896  1.1  christos 		}
   3897  1.1  christos 
   3898  1.1  christos 		chain = search.chain;
   3899  1.1  christos 		active = activeempty(&search, &chain, name);
   3900  1.1  christos 
   3901  1.1  christos 		/*
   3902  1.1  christos 		 * If we're here, then the name does not exist, is not
   3903  1.1  christos 		 * beneath a zonecut, and there's no matching wildcard.
   3904  1.1  christos 		 */
   3905  1.1  christos 		if ((search.rbtversion->secure == dns_db_secure &&
   3906  1.1  christos 		     !search.rbtversion->havensec3) ||
   3907  1.1  christos 		    (search.options & DNS_DBFIND_FORCENSEC) != 0 ||
   3908  1.1  christos 		    (search.options & DNS_DBFIND_FORCENSEC3) != 0)
   3909  1.1  christos 		{
   3910  1.1  christos 			result = find_closest_nsec(&search, nodep, foundname,
   3911  1.1  christos 						   rdataset, sigrdataset, tree,
   3912  1.1  christos 						   search.rbtversion->secure);
   3913  1.1  christos 			if (result == ISC_R_SUCCESS)
   3914  1.1  christos 				result = active ? DNS_R_EMPTYNAME :
   3915  1.1  christos 						  DNS_R_NXDOMAIN;
   3916  1.1  christos 		} else
   3917  1.1  christos 			result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN;
   3918  1.1  christos 		goto tree_exit;
   3919  1.1  christos 	} else if (result != ISC_R_SUCCESS)
   3920  1.1  christos 		goto tree_exit;
   3921  1.1  christos 
   3922  1.1  christos  found:
   3923  1.1  christos 	/*
   3924  1.1  christos 	 * We have found a node whose name is the desired name, or we
   3925  1.1  christos 	 * have matched a wildcard.
   3926  1.1  christos 	 */
   3927  1.1  christos 
   3928  1.1  christos 	if (search.zonecut != NULL) {
   3929  1.1  christos 		/*
   3930  1.1  christos 		 * If we're beneath a zone cut, we don't want to look for
   3931  1.1  christos 		 * CNAMEs because they're not legitimate zone glue.
   3932  1.1  christos 		 */
   3933  1.3  christos 		cname_ok = false;
   3934  1.1  christos 	} else {
   3935  1.1  christos 		/*
   3936  1.1  christos 		 * The node may be a zone cut itself.  If it might be one,
   3937  1.1  christos 		 * make sure we check for it later.
   3938  1.1  christos 		 *
   3939  1.1  christos 		 * DS records live above the zone cut in ordinary zone so
   3940  1.1  christos 		 * we want to ignore any referral.
   3941  1.1  christos 		 *
   3942  1.1  christos 		 * Stub zones don't have anything "above" the delgation so
   3943  1.1  christos 		 * we always return a referral.
   3944  1.1  christos 		 */
   3945  1.1  christos 		if (node->find_callback &&
   3946  1.1  christos 		    ((node != search.rbtdb->origin_node &&
   3947  1.1  christos 		      !dns_rdatatype_atparent(type)) ||
   3948  1.1  christos 		     IS_STUB(search.rbtdb)))
   3949  1.3  christos 			maybe_zonecut = true;
   3950  1.1  christos 	}
   3951  1.1  christos 
   3952  1.1  christos 	/*
   3953  1.1  christos 	 * Certain DNSSEC types are not subject to CNAME matching
   3954  1.1  christos 	 * (RFC4035, section 2.5 and RFC3007).
   3955  1.1  christos 	 *
   3956  1.1  christos 	 * We don't check for RRSIG, because we don't store RRSIG records
   3957  1.1  christos 	 * directly.
   3958  1.1  christos 	 */
   3959  1.1  christos 	if (type == dns_rdatatype_key || type == dns_rdatatype_nsec)
   3960  1.3  christos 		cname_ok = false;
   3961  1.1  christos 
   3962  1.1  christos 	/*
   3963  1.1  christos 	 * We now go looking for rdata...
   3964  1.1  christos 	 */
   3965  1.1  christos 
   3966  1.1  christos 	lock = &search.rbtdb->node_locks[node->locknum].lock;
   3967  1.1  christos 	NODE_LOCK(lock, isc_rwlocktype_read);
   3968  1.1  christos 
   3969  1.1  christos 	found = NULL;
   3970  1.1  christos 	foundsig = NULL;
   3971  1.1  christos 	sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
   3972  1.1  christos 	nsecheader = NULL;
   3973  1.1  christos 	nsecsig = NULL;
   3974  1.1  christos 	cnamesig = NULL;
   3975  1.3  christos 	empty_node = true;
   3976  1.1  christos 	for (header = node->data; header != NULL; header = header_next) {
   3977  1.1  christos 		header_next = header->next;
   3978  1.1  christos 		/*
   3979  1.1  christos 		 * Look for an active, extant rdataset.
   3980  1.1  christos 		 */
   3981  1.1  christos 		do {
   3982  1.1  christos 			if (header->serial <= search.serial &&
   3983  1.1  christos 			    !IGNORE(header)) {
   3984  1.1  christos 				/*
   3985  1.1  christos 				 * Is this a "this rdataset doesn't
   3986  1.1  christos 				 * exist" record?
   3987  1.1  christos 				 */
   3988  1.1  christos 				if (NONEXISTENT(header))
   3989  1.1  christos 					header = NULL;
   3990  1.1  christos 				break;
   3991  1.1  christos 			} else
   3992  1.1  christos 				header = header->down;
   3993  1.1  christos 		} while (header != NULL);
   3994  1.1  christos 		if (header != NULL) {
   3995  1.1  christos 			/*
   3996  1.1  christos 			 * We now know that there is at least one active
   3997  1.1  christos 			 * rdataset at this node.
   3998  1.1  christos 			 */
   3999  1.3  christos 			empty_node = false;
   4000  1.1  christos 
   4001  1.1  christos 			/*
   4002  1.1  christos 			 * Do special zone cut handling, if requested.
   4003  1.1  christos 			 */
   4004  1.1  christos 			if (maybe_zonecut &&
   4005  1.1  christos 			    header->type == dns_rdatatype_ns) {
   4006  1.1  christos 				/*
   4007  1.1  christos 				 * We increment the reference count on node to
   4008  1.1  christos 				 * ensure that search->zonecut_rdataset will
   4009  1.1  christos 				 * still be valid later.
   4010  1.1  christos 				 */
   4011  1.1  christos 				new_reference(search.rbtdb, node);
   4012  1.1  christos 				search.zonecut = node;
   4013  1.1  christos 				search.zonecut_rdataset = header;
   4014  1.1  christos 				search.zonecut_sigrdataset = NULL;
   4015  1.3  christos 				search.need_cleanup = true;
   4016  1.3  christos 				maybe_zonecut = false;
   4017  1.3  christos 				at_zonecut = true;
   4018  1.1  christos 				/*
   4019  1.1  christos 				 * It is not clear if KEY should still be
   4020  1.1  christos 				 * allowed at the parent side of the zone
   4021  1.1  christos 				 * cut or not.  It is needed for RFC3007
   4022  1.1  christos 				 * validated updates.
   4023  1.1  christos 				 */
   4024  1.1  christos 				if ((search.options & DNS_DBFIND_GLUEOK) == 0
   4025  1.1  christos 				    && type != dns_rdatatype_nsec
   4026  1.1  christos 				    && type != dns_rdatatype_key) {
   4027  1.1  christos 					/*
   4028  1.1  christos 					 * Glue is not OK, but any answer we
   4029  1.1  christos 					 * could return would be glue.  Return
   4030  1.1  christos 					 * the delegation.
   4031  1.1  christos 					 */
   4032  1.1  christos 					found = NULL;
   4033  1.1  christos 					break;
   4034  1.1  christos 				}
   4035  1.1  christos 				if (found != NULL && foundsig != NULL)
   4036  1.1  christos 					break;
   4037  1.1  christos 			}
   4038  1.1  christos 
   4039  1.1  christos 
   4040  1.1  christos 			/*
   4041  1.1  christos 			 * If the NSEC3 record doesn't match the chain
   4042  1.1  christos 			 * we are using behave as if it isn't here.
   4043  1.1  christos 			 */
   4044  1.1  christos 			if (header->type == dns_rdatatype_nsec3 &&
   4045  1.1  christos 			   !matchparams(header, &search)) {
   4046  1.1  christos 				NODE_UNLOCK(lock, isc_rwlocktype_read);
   4047  1.1  christos 				goto partial_match;
   4048  1.1  christos 			}
   4049  1.1  christos 			/*
   4050  1.1  christos 			 * If we found a type we were looking for,
   4051  1.1  christos 			 * remember it.
   4052  1.1  christos 			 */
   4053  1.1  christos 			if (header->type == type ||
   4054  1.1  christos 			    type == dns_rdatatype_any ||
   4055  1.1  christos 			    (header->type == dns_rdatatype_cname &&
   4056  1.1  christos 			     cname_ok)) {
   4057  1.1  christos 				/*
   4058  1.1  christos 				 * We've found the answer!
   4059  1.1  christos 				 */
   4060  1.1  christos 				found = header;
   4061  1.1  christos 				if (header->type == dns_rdatatype_cname &&
   4062  1.1  christos 				    cname_ok) {
   4063  1.1  christos 					/*
   4064  1.1  christos 					 * We may be finding a CNAME instead
   4065  1.1  christos 					 * of the desired type.
   4066  1.1  christos 					 *
   4067  1.1  christos 					 * If we've already got the CNAME RRSIG,
   4068  1.1  christos 					 * use it, otherwise change sigtype
   4069  1.1  christos 					 * so that we find it.
   4070  1.1  christos 					 */
   4071  1.1  christos 					if (cnamesig != NULL)
   4072  1.1  christos 						foundsig = cnamesig;
   4073  1.1  christos 					else
   4074  1.1  christos 						sigtype =
   4075  1.1  christos 						    RBTDB_RDATATYPE_SIGCNAME;
   4076  1.1  christos 				}
   4077  1.1  christos 				/*
   4078  1.1  christos 				 * If we've got all we need, end the search.
   4079  1.1  christos 				 */
   4080  1.1  christos 				if (!maybe_zonecut && foundsig != NULL)
   4081  1.1  christos 					break;
   4082  1.1  christos 			} else if (header->type == sigtype) {
   4083  1.1  christos 				/*
   4084  1.1  christos 				 * We've found the RRSIG rdataset for our
   4085  1.1  christos 				 * target type.  Remember it.
   4086  1.1  christos 				 */
   4087  1.1  christos 				foundsig = header;
   4088  1.1  christos 				/*
   4089  1.1  christos 				 * If we've got all we need, end the search.
   4090  1.1  christos 				 */
   4091  1.1  christos 				if (!maybe_zonecut && found != NULL)
   4092  1.1  christos 					break;
   4093  1.1  christos 			} else if (header->type == dns_rdatatype_nsec &&
   4094  1.1  christos 				   !search.rbtversion->havensec3) {
   4095  1.1  christos 				/*
   4096  1.1  christos 				 * Remember a NSEC rdataset even if we're
   4097  1.1  christos 				 * not specifically looking for it, because
   4098  1.1  christos 				 * we might need it later.
   4099  1.1  christos 				 */
   4100  1.1  christos 				nsecheader = header;
   4101  1.1  christos 			} else if (header->type == RBTDB_RDATATYPE_SIGNSEC &&
   4102  1.1  christos 				   !search.rbtversion->havensec3) {
   4103  1.1  christos 				/*
   4104  1.1  christos 				 * If we need the NSEC rdataset, we'll also
   4105  1.1  christos 				 * need its signature.
   4106  1.1  christos 				 */
   4107  1.1  christos 				nsecsig = header;
   4108  1.1  christos 			} else if (cname_ok &&
   4109  1.1  christos 				   header->type == RBTDB_RDATATYPE_SIGCNAME) {
   4110  1.1  christos 				/*
   4111  1.1  christos 				 * If we get a CNAME match, we'll also need
   4112  1.1  christos 				 * its signature.
   4113  1.1  christos 				 */
   4114  1.1  christos 				cnamesig = header;
   4115  1.1  christos 			}
   4116  1.1  christos 		}
   4117  1.1  christos 	}
   4118  1.1  christos 
   4119  1.1  christos 	if (empty_node) {
   4120  1.1  christos 		/*
   4121  1.1  christos 		 * We have an exact match for the name, but there are no
   4122  1.1  christos 		 * active rdatasets in the desired version.  That means that
   4123  1.1  christos 		 * this node doesn't exist in the desired version, and that
   4124  1.1  christos 		 * we really have a partial match.
   4125  1.1  christos 		 */
   4126  1.1  christos 		if (!wild) {
   4127  1.1  christos 			NODE_UNLOCK(lock, isc_rwlocktype_read);
   4128  1.1  christos 			goto partial_match;
   4129  1.1  christos 		}
   4130  1.1  christos 	}
   4131  1.1  christos 
   4132  1.1  christos 	/*
   4133  1.1  christos 	 * If we didn't find what we were looking for...
   4134  1.1  christos 	 */
   4135  1.1  christos 	if (found == NULL) {
   4136  1.1  christos 		if (search.zonecut != NULL) {
   4137  1.1  christos 			/*
   4138  1.1  christos 			 * We were trying to find glue at a node beneath a
   4139  1.1  christos 			 * zone cut, but didn't.
   4140  1.1  christos 			 *
   4141  1.1  christos 			 * Return the delegation.
   4142  1.1  christos 			 */
   4143  1.1  christos 			NODE_UNLOCK(lock, isc_rwlocktype_read);
   4144  1.1  christos 			result = setup_delegation(&search, nodep, foundname,
   4145  1.1  christos 						  rdataset, sigrdataset);
   4146  1.1  christos 			goto tree_exit;
   4147  1.1  christos 		}
   4148  1.1  christos 		/*
   4149  1.1  christos 		 * The desired type doesn't exist.
   4150  1.1  christos 		 */
   4151  1.1  christos 		result = DNS_R_NXRRSET;
   4152  1.1  christos 		if (search.rbtversion->secure == dns_db_secure &&
   4153  1.1  christos 		    !search.rbtversion->havensec3 &&
   4154  1.1  christos 		    (nsecheader == NULL || nsecsig == NULL)) {
   4155  1.1  christos 			/*
   4156  1.1  christos 			 * The zone is secure but there's no NSEC,
   4157  1.1  christos 			 * or the NSEC has no signature!
   4158  1.1  christos 			 */
   4159  1.1  christos 			if (!wild) {
   4160  1.1  christos 				result = DNS_R_BADDB;
   4161  1.1  christos 				goto node_exit;
   4162  1.1  christos 			}
   4163  1.1  christos 
   4164  1.1  christos 			NODE_UNLOCK(lock, isc_rwlocktype_read);
   4165  1.1  christos 			result = find_closest_nsec(&search, nodep, foundname,
   4166  1.1  christos 						   rdataset, sigrdataset,
   4167  1.1  christos 						   search.rbtdb->tree,
   4168  1.1  christos 						   search.rbtversion->secure);
   4169  1.1  christos 			if (result == ISC_R_SUCCESS)
   4170  1.1  christos 				result = DNS_R_EMPTYWILD;
   4171  1.1  christos 			goto tree_exit;
   4172  1.1  christos 		}
   4173  1.1  christos 		if ((search.options & DNS_DBFIND_FORCENSEC) != 0 &&
   4174  1.1  christos 		    nsecheader == NULL)
   4175  1.1  christos 		{
   4176  1.1  christos 			/*
   4177  1.1  christos 			 * There's no NSEC record, and we were told
   4178  1.1  christos 			 * to find one.
   4179  1.1  christos 			 */
   4180  1.1  christos 			result = DNS_R_BADDB;
   4181  1.1  christos 			goto node_exit;
   4182  1.1  christos 		}
   4183  1.1  christos 		if (nodep != NULL) {
   4184  1.1  christos 			new_reference(search.rbtdb, node);
   4185  1.1  christos 			*nodep = node;
   4186  1.1  christos 		}
   4187  1.1  christos 		if ((search.rbtversion->secure == dns_db_secure &&
   4188  1.1  christos 		     !search.rbtversion->havensec3) ||
   4189  1.1  christos 		    (search.options & DNS_DBFIND_FORCENSEC) != 0)
   4190  1.1  christos 		{
   4191  1.1  christos 			bind_rdataset(search.rbtdb, node, nsecheader,
   4192  1.1  christos 				      0, rdataset);
   4193  1.1  christos 			if (nsecsig != NULL)
   4194  1.1  christos 				bind_rdataset(search.rbtdb, node,
   4195  1.1  christos 					      nsecsig, 0, sigrdataset);
   4196  1.1  christos 		}
   4197  1.1  christos 		if (wild)
   4198  1.1  christos 			foundname->attributes |= DNS_NAMEATTR_WILDCARD;
   4199  1.1  christos 		goto node_exit;
   4200  1.1  christos 	}
   4201  1.1  christos 
   4202  1.1  christos 	/*
   4203  1.1  christos 	 * We found what we were looking for, or we found a CNAME.
   4204  1.1  christos 	 */
   4205  1.1  christos 
   4206  1.1  christos 	if (type != found->type &&
   4207  1.1  christos 	    type != dns_rdatatype_any &&
   4208  1.1  christos 	    found->type == dns_rdatatype_cname) {
   4209  1.1  christos 		/*
   4210  1.1  christos 		 * We weren't doing an ANY query and we found a CNAME instead
   4211  1.1  christos 		 * of the type we were looking for, so we need to indicate
   4212  1.1  christos 		 * that result to the caller.
   4213  1.1  christos 		 */
   4214  1.1  christos 		result = DNS_R_CNAME;
   4215  1.1  christos 	} else if (search.zonecut != NULL) {
   4216  1.1  christos 		/*
   4217  1.1  christos 		 * If we're beneath a zone cut, we must indicate that the
   4218  1.1  christos 		 * result is glue, unless we're actually at the zone cut
   4219  1.1  christos 		 * and the type is NSEC or KEY.
   4220  1.1  christos 		 */
   4221  1.1  christos 		if (search.zonecut == node) {
   4222  1.1  christos 			/*
   4223  1.1  christos 			 * It is not clear if KEY should still be
   4224  1.1  christos 			 * allowed at the parent side of the zone
   4225  1.1  christos 			 * cut or not.  It is needed for RFC3007
   4226  1.1  christos 			 * validated updates.
   4227  1.1  christos 			 */
   4228  1.1  christos 			if (type == dns_rdatatype_nsec ||
   4229  1.1  christos 			    type == dns_rdatatype_nsec3 ||
   4230  1.1  christos 			    type == dns_rdatatype_key)
   4231  1.1  christos 				result = ISC_R_SUCCESS;
   4232  1.1  christos 			else if (type == dns_rdatatype_any)
   4233  1.1  christos 				result = DNS_R_ZONECUT;
   4234  1.1  christos 			else
   4235  1.1  christos 				result = DNS_R_GLUE;
   4236  1.1  christos 		} else
   4237  1.1  christos 			result = DNS_R_GLUE;
   4238  1.1  christos 		/*
   4239  1.1  christos 		 * We might have found data that isn't glue, but was occluded
   4240  1.1  christos 		 * by a dynamic update.  If the caller cares about this, they
   4241  1.1  christos 		 * will have told us to validate glue.
   4242  1.1  christos 		 *
   4243  1.1  christos 		 * XXX We should cache the glue validity state!
   4244  1.1  christos 		 */
   4245  1.1  christos 		if (result == DNS_R_GLUE &&
   4246  1.1  christos 		    (search.options & DNS_DBFIND_VALIDATEGLUE) != 0 &&
   4247  1.1  christos 		    !valid_glue(&search, foundname, type, node)) {
   4248  1.1  christos 			NODE_UNLOCK(lock, isc_rwlocktype_read);
   4249  1.1  christos 			result = setup_delegation(&search, nodep, foundname,
   4250  1.1  christos 						  rdataset, sigrdataset);
   4251  1.1  christos 		    goto tree_exit;
   4252  1.1  christos 		}
   4253  1.1  christos 	} else {
   4254  1.1  christos 		/*
   4255  1.1  christos 		 * An ordinary successful query!
   4256  1.1  christos 		 */
   4257  1.1  christos 		result = ISC_R_SUCCESS;
   4258  1.1  christos 	}
   4259  1.1  christos 
   4260  1.1  christos 	if (nodep != NULL) {
   4261  1.1  christos 		if (!at_zonecut)
   4262  1.1  christos 			new_reference(search.rbtdb, node);
   4263  1.1  christos 		else
   4264  1.3  christos 			search.need_cleanup = false;
   4265  1.1  christos 		*nodep = node;
   4266  1.1  christos 	}
   4267  1.1  christos 
   4268  1.1  christos 	if (type != dns_rdatatype_any) {
   4269  1.1  christos 		bind_rdataset(search.rbtdb, node, found, 0, rdataset);
   4270  1.1  christos 		if (foundsig != NULL)
   4271  1.1  christos 			bind_rdataset(search.rbtdb, node, foundsig, 0,
   4272  1.1  christos 				      sigrdataset);
   4273  1.1  christos 	}
   4274  1.1  christos 
   4275  1.1  christos 	if (wild)
   4276  1.1  christos 		foundname->attributes |= DNS_NAMEATTR_WILDCARD;
   4277  1.1  christos 
   4278  1.1  christos  node_exit:
   4279  1.1  christos 	NODE_UNLOCK(lock, isc_rwlocktype_read);
   4280  1.1  christos 
   4281  1.1  christos  tree_exit:
   4282  1.1  christos 	RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
   4283  1.1  christos 
   4284  1.1  christos 	/*
   4285  1.1  christos 	 * If we found a zonecut but aren't going to use it, we have to
   4286  1.1  christos 	 * let go of it.
   4287  1.1  christos 	 */
   4288  1.1  christos 	if (search.need_cleanup) {
   4289  1.1  christos 		node = search.zonecut;
   4290  1.1  christos 		INSIST(node != NULL);
   4291  1.1  christos 		lock = &(search.rbtdb->node_locks[node->locknum].lock);
   4292  1.1  christos 
   4293  1.1  christos 		NODE_LOCK(lock, isc_rwlocktype_read);
   4294  1.1  christos 		decrement_reference(search.rbtdb, node, 0,
   4295  1.1  christos 				    isc_rwlocktype_read, isc_rwlocktype_none,
   4296  1.3  christos 				    false);
   4297  1.1  christos 		NODE_UNLOCK(lock, isc_rwlocktype_read);
   4298  1.1  christos 	}
   4299  1.1  christos 
   4300  1.1  christos 	if (close_version)
   4301  1.3  christos 		closeversion(db, &version, false);
   4302  1.1  christos 
   4303  1.1  christos 	dns_rbtnodechain_reset(&search.chain);
   4304  1.1  christos 
   4305  1.1  christos 	return (result);
   4306  1.1  christos }
   4307  1.1  christos 
   4308  1.1  christos static isc_result_t
   4309  1.1  christos zone_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
   4310  1.1  christos 		 isc_stdtime_t now, dns_dbnode_t **nodep,
   4311  1.3  christos 		 dns_name_t *foundname, dns_name_t *dcname,
   4312  1.1  christos 		 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
   4313  1.1  christos {
   4314  1.1  christos 	UNUSED(db);
   4315  1.1  christos 	UNUSED(name);
   4316  1.1  christos 	UNUSED(options);
   4317  1.1  christos 	UNUSED(now);
   4318  1.1  christos 	UNUSED(nodep);
   4319  1.1  christos 	UNUSED(foundname);
   4320  1.3  christos 	UNUSED(dcname);
   4321  1.1  christos 	UNUSED(rdataset);
   4322  1.1  christos 	UNUSED(sigrdataset);
   4323  1.1  christos 
   4324  1.1  christos 	FATAL_ERROR(__FILE__, __LINE__, "zone_findzonecut() called!");
   4325  1.1  christos 
   4326  1.1  christos 	/* NOTREACHED */
   4327  1.1  christos 	return (ISC_R_NOTIMPLEMENTED);
   4328  1.1  christos }
   4329  1.1  christos 
   4330  1.3  christos static bool
   4331  1.1  christos check_stale_header(dns_rbtnode_t *node, rdatasetheader_t *header,
   4332  1.1  christos 		   isc_rwlocktype_t *locktype, nodelock_t *lock,
   4333  1.1  christos 		   rbtdb_search_t *search, rdatasetheader_t **header_prev)
   4334  1.1  christos {
   4335  1.1  christos 
   4336  1.1  christos 	if (!ACTIVE(header, search->now)) {
   4337  1.1  christos 		dns_ttl_t stale = header->rdh_ttl +
   4338  1.1  christos 				  search->rbtdb->serve_stale_ttl;
   4339  1.1  christos 		/*
   4340  1.1  christos 		 * If this data is in the stale window keep it and if
   4341  1.1  christos 		 * DNS_DBFIND_STALEOK is not set we tell the caller to
   4342  1.1  christos 		 * skip this record.
   4343  1.1  christos 		 */
   4344  1.1  christos 		if (KEEPSTALE(search->rbtdb) && stale > search->now) {
   4345  1.1  christos 			header->attributes |= RDATASET_ATTR_STALE;
   4346  1.1  christos 			*header_prev = header;
   4347  1.1  christos 			return ((search->options & DNS_DBFIND_STALEOK) == 0);
   4348  1.1  christos 		}
   4349  1.1  christos 
   4350  1.1  christos 		/*
   4351  1.1  christos 		 * This rdataset is stale.  If no one else is using the
   4352  1.1  christos 		 * node, we can clean it up right now, otherwise we mark
   4353  1.1  christos 		 * it as stale, and the node as dirty, so it will get
   4354  1.1  christos 		 * cleaned up later.
   4355  1.1  christos 		 */
   4356  1.1  christos 		if ((header->rdh_ttl < search->now - RBTDB_VIRTUAL) &&
   4357  1.1  christos 		    (*locktype == isc_rwlocktype_write ||
   4358  1.1  christos 		     NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS))
   4359  1.1  christos 		{
   4360  1.1  christos 			/*
   4361  1.1  christos 			 * We update the node's status only when we can
   4362  1.1  christos 			 * get write access; otherwise, we leave others
   4363  1.1  christos 			 * to this work.  Periodical cleaning will
   4364  1.1  christos 			 * eventually take the job as the last resort.
   4365  1.1  christos 			 * We won't downgrade the lock, since other
   4366  1.1  christos 			 * rdatasets are probably stale, too.
   4367  1.1  christos 			 */
   4368  1.1  christos 			*locktype = isc_rwlocktype_write;
   4369  1.1  christos 
   4370  1.3  christos 			if (isc_refcount_current(&node->references) == 0) {
   4371  1.1  christos 				isc_mem_t *mctx;
   4372  1.1  christos 
   4373  1.1  christos 				/*
   4374  1.1  christos 				 * header->down can be non-NULL if the
   4375  1.1  christos 				 * refcount has just decremented to 0
   4376  1.1  christos 				 * but decrement_reference() has not
   4377  1.1  christos 				 * performed clean_cache_node(), in
   4378  1.1  christos 				 * which case we need to purge the stale
   4379  1.1  christos 				 * headers first.
   4380  1.1  christos 				 */
   4381  1.1  christos 				mctx = search->rbtdb->common.mctx;
   4382  1.1  christos 				clean_stale_headers(search->rbtdb, mctx, header);
   4383  1.1  christos 				if (*header_prev != NULL)
   4384  1.1  christos 					(*header_prev)->next = header->next;
   4385  1.1  christos 				else
   4386  1.1  christos 					node->data = header->next;
   4387  1.1  christos 				free_rdataset(search->rbtdb, mctx, header);
   4388  1.1  christos 			} else {
   4389  1.1  christos 				mark_header_ancient(search->rbtdb, header);
   4390  1.1  christos 				*header_prev = header;
   4391  1.1  christos 			}
   4392  1.1  christos 		} else
   4393  1.1  christos 			*header_prev = header;
   4394  1.3  christos 		return (true);
   4395  1.1  christos 	}
   4396  1.3  christos 	return (false);
   4397  1.1  christos }
   4398  1.1  christos 
   4399  1.1  christos static isc_result_t
   4400  1.1  christos cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
   4401  1.1  christos 	rbtdb_search_t *search = arg;
   4402  1.1  christos 	rdatasetheader_t *header, *header_prev, *header_next;
   4403  1.1  christos 	rdatasetheader_t *dname_header, *sigdname_header;
   4404  1.1  christos 	isc_result_t result;
   4405  1.1  christos 	nodelock_t *lock;
   4406  1.1  christos 	isc_rwlocktype_t locktype;
   4407  1.1  christos 
   4408  1.1  christos 	/* XXX comment */
   4409  1.1  christos 
   4410  1.1  christos 	REQUIRE(search->zonecut == NULL);
   4411  1.1  christos 
   4412  1.1  christos 	/*
   4413  1.1  christos 	 * Keep compiler silent.
   4414  1.1  christos 	 */
   4415  1.1  christos 	UNUSED(name);
   4416  1.1  christos 
   4417  1.1  christos 	lock = &(search->rbtdb->node_locks[node->locknum].lock);
   4418  1.1  christos 	locktype = isc_rwlocktype_read;
   4419  1.1  christos 	NODE_LOCK(lock, locktype);
   4420  1.1  christos 
   4421  1.1  christos 	/*
   4422  1.1  christos 	 * Look for a DNAME or RRSIG DNAME rdataset.
   4423  1.1  christos 	 */
   4424  1.1  christos 	dname_header = NULL;
   4425  1.1  christos 	sigdname_header = NULL;
   4426  1.1  christos 	header_prev = NULL;
   4427  1.1  christos 	for (header = node->data; header != NULL; header = header_next) {
   4428  1.1  christos 		header_next = header->next;
   4429  1.1  christos 		if (check_stale_header(node, header,
   4430  1.1  christos 				       &locktype, lock, search,
   4431  1.1  christos 				       &header_prev)) {
   4432  1.1  christos 			/* Do nothing. */
   4433  1.1  christos 		} else if (header->type == dns_rdatatype_dname &&
   4434  1.1  christos 			   EXISTS(header)) {
   4435  1.1  christos 			dname_header = header;
   4436  1.1  christos 			header_prev = header;
   4437  1.1  christos 		} else if (header->type == RBTDB_RDATATYPE_SIGDNAME &&
   4438  1.1  christos 			 EXISTS(header)) {
   4439  1.1  christos 			sigdname_header = header;
   4440  1.1  christos 			header_prev = header;
   4441  1.1  christos 		} else
   4442  1.1  christos 			header_prev = header;
   4443  1.1  christos 	}
   4444  1.1  christos 
   4445  1.1  christos 	if (dname_header != NULL &&
   4446  1.1  christos 	    (!DNS_TRUST_PENDING(dname_header->trust) ||
   4447  1.1  christos 	     (search->options & DNS_DBFIND_PENDINGOK) != 0)) {
   4448  1.1  christos 		/*
   4449  1.1  christos 		 * We increment the reference count on node to ensure that
   4450  1.1  christos 		 * search->zonecut_rdataset will still be valid later.
   4451  1.1  christos 		 */
   4452  1.1  christos 		new_reference(search->rbtdb, node);
   4453  1.1  christos 		INSIST(!ISC_LINK_LINKED(node, deadlink));
   4454  1.1  christos 		search->zonecut = node;
   4455  1.1  christos 		search->zonecut_rdataset = dname_header;
   4456  1.1  christos 		search->zonecut_sigrdataset = sigdname_header;
   4457  1.3  christos 		search->need_cleanup = true;
   4458  1.1  christos 		result = DNS_R_PARTIALMATCH;
   4459  1.1  christos 	} else
   4460  1.1  christos 		result = DNS_R_CONTINUE;
   4461  1.1  christos 
   4462  1.1  christos 	NODE_UNLOCK(lock, locktype);
   4463  1.1  christos 
   4464  1.1  christos 	return (result);
   4465  1.1  christos }
   4466  1.1  christos 
   4467  1.1  christos static inline isc_result_t
   4468  1.1  christos find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
   4469  1.1  christos 		     dns_dbnode_t **nodep, dns_name_t *foundname,
   4470  1.1  christos 		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
   4471  1.1  christos {
   4472  1.1  christos 	unsigned int i;
   4473  1.1  christos 	dns_rbtnode_t *level_node;
   4474  1.1  christos 	rdatasetheader_t *header, *header_prev, *header_next;
   4475  1.1  christos 	rdatasetheader_t *found, *foundsig;
   4476  1.1  christos 	isc_result_t result = ISC_R_NOTFOUND;
   4477  1.1  christos 	dns_name_t name;
   4478  1.1  christos 	dns_rbtdb_t *rbtdb;
   4479  1.3  christos 	bool done;
   4480  1.1  christos 	nodelock_t *lock;
   4481  1.1  christos 	isc_rwlocktype_t locktype;
   4482  1.1  christos 
   4483  1.1  christos 	/*
   4484  1.1  christos 	 * Caller must be holding the tree lock.
   4485  1.1  christos 	 */
   4486  1.1  christos 
   4487  1.1  christos 	rbtdb = search->rbtdb;
   4488  1.1  christos 	i = search->chain.level_matches;
   4489  1.3  christos 	done = false;
   4490  1.1  christos 	do {
   4491  1.1  christos 		locktype = isc_rwlocktype_read;
   4492  1.1  christos 		lock = &rbtdb->node_locks[node->locknum].lock;
   4493  1.1  christos 		NODE_LOCK(lock, locktype);
   4494  1.1  christos 
   4495  1.1  christos 		/*
   4496  1.1  christos 		 * Look for NS and RRSIG NS rdatasets.
   4497  1.1  christos 		 */
   4498  1.1  christos 		found = NULL;
   4499  1.1  christos 		foundsig = NULL;
   4500  1.1  christos 		header_prev = NULL;
   4501  1.1  christos 		for (header = node->data; header != NULL; header = header_next) {
   4502  1.1  christos 			header_next = header->next;
   4503  1.1  christos 			if (check_stale_header(node, header,
   4504  1.1  christos 					       &locktype, lock, search,
   4505  1.1  christos 					       &header_prev)) {
   4506  1.1  christos 				/* Do nothing. */
   4507  1.1  christos 			} else if (EXISTS(header)) {
   4508  1.1  christos 				/*
   4509  1.1  christos 				 * We've found an extant rdataset.  See if
   4510  1.1  christos 				 * we're interested in it.
   4511  1.1  christos 				 */
   4512  1.1  christos 				if (header->type == dns_rdatatype_ns) {
   4513  1.1  christos 					found = header;
   4514  1.1  christos 					if (foundsig != NULL)
   4515  1.1  christos 						break;
   4516  1.1  christos 				} else if (header->type ==
   4517  1.1  christos 					   RBTDB_RDATATYPE_SIGNS) {
   4518  1.1  christos 					foundsig = header;
   4519  1.1  christos 					if (found != NULL)
   4520  1.1  christos 						break;
   4521  1.1  christos 				}
   4522  1.1  christos 				header_prev = header;
   4523  1.1  christos 			} else
   4524  1.1  christos 				header_prev = header;
   4525  1.1  christos 		}
   4526  1.1  christos 
   4527  1.1  christos 		if (found != NULL) {
   4528  1.1  christos 			/*
   4529  1.1  christos 			 * If we have to set foundname, we do it before
   4530  1.1  christos 			 * anything else.  If we were to set foundname after
   4531  1.1  christos 			 * we had set nodep or bound the rdataset, then we'd
   4532  1.1  christos 			 * have to undo that work if dns_name_concatenate()
   4533  1.1  christos 			 * failed.  By setting foundname first, there's
   4534  1.1  christos 			 * nothing to undo if we have trouble.
   4535  1.1  christos 			 */
   4536  1.1  christos 			if (foundname != NULL) {
   4537  1.1  christos 				dns_name_init(&name, NULL);
   4538  1.1  christos 				dns_rbt_namefromnode(node, &name);
   4539  1.1  christos 				result = dns_name_copy(&name, foundname, NULL);
   4540  1.1  christos 				while (result == ISC_R_SUCCESS && i > 0) {
   4541  1.1  christos 					i--;
   4542  1.1  christos 					level_node = search->chain.levels[i];
   4543  1.1  christos 					dns_name_init(&name, NULL);
   4544  1.1  christos 					dns_rbt_namefromnode(level_node,
   4545  1.1  christos 							     &name);
   4546  1.1  christos 					result =
   4547  1.1  christos 						dns_name_concatenate(foundname,
   4548  1.1  christos 								     &name,
   4549  1.1  christos 								     foundname,
   4550  1.1  christos 								     NULL);
   4551  1.1  christos 				}
   4552  1.1  christos 				if (result != ISC_R_SUCCESS) {
   4553  1.1  christos 					*nodep = NULL;
   4554  1.1  christos 					goto node_exit;
   4555  1.1  christos 				}
   4556  1.1  christos 			}
   4557  1.1  christos 			result = DNS_R_DELEGATION;
   4558  1.1  christos 			if (nodep != NULL) {
   4559  1.1  christos 				new_reference(search->rbtdb, node);
   4560  1.1  christos 				*nodep = node;
   4561  1.1  christos 			}
   4562  1.1  christos 			bind_rdataset(search->rbtdb, node, found, search->now,
   4563  1.1  christos 				      rdataset);
   4564  1.1  christos 			if (foundsig != NULL)
   4565  1.1  christos 				bind_rdataset(search->rbtdb, node, foundsig,
   4566  1.1  christos 					      search->now, sigrdataset);
   4567  1.1  christos 			if (need_headerupdate(found, search->now) ||
   4568  1.1  christos 			    (foundsig != NULL &&
   4569  1.1  christos 			     need_headerupdate(foundsig, search->now))) {
   4570  1.1  christos 				if (locktype != isc_rwlocktype_write) {
   4571  1.1  christos 					NODE_UNLOCK(lock, locktype);
   4572  1.1  christos 					NODE_LOCK(lock, isc_rwlocktype_write);
   4573  1.1  christos 					locktype = isc_rwlocktype_write;
   4574  1.1  christos 					POST(locktype);
   4575  1.1  christos 				}
   4576  1.1  christos 				if (need_headerupdate(found, search->now))
   4577  1.1  christos 					update_header(search->rbtdb, found,
   4578  1.1  christos 						      search->now);
   4579  1.1  christos 				if (foundsig != NULL &&
   4580  1.1  christos 				    need_headerupdate(foundsig, search->now)) {
   4581  1.1  christos 					update_header(search->rbtdb, foundsig,
   4582  1.1  christos 						      search->now);
   4583  1.1  christos 				}
   4584  1.1  christos 			}
   4585  1.1  christos 		}
   4586  1.1  christos 
   4587  1.1  christos 	node_exit:
   4588  1.1  christos 		NODE_UNLOCK(lock, locktype);
   4589  1.1  christos 
   4590  1.1  christos 		if (found == NULL && i > 0) {
   4591  1.1  christos 			i--;
   4592  1.1  christos 			node = search->chain.levels[i];
   4593  1.1  christos 		} else
   4594  1.3  christos 			done = true;
   4595  1.1  christos 
   4596  1.1  christos 	} while (!done);
   4597  1.1  christos 
   4598  1.1  christos 	return (result);
   4599  1.1  christos }
   4600  1.1  christos 
   4601  1.1  christos static isc_result_t
   4602  1.1  christos find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
   4603  1.1  christos 		  isc_stdtime_t now, dns_name_t *foundname,
   4604  1.1  christos 		  dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
   4605  1.1  christos {
   4606  1.1  christos 	dns_rbtnode_t *node;
   4607  1.1  christos 	rdatasetheader_t *header, *header_next, *header_prev;
   4608  1.1  christos 	rdatasetheader_t *found, *foundsig;
   4609  1.3  christos 	bool empty_node;
   4610  1.1  christos 	isc_result_t result;
   4611  1.1  christos 	dns_fixedname_t fname, forigin;
   4612  1.1  christos 	dns_name_t *name, *origin;
   4613  1.1  christos 	rbtdb_rdatatype_t matchtype, sigmatchtype;
   4614  1.1  christos 	nodelock_t *lock;
   4615  1.1  christos 	isc_rwlocktype_t locktype;
   4616  1.1  christos 	dns_rbtnodechain_t chain;
   4617  1.1  christos 
   4618  1.1  christos 	chain = search->chain;
   4619  1.1  christos 
   4620  1.1  christos 	matchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_nsec, 0);
   4621  1.1  christos 	sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig,
   4622  1.1  christos 					     dns_rdatatype_nsec);
   4623  1.1  christos 
   4624  1.1  christos 	do {
   4625  1.1  christos 		node = NULL;
   4626  1.1  christos 		name = dns_fixedname_initname(&fname);
   4627  1.1  christos 		origin = dns_fixedname_initname(&forigin);
   4628  1.1  christos 		result = dns_rbtnodechain_current(&chain, name, origin, &node);
   4629  1.1  christos 		if (result != ISC_R_SUCCESS)
   4630  1.1  christos 			return (result);
   4631  1.1  christos 		locktype = isc_rwlocktype_read;
   4632  1.1  christos 		lock = &(search->rbtdb->node_locks[node->locknum].lock);
   4633  1.1  christos 		NODE_LOCK(lock, locktype);
   4634  1.1  christos 		found = NULL;
   4635  1.1  christos 		foundsig = NULL;
   4636  1.3  christos 		empty_node = true;
   4637  1.1  christos 		header_prev = NULL;
   4638  1.1  christos 		for (header = node->data; header != NULL; header = header_next)
   4639  1.1  christos 		{
   4640  1.1  christos 			header_next = header->next;
   4641  1.1  christos 			if (check_stale_header(node, header,
   4642  1.1  christos 					       &locktype, lock, search,
   4643  1.1  christos 					       &header_prev)) {
   4644  1.1  christos 				continue;
   4645  1.1  christos 			}
   4646  1.1  christos 			if (NONEXISTENT(header) ||
   4647  1.1  christos 			    RBTDB_RDATATYPE_BASE(header->type) == 0) {
   4648  1.1  christos 				header_prev = header;
   4649  1.1  christos 				continue;
   4650  1.1  christos 			}
   4651  1.1  christos 			/*
   4652  1.1  christos 			 * Don't stop on provable noqname / RRSIG.
   4653  1.1  christos 			 */
   4654  1.1  christos 			if (header->noqname == NULL &&
   4655  1.1  christos 			    RBTDB_RDATATYPE_BASE(header->type)
   4656  1.1  christos 			     != dns_rdatatype_rrsig)
   4657  1.1  christos 			{
   4658  1.3  christos 				empty_node = false;
   4659  1.1  christos 			}
   4660  1.1  christos 			if (header->type == matchtype)
   4661  1.1  christos 				found = header;
   4662  1.1  christos 			else if (header->type == sigmatchtype)
   4663  1.1  christos 				foundsig = header;
   4664  1.1  christos 			header_prev = header;
   4665  1.1  christos 		}
   4666  1.1  christos 		if (found != NULL) {
   4667  1.1  christos 			result = dns_name_concatenate(name, origin,
   4668  1.1  christos 						      foundname, NULL);
   4669  1.1  christos 			if (result != ISC_R_SUCCESS)
   4670  1.1  christos 				goto unlock_node;
   4671  1.1  christos 			bind_rdataset(search->rbtdb, node, found,
   4672  1.1  christos 				      now, rdataset);
   4673  1.1  christos 			if (foundsig != NULL)
   4674  1.1  christos 				bind_rdataset(search->rbtdb, node, foundsig,
   4675  1.1  christos 					      now, sigrdataset);
   4676  1.1  christos 			new_reference(search->rbtdb, node);
   4677  1.1  christos 			*nodep = node;
   4678  1.1  christos 			result = DNS_R_COVERINGNSEC;
   4679  1.1  christos 		} else if (!empty_node) {
   4680  1.1  christos 			result = ISC_R_NOTFOUND;
   4681  1.1  christos 		} else
   4682  1.1  christos 			result = dns_rbtnodechain_prev(&chain, NULL, NULL);
   4683  1.1  christos  unlock_node:
   4684  1.1  christos 		NODE_UNLOCK(lock, locktype);
   4685  1.1  christos 	} while (empty_node && result == ISC_R_SUCCESS);
   4686  1.1  christos 	return (result);
   4687  1.1  christos }
   4688  1.1  christos 
   4689  1.1  christos static isc_result_t
   4690  1.1  christos cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
   4691  1.1  christos 	   dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
   4692  1.1  christos 	   dns_dbnode_t **nodep, dns_name_t *foundname,
   4693  1.1  christos 	   dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
   4694  1.1  christos {
   4695  1.1  christos 	dns_rbtnode_t *node = NULL;
   4696  1.1  christos 	isc_result_t result;
   4697  1.1  christos 	rbtdb_search_t search;
   4698  1.3  christos 	bool cname_ok = true;
   4699  1.3  christos 	bool empty_node;
   4700  1.1  christos 	nodelock_t *lock;
   4701  1.1  christos 	isc_rwlocktype_t locktype;
   4702  1.1  christos 	rdatasetheader_t *header, *header_prev, *header_next;
   4703  1.1  christos 	rdatasetheader_t *found, *nsheader;
   4704  1.1  christos 	rdatasetheader_t *foundsig, *nssig, *cnamesig;
   4705  1.1  christos 	rdatasetheader_t *update, *updatesig;
   4706  1.1  christos 	rdatasetheader_t *nsecheader, *nsecsig;
   4707  1.1  christos 	rbtdb_rdatatype_t sigtype, negtype;
   4708  1.1  christos 
   4709  1.1  christos 	UNUSED(version);
   4710  1.1  christos 
   4711  1.1  christos 	search.rbtdb = (dns_rbtdb_t *)db;
   4712  1.1  christos 
   4713  1.1  christos 	REQUIRE(VALID_RBTDB(search.rbtdb));
   4714  1.1  christos 	REQUIRE(version == NULL);
   4715  1.1  christos 
   4716  1.1  christos 	if (now == 0)
   4717  1.1  christos 		isc_stdtime_get(&now);
   4718  1.1  christos 
   4719  1.1  christos 	search.rbtversion = NULL;
   4720  1.1  christos 	search.serial = 1;
   4721  1.1  christos 	search.options = options;
   4722  1.3  christos 	search.copy_name = false;
   4723  1.3  christos 	search.need_cleanup = false;
   4724  1.3  christos 	search.wild = false;
   4725  1.1  christos 	search.zonecut = NULL;
   4726  1.1  christos 	dns_fixedname_init(&search.zonecut_name);
   4727  1.1  christos 	dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
   4728  1.1  christos 	search.now = now;
   4729  1.1  christos 	update = NULL;
   4730  1.1  christos 	updatesig = NULL;
   4731  1.1  christos 
   4732  1.1  christos 	RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
   4733  1.1  christos 
   4734  1.1  christos 	/*
   4735  1.1  christos 	 * Search down from the root of the tree.  If, while going down, we
   4736  1.1  christos 	 * encounter a callback node, cache_zonecut_callback() will search the
   4737  1.1  christos 	 * rdatasets at the zone cut for a DNAME rdataset.
   4738  1.1  christos 	 */
   4739  1.1  christos 	result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
   4740  1.1  christos 				  &search.chain, DNS_RBTFIND_EMPTYDATA,
   4741  1.1  christos 				  cache_zonecut_callback, &search);
   4742  1.1  christos 
   4743  1.1  christos 	if (result == DNS_R_PARTIALMATCH) {
   4744  1.1  christos 		if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) {
   4745  1.1  christos 			result = find_coveringnsec(&search, nodep, now,
   4746  1.1  christos 						   foundname, rdataset,
   4747  1.1  christos 						   sigrdataset);
   4748  1.1  christos 			if (result == DNS_R_COVERINGNSEC)
   4749  1.1  christos 				goto tree_exit;
   4750  1.1  christos 		}
   4751  1.1  christos 		if (search.zonecut != NULL) {
   4752  1.1  christos 		    result = setup_delegation(&search, nodep, foundname,
   4753  1.1  christos 					      rdataset, sigrdataset);
   4754  1.1  christos 		    goto tree_exit;
   4755  1.1  christos 		} else {
   4756  1.1  christos 		find_ns:
   4757  1.1  christos 			result = find_deepest_zonecut(&search, node, nodep,
   4758  1.1  christos 						      foundname, rdataset,
   4759  1.1  christos 						      sigrdataset);
   4760  1.1  christos 			goto tree_exit;
   4761  1.1  christos 		}
   4762  1.1  christos 	} else if (result != ISC_R_SUCCESS)
   4763  1.1  christos 		goto tree_exit;
   4764  1.1  christos 
   4765  1.1  christos 	/*
   4766  1.1  christos 	 * Certain DNSSEC types are not subject to CNAME matching
   4767  1.1  christos 	 * (RFC4035, section 2.5 and RFC3007).
   4768  1.1  christos 	 *
   4769  1.1  christos 	 * We don't check for RRSIG, because we don't store RRSIG records
   4770  1.1  christos 	 * directly.
   4771  1.1  christos 	 */
   4772  1.1  christos 	if (type == dns_rdatatype_key || type == dns_rdatatype_nsec)
   4773  1.3  christos 		cname_ok = false;
   4774  1.1  christos 
   4775  1.1  christos 	/*
   4776  1.1  christos 	 * We now go looking for rdata...
   4777  1.1  christos 	 */
   4778  1.1  christos 
   4779  1.1  christos 	lock = &(search.rbtdb->node_locks[node->locknum].lock);
   4780  1.1  christos 	locktype = isc_rwlocktype_read;
   4781  1.1  christos 	NODE_LOCK(lock, locktype);
   4782  1.1  christos 
   4783  1.1  christos 	found = NULL;
   4784  1.1  christos 	foundsig = NULL;
   4785  1.1  christos 	sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
   4786  1.1  christos 	negtype = RBTDB_RDATATYPE_VALUE(0, type);
   4787  1.1  christos 	nsheader = NULL;
   4788  1.1  christos 	nsecheader = NULL;
   4789  1.1  christos 	nssig = NULL;
   4790  1.1  christos 	nsecsig = NULL;
   4791  1.1  christos 	cnamesig = NULL;
   4792  1.3  christos 	empty_node = true;
   4793  1.1  christos 	header_prev = NULL;
   4794  1.1  christos 	for (header = node->data; header != NULL; header = header_next) {
   4795  1.1  christos 		header_next = header->next;
   4796  1.1  christos 		if (check_stale_header(node, header,
   4797  1.1  christos 				       &locktype, lock, &search,
   4798  1.1  christos 				       &header_prev)) {
   4799  1.1  christos 			/* Do nothing. */
   4800  1.1  christos 		} else if (EXISTS(header) && !ANCIENT(header)) {
   4801  1.1  christos 			/*
   4802  1.1  christos 			 * We now know that there is at least one active
   4803  1.1  christos 			 * non-stale rdataset at this node.
   4804  1.1  christos 			 */
   4805  1.3  christos 			empty_node = false;
   4806  1.1  christos 
   4807  1.1  christos 			/*
   4808  1.1  christos 			 * If we found a type we were looking for, remember
   4809  1.1  christos 			 * it.
   4810  1.1  christos 			 */
   4811  1.1  christos 			if (header->type == type ||
   4812  1.1  christos 			    (type == dns_rdatatype_any &&
   4813  1.1  christos 			     RBTDB_RDATATYPE_BASE(header->type) != 0) ||
   4814  1.1  christos 			    (cname_ok && header->type ==
   4815  1.1  christos 			     dns_rdatatype_cname)) {
   4816  1.1  christos 				/*
   4817  1.1  christos 				 * We've found the answer.
   4818  1.1  christos 				 */
   4819  1.1  christos 				found = header;
   4820  1.1  christos 				if (header->type == dns_rdatatype_cname &&
   4821  1.1  christos 				    cname_ok &&
   4822  1.1  christos 				    cnamesig != NULL) {
   4823  1.1  christos 					/*
   4824  1.1  christos 					 * If we've already got the
   4825  1.1  christos 					 * CNAME RRSIG, use it.
   4826  1.1  christos 					 */
   4827  1.1  christos 					foundsig = cnamesig;
   4828  1.1  christos 				}
   4829  1.1  christos 			} else if (header->type == sigtype) {
   4830  1.1  christos 				/*
   4831  1.1  christos 				 * We've found the RRSIG rdataset for our
   4832  1.1  christos 				 * target type.  Remember it.
   4833  1.1  christos 				 */
   4834  1.1  christos 				foundsig = header;
   4835  1.1  christos 			} else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
   4836  1.1  christos 				   header->type == negtype) {
   4837  1.1  christos 				/*
   4838  1.1  christos 				 * We've found a negative cache entry.
   4839  1.1  christos 				 */
   4840  1.1  christos 				found = header;
   4841  1.1  christos 			} else if (header->type == dns_rdatatype_ns) {
   4842  1.1  christos 				/*
   4843  1.1  christos 				 * Remember a NS rdataset even if we're
   4844  1.1  christos 				 * not specifically looking for it, because
   4845  1.1  christos 				 * we might need it later.
   4846  1.1  christos 				 */
   4847  1.1  christos 				nsheader = header;
   4848  1.1  christos 			} else if (header->type == RBTDB_RDATATYPE_SIGNS) {
   4849  1.1  christos 				/*
   4850  1.1  christos 				 * If we need the NS rdataset, we'll also
   4851  1.1  christos 				 * need its signature.
   4852  1.1  christos 				 */
   4853  1.1  christos 				nssig = header;
   4854  1.1  christos 			} else if (header->type == dns_rdatatype_nsec) {
   4855  1.1  christos 				nsecheader = header;
   4856  1.1  christos 			} else if (header->type == RBTDB_RDATATYPE_SIGNSEC) {
   4857  1.1  christos 				nsecsig = header;
   4858  1.1  christos 			} else if (cname_ok &&
   4859  1.1  christos 				   header->type == RBTDB_RDATATYPE_SIGCNAME) {
   4860  1.1  christos 				/*
   4861  1.1  christos 				 * If we get a CNAME match, we'll also need
   4862  1.1  christos 				 * its signature.
   4863  1.1  christos 				 */
   4864  1.1  christos 				cnamesig = header;
   4865  1.1  christos 			}
   4866  1.1  christos 			header_prev = header;
   4867  1.1  christos 		} else
   4868  1.1  christos 			header_prev = header;
   4869  1.1  christos 	}
   4870  1.1  christos 
   4871  1.1  christos 	if (empty_node) {
   4872  1.1  christos 		/*
   4873  1.1  christos 		 * We have an exact match for the name, but there are no
   4874  1.1  christos 		 * extant rdatasets.  That means that this node doesn't
   4875  1.1  christos 		 * meaningfully exist, and that we really have a partial match.
   4876  1.1  christos 		 */
   4877  1.1  christos 		NODE_UNLOCK(lock, locktype);
   4878  1.1  christos 		goto find_ns;
   4879  1.1  christos 	}
   4880  1.1  christos 
   4881  1.1  christos 	/*
   4882  1.1  christos 	 * If we didn't find what we were looking for...
   4883  1.1  christos 	 */
   4884  1.1  christos 	if (found == NULL ||
   4885  1.1  christos 	    (DNS_TRUST_ADDITIONAL(found->trust) &&
   4886  1.1  christos 	     ((options & DNS_DBFIND_ADDITIONALOK) == 0)) ||
   4887  1.1  christos 	    (found->trust == dns_trust_glue &&
   4888  1.1  christos 	     ((options & DNS_DBFIND_GLUEOK) == 0)) ||
   4889  1.1  christos 	    (DNS_TRUST_PENDING(found->trust) &&
   4890  1.1  christos 	     ((options & DNS_DBFIND_PENDINGOK) == 0))) {
   4891  1.1  christos 
   4892  1.1  christos 		/*
   4893  1.1  christos 		 * Return covering NODATA NSEC record.
   4894  1.1  christos 		 */
   4895  1.1  christos 		if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0 &&
   4896  1.1  christos 		    nsecheader != NULL)
   4897  1.1  christos 		{
   4898  1.1  christos 			if (nodep != NULL) {
   4899  1.1  christos 				new_reference(search.rbtdb, node);
   4900  1.1  christos 				INSIST(!ISC_LINK_LINKED(node, deadlink));
   4901  1.1  christos 				*nodep = node;
   4902  1.1  christos 			}
   4903  1.1  christos 			bind_rdataset(search.rbtdb, node, nsecheader,
   4904  1.1  christos 				      search.now, rdataset);
   4905  1.1  christos 			if (need_headerupdate(nsecheader, search.now))
   4906  1.1  christos 				update = nsecheader;
   4907  1.1  christos 			if (nsecsig != NULL) {
   4908  1.1  christos 				bind_rdataset(search.rbtdb, node, nsecsig,
   4909  1.1  christos 					      search.now, sigrdataset);
   4910  1.1  christos 				if (need_headerupdate(nsecsig, search.now))
   4911  1.1  christos 					updatesig = nsecsig;
   4912  1.1  christos 			}
   4913  1.1  christos 			result = DNS_R_COVERINGNSEC;
   4914  1.1  christos 			goto node_exit;
   4915  1.1  christos 		}
   4916  1.1  christos 
   4917  1.1  christos 		/*
   4918  1.1  christos 		 * If there is an NS rdataset at this node, then this is the
   4919  1.1  christos 		 * deepest zone cut.
   4920  1.1  christos 		 */
   4921  1.1  christos 		if (nsheader != NULL) {
   4922  1.1  christos 			if (nodep != NULL) {
   4923  1.1  christos 				new_reference(search.rbtdb, node);
   4924  1.1  christos 				INSIST(!ISC_LINK_LINKED(node, deadlink));
   4925  1.1  christos 				*nodep = node;
   4926  1.1  christos 			}
   4927  1.1  christos 			bind_rdataset(search.rbtdb, node, nsheader, search.now,
   4928  1.1  christos 				      rdataset);
   4929  1.1  christos 			if (need_headerupdate(nsheader, search.now))
   4930  1.1  christos 				update = nsheader;
   4931  1.1  christos 			if (nssig != NULL) {
   4932  1.1  christos 				bind_rdataset(search.rbtdb, node, nssig,
   4933  1.1  christos 					      search.now, sigrdataset);
   4934  1.1  christos 				if (need_headerupdate(nssig, search.now))
   4935  1.1  christos 					updatesig = nssig;
   4936  1.1  christos 			}
   4937  1.1  christos 			result = DNS_R_DELEGATION;
   4938  1.1  christos 			goto node_exit;
   4939  1.1  christos 		}
   4940  1.1  christos 
   4941  1.1  christos 		/*
   4942  1.1  christos 		 * Go find the deepest zone cut.
   4943  1.1  christos 		 */
   4944  1.1  christos 		NODE_UNLOCK(lock, locktype);
   4945  1.1  christos 		goto find_ns;
   4946  1.1  christos 	}
   4947  1.1  christos 
   4948  1.1  christos 	/*
   4949  1.1  christos 	 * We found what we were looking for, or we found a CNAME.
   4950  1.1  christos 	 */
   4951  1.1  christos 
   4952  1.1  christos 	if (nodep != NULL) {
   4953  1.1  christos 		new_reference(search.rbtdb, node);
   4954  1.1  christos 		INSIST(!ISC_LINK_LINKED(node, deadlink));
   4955  1.1  christos 		*nodep = node;
   4956  1.1  christos 	}
   4957  1.1  christos 
   4958  1.1  christos 	if (NEGATIVE(found)) {
   4959  1.1  christos 		/*
   4960  1.1  christos 		 * We found a negative cache entry.
   4961  1.1  christos 		 */
   4962  1.1  christos 		if (NXDOMAIN(found))
   4963  1.1  christos 			result = DNS_R_NCACHENXDOMAIN;
   4964  1.1  christos 		else
   4965  1.1  christos 			result = DNS_R_NCACHENXRRSET;
   4966  1.1  christos 	} else if (type != found->type &&
   4967  1.1  christos 		   type != dns_rdatatype_any &&
   4968  1.1  christos 		   found->type == dns_rdatatype_cname) {
   4969  1.1  christos 		/*
   4970  1.1  christos 		 * We weren't doing an ANY query and we found a CNAME instead
   4971  1.1  christos 		 * of the type we were looking for, so we need to indicate
   4972  1.1  christos 		 * that result to the caller.
   4973  1.1  christos 		 */
   4974  1.1  christos 		result = DNS_R_CNAME;
   4975  1.1  christos 	} else {
   4976  1.1  christos 		/*
   4977  1.1  christos 		 * An ordinary successful query!
   4978  1.1  christos 		 */
   4979  1.1  christos 		result = ISC_R_SUCCESS;
   4980  1.1  christos 	}
   4981  1.1  christos 
   4982  1.1  christos 	if (type != dns_rdatatype_any || result == DNS_R_NCACHENXDOMAIN ||
   4983  1.1  christos 	    result == DNS_R_NCACHENXRRSET) {
   4984  1.1  christos 		bind_rdataset(search.rbtdb, node, found, search.now,
   4985  1.1  christos 			      rdataset);
   4986  1.1  christos 		if (need_headerupdate(found, search.now))
   4987  1.1  christos 			update = found;
   4988  1.1  christos 		if (!NEGATIVE(found) && foundsig != NULL) {
   4989  1.1  christos 			bind_rdataset(search.rbtdb, node, foundsig, search.now,
   4990  1.1  christos 				      sigrdataset);
   4991  1.1  christos 			if (need_headerupdate(foundsig, search.now))
   4992  1.1  christos 				updatesig = foundsig;
   4993  1.1  christos 		}
   4994  1.1  christos 	}
   4995  1.1  christos 
   4996  1.1  christos  node_exit:
   4997  1.1  christos 	if ((update != NULL || updatesig != NULL) &&
   4998  1.1  christos 	    locktype != isc_rwlocktype_write) {
   4999  1.1  christos 		NODE_UNLOCK(lock, locktype);
   5000  1.1  christos 		NODE_LOCK(lock, isc_rwlocktype_write);
   5001  1.1  christos 		locktype = isc_rwlocktype_write;
   5002  1.1  christos 		POST(locktype);
   5003  1.1  christos 	}
   5004  1.1  christos 	if (update != NULL && need_headerupdate(update, search.now))
   5005  1.1  christos 		update_header(search.rbtdb, update, search.now);
   5006  1.1  christos 	if (updatesig != NULL && need_headerupdate(updatesig, search.now))
   5007  1.1  christos 		update_header(search.rbtdb, updatesig, search.now);
   5008  1.1  christos 
   5009  1.1  christos 	NODE_UNLOCK(lock, locktype);
   5010  1.1  christos 
   5011  1.1  christos  tree_exit:
   5012  1.1  christos 	RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
   5013  1.1  christos 
   5014  1.1  christos 	/*
   5015  1.1  christos 	 * If we found a zonecut but aren't going to use it, we have to
   5016  1.1  christos 	 * let go of it.
   5017  1.1  christos 	 */
   5018  1.1  christos 	if (search.need_cleanup) {
   5019  1.1  christos 		node = search.zonecut;
   5020  1.1  christos 		INSIST(node != NULL);
   5021  1.1  christos 		lock = &(search.rbtdb->node_locks[node->locknum].lock);
   5022  1.1  christos 
   5023  1.1  christos 		NODE_LOCK(lock, isc_rwlocktype_read);
   5024  1.1  christos 		decrement_reference(search.rbtdb, node, 0,
   5025  1.1  christos 				    isc_rwlocktype_read, isc_rwlocktype_none,
   5026  1.3  christos 				    false);
   5027  1.1  christos 		NODE_UNLOCK(lock, isc_rwlocktype_read);
   5028  1.1  christos 	}
   5029  1.1  christos 
   5030  1.1  christos 	dns_rbtnodechain_reset(&search.chain);
   5031  1.1  christos 
   5032  1.1  christos 	update_cachestats(search.rbtdb, result);
   5033  1.1  christos 	return (result);
   5034  1.1  christos }
   5035  1.1  christos 
   5036  1.1  christos static isc_result_t
   5037  1.1  christos cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
   5038  1.1  christos 		  isc_stdtime_t now, dns_dbnode_t **nodep,
   5039  1.3  christos 		  dns_name_t *foundname, dns_name_t *dcname,
   5040  1.1  christos 		  dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
   5041  1.1  christos {
   5042  1.1  christos 	dns_rbtnode_t *node = NULL;
   5043  1.1  christos 	nodelock_t *lock;
   5044  1.1  christos 	isc_result_t result;
   5045  1.1  christos 	rbtdb_search_t search;
   5046  1.1  christos 	rdatasetheader_t *header, *header_prev, *header_next;
   5047  1.1  christos 	rdatasetheader_t *found, *foundsig;
   5048  1.1  christos 	unsigned int rbtoptions = DNS_RBTFIND_EMPTYDATA;
   5049  1.1  christos 	isc_rwlocktype_t locktype;
   5050  1.3  christos 	bool dcnull = (dcname == NULL);
   5051  1.1  christos 
   5052  1.1  christos 	search.rbtdb = (dns_rbtdb_t *)db;
   5053  1.1  christos 
   5054  1.1  christos 	REQUIRE(VALID_RBTDB(search.rbtdb));
   5055  1.1  christos 
   5056  1.1  christos 	if (now == 0)
   5057  1.1  christos 		isc_stdtime_get(&now);
   5058  1.1  christos 
   5059  1.1  christos 	search.rbtversion = NULL;
   5060  1.1  christos 	search.serial = 1;
   5061  1.1  christos 	search.options = options;
   5062  1.3  christos 	search.copy_name = false;
   5063  1.3  christos 	search.need_cleanup = false;
   5064  1.3  christos 	search.wild = false;
   5065  1.1  christos 	search.zonecut = NULL;
   5066  1.1  christos 	dns_fixedname_init(&search.zonecut_name);
   5067  1.1  christos 	dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
   5068  1.1  christos 	search.now = now;
   5069  1.1  christos 
   5070  1.3  christos 	if (dcnull) {
   5071  1.3  christos 		dcname = foundname;
   5072  1.3  christos 	}
   5073  1.3  christos 
   5074  1.1  christos 	if ((options & DNS_DBFIND_NOEXACT) != 0)
   5075  1.1  christos 		rbtoptions |= DNS_RBTFIND_NOEXACT;
   5076  1.1  christos 
   5077  1.1  christos 	RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
   5078  1.1  christos 
   5079  1.1  christos 	/*
   5080  1.1  christos 	 * Search down from the root of the tree.
   5081  1.1  christos 	 */
   5082  1.3  christos 	result = dns_rbt_findnode(search.rbtdb->tree, name, dcname, &node,
   5083  1.1  christos 				  &search.chain, rbtoptions, NULL, &search);
   5084  1.1  christos 
   5085  1.1  christos 	if (result == DNS_R_PARTIALMATCH) {
   5086  1.1  christos 		result = find_deepest_zonecut(&search, node, nodep, foundname,
   5087  1.1  christos 					      rdataset, sigrdataset);
   5088  1.1  christos 		goto tree_exit;
   5089  1.3  christos 	} else if (result != ISC_R_SUCCESS) {
   5090  1.1  christos 		goto tree_exit;
   5091  1.3  christos 	} else if (!dcnull) {
   5092  1.3  christos 		dns_name_copy(dcname, foundname, NULL);
   5093  1.3  christos 	}
   5094  1.1  christos 	/*
   5095  1.1  christos 	 * We now go looking for an NS rdataset at the node.
   5096  1.1  christos 	 */
   5097  1.1  christos 
   5098  1.1  christos 	lock = &(search.rbtdb->node_locks[node->locknum].lock);
   5099  1.1  christos 	locktype = isc_rwlocktype_read;
   5100  1.1  christos 	NODE_LOCK(lock, locktype);
   5101  1.1  christos 
   5102  1.1  christos 	found = NULL;
   5103  1.1  christos 	foundsig = NULL;
   5104  1.1  christos 	header_prev = NULL;
   5105  1.1  christos 	for (header = node->data; header != NULL; header = header_next) {
   5106  1.1  christos 		header_next = header->next;
   5107  1.1  christos 		if (check_stale_header(node, header,
   5108  1.1  christos 				       &locktype, lock, &search,
   5109  1.1  christos 				       &header_prev)) {
   5110  1.1  christos 			/* Do nothing. */
   5111  1.1  christos 		} else if (EXISTS(header)) {
   5112  1.1  christos 			/*
   5113  1.1  christos 			 * If we found a type we were looking for, remember
   5114  1.1  christos 			 * it.
   5115  1.1  christos 			 */
   5116  1.1  christos 			if (header->type == dns_rdatatype_ns) {
   5117  1.1  christos 				/*
   5118  1.1  christos 				 * Remember a NS rdataset even if we're
   5119  1.1  christos 				 * not specifically looking for it, because
   5120  1.1  christos 				 * we might need it later.
   5121  1.1  christos 				 */
   5122  1.1  christos 				found = header;
   5123  1.1  christos 			} else if (header->type == RBTDB_RDATATYPE_SIGNS) {
   5124  1.1  christos 				/*
   5125  1.1  christos 				 * If we need the NS rdataset, we'll also
   5126  1.1  christos 				 * need its signature.
   5127  1.1  christos 				 */
   5128  1.1  christos 				foundsig = header;
   5129  1.1  christos 			}
   5130  1.1  christos 			header_prev = header;
   5131  1.1  christos 		} else
   5132  1.1  christos 			header_prev = header;
   5133  1.1  christos 	}
   5134  1.1  christos 
   5135  1.1  christos 	if (found == NULL) {
   5136  1.1  christos 		/*
   5137  1.1  christos 		 * No NS records here.
   5138  1.1  christos 		 */
   5139  1.1  christos 		NODE_UNLOCK(lock, locktype);
   5140  1.3  christos 		result = find_deepest_zonecut(&search, node, nodep, foundname,
   5141  1.3  christos 					      rdataset, sigrdataset);
   5142  1.3  christos 		goto tree_exit;
   5143  1.1  christos 	}
   5144  1.1  christos 
   5145  1.1  christos 	if (nodep != NULL) {
   5146  1.1  christos 		new_reference(search.rbtdb, node);
   5147  1.1  christos 		INSIST(!ISC_LINK_LINKED(node, deadlink));
   5148  1.1  christos 		*nodep = node;
   5149  1.1  christos 	}
   5150  1.1  christos 
   5151  1.1  christos 	bind_rdataset(search.rbtdb, node, found, search.now, rdataset);
   5152  1.1  christos 	if (foundsig != NULL)
   5153  1.1  christos 		bind_rdataset(search.rbtdb, node, foundsig, search.now,
   5154  1.1  christos 			      sigrdataset);
   5155  1.1  christos 
   5156  1.1  christos 	if (need_headerupdate(found, search.now) ||
   5157  1.1  christos 	    (foundsig != NULL &&  need_headerupdate(foundsig, search.now))) {
   5158  1.1  christos 		if (locktype != isc_rwlocktype_write) {
   5159  1.1  christos 			NODE_UNLOCK(lock, locktype);
   5160  1.1  christos 			NODE_LOCK(lock, isc_rwlocktype_write);
   5161  1.1  christos 			locktype = isc_rwlocktype_write;
   5162  1.1  christos 			POST(locktype);
   5163  1.1  christos 		}
   5164  1.1  christos 		if (need_headerupdate(found, search.now))
   5165  1.1  christos 			update_header(search.rbtdb, found, search.now);
   5166  1.1  christos 		if (foundsig != NULL &&
   5167  1.1  christos 		    need_headerupdate(foundsig, search.now)) {
   5168  1.1  christos 			update_header(search.rbtdb, foundsig, search.now);
   5169  1.1  christos 		}
   5170  1.1  christos 	}
   5171  1.1  christos 
   5172  1.1  christos 	NODE_UNLOCK(lock, locktype);
   5173  1.1  christos 
   5174  1.1  christos  tree_exit:
   5175  1.1  christos 	RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
   5176  1.1  christos 
   5177  1.1  christos 	INSIST(!search.need_cleanup);
   5178  1.1  christos 
   5179  1.1  christos 	dns_rbtnodechain_reset(&search.chain);
   5180  1.1  christos 
   5181  1.1  christos 	if (result == DNS_R_DELEGATION)
   5182  1.1  christos 		result = ISC_R_SUCCESS;
   5183  1.1  christos 
   5184  1.1  christos 	return (result);
   5185  1.1  christos }
   5186  1.1  christos 
   5187  1.1  christos static void
   5188  1.1  christos attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
   5189  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   5190  1.1  christos 	dns_rbtnode_t *node = (dns_rbtnode_t *)source;
   5191  1.1  christos 
   5192  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   5193  1.1  christos 	REQUIRE(targetp != NULL && *targetp == NULL);
   5194  1.1  christos 
   5195  1.3  christos 	isc_refcount_increment(&node->references);
   5196  1.1  christos 
   5197  1.1  christos 	*targetp = source;
   5198  1.1  christos }
   5199  1.1  christos 
   5200  1.1  christos static void
   5201  1.1  christos detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
   5202  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   5203  1.1  christos 	dns_rbtnode_t *node;
   5204  1.3  christos 	bool want_free = false;
   5205  1.3  christos 	bool inactive = false;
   5206  1.1  christos 	rbtdb_nodelock_t *nodelock;
   5207  1.1  christos 
   5208  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   5209  1.1  christos 	REQUIRE(targetp != NULL && *targetp != NULL);
   5210  1.1  christos 
   5211  1.1  christos 	node = (dns_rbtnode_t *)(*targetp);
   5212  1.1  christos 	nodelock = &rbtdb->node_locks[node->locknum];
   5213  1.1  christos 
   5214  1.1  christos 	NODE_LOCK(&nodelock->lock, isc_rwlocktype_read);
   5215  1.1  christos 
   5216  1.1  christos 	if (decrement_reference(rbtdb, node, 0, isc_rwlocktype_read,
   5217  1.3  christos 				isc_rwlocktype_none, false)) {
   5218  1.1  christos 		if (isc_refcount_current(&nodelock->references) == 0 &&
   5219  1.1  christos 		    nodelock->exiting) {
   5220  1.3  christos 			inactive = true;
   5221  1.1  christos 		}
   5222  1.1  christos 	}
   5223  1.1  christos 
   5224  1.1  christos 	NODE_UNLOCK(&nodelock->lock, isc_rwlocktype_read);
   5225  1.1  christos 
   5226  1.1  christos 	*targetp = NULL;
   5227  1.1  christos 
   5228  1.1  christos 	if (inactive) {
   5229  1.1  christos 		RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
   5230  1.1  christos 		rbtdb->active--;
   5231  1.1  christos 		if (rbtdb->active == 0)
   5232  1.3  christos 			want_free = true;
   5233  1.1  christos 		RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
   5234  1.1  christos 		if (want_free) {
   5235  1.1  christos 			char buf[DNS_NAME_FORMATSIZE];
   5236  1.1  christos 			if (dns_name_dynamic(&rbtdb->common.origin))
   5237  1.1  christos 				dns_name_format(&rbtdb->common.origin, buf,
   5238  1.1  christos 						sizeof(buf));
   5239  1.1  christos 			else
   5240  1.1  christos 				strlcpy(buf, "<UNKNOWN>", sizeof(buf));
   5241  1.1  christos 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
   5242  1.1  christos 				      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
   5243  1.1  christos 				      "calling free_rbtdb(%s)", buf);
   5244  1.3  christos 			free_rbtdb(rbtdb, true, NULL);
   5245  1.1  christos 		}
   5246  1.1  christos 	}
   5247  1.1  christos }
   5248  1.1  christos 
   5249  1.1  christos static isc_result_t
   5250  1.1  christos expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
   5251  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   5252  1.1  christos 	dns_rbtnode_t *rbtnode = node;
   5253  1.1  christos 	rdatasetheader_t *header;
   5254  1.3  christos 	bool force_expire = false;
   5255  1.1  christos 	/*
   5256  1.1  christos 	 * These are the category and module used by the cache cleaner.
   5257  1.1  christos 	 */
   5258  1.3  christos 	bool log = false;
   5259  1.1  christos 	isc_logcategory_t *category = DNS_LOGCATEGORY_DATABASE;
   5260  1.1  christos 	isc_logmodule_t *module = DNS_LOGMODULE_CACHE;
   5261  1.1  christos 	int level = ISC_LOG_DEBUG(2);
   5262  1.1  christos 	char printname[DNS_NAME_FORMATSIZE];
   5263  1.1  christos 
   5264  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   5265  1.1  christos 
   5266  1.1  christos 	/*
   5267  1.1  christos 	 * Caller must hold a tree lock.
   5268  1.1  christos 	 */
   5269  1.1  christos 
   5270  1.1  christos 	if (now == 0)
   5271  1.1  christos 		isc_stdtime_get(&now);
   5272  1.1  christos 
   5273  1.1  christos 	if (isc_mem_isovermem(rbtdb->common.mctx)) {
   5274  1.1  christos 		/*
   5275  1.3  christos 		 * Force expire with 25% probability.
   5276  1.1  christos 		 * XXXDCL Could stand to have a better policy, like LRU.
   5277  1.1  christos 		 */
   5278  1.3  christos 		force_expire = (rbtnode->down == NULL &&
   5279  1.3  christos 				(isc_random32() % 4) == 0);
   5280  1.1  christos 
   5281  1.1  christos 		/*
   5282  1.1  christos 		 * Note that 'log' can be true IFF overmem is also true.
   5283  1.1  christos 		 * overmem can currently only be true for cache
   5284  1.1  christos 		 * databases -- hence all of the "overmem cache" log strings.
   5285  1.1  christos 		 */
   5286  1.3  christos 		log = isc_log_wouldlog(dns_lctx, level);
   5287  1.1  christos 		if (log)
   5288  1.1  christos 			isc_log_write(dns_lctx, category, module, level,
   5289  1.1  christos 				      "overmem cache: %s %s",
   5290  1.1  christos 				      force_expire ? "FORCE" : "check",
   5291  1.1  christos 				      dns_rbt_formatnodename(rbtnode,
   5292  1.1  christos 							   printname,
   5293  1.1  christos 							   sizeof(printname)));
   5294  1.1  christos 	}
   5295  1.1  christos 
   5296  1.1  christos 	/*
   5297  1.1  christos 	 * We may not need write access, but this code path is not performance
   5298  1.1  christos 	 * sensitive, so it should be okay to always lock as a writer.
   5299  1.1  christos 	 */
   5300  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   5301  1.1  christos 		  isc_rwlocktype_write);
   5302  1.1  christos 
   5303  1.1  christos 	for (header = rbtnode->data; header != NULL; header = header->next)
   5304  1.1  christos 		if (header->rdh_ttl <= now - RBTDB_VIRTUAL) {
   5305  1.1  christos 			/*
   5306  1.1  christos 			 * We don't check if refcurrent(rbtnode) == 0 and try
   5307  1.1  christos 			 * to free like we do in cache_find(), because
   5308  1.1  christos 			 * refcurrent(rbtnode) must be non-zero.  This is so
   5309  1.1  christos 			 * because 'node' is an argument to the function.
   5310  1.1  christos 			 */
   5311  1.1  christos 			mark_header_ancient(rbtdb, header);
   5312  1.1  christos 			if (log)
   5313  1.1  christos 				isc_log_write(dns_lctx, category, module,
   5314  1.1  christos 					      level, "overmem cache: stale %s",
   5315  1.1  christos 					      printname);
   5316  1.1  christos 		} else if (force_expire) {
   5317  1.1  christos 			if (! RETAIN(header)) {
   5318  1.1  christos 				set_ttl(rbtdb, header, 0);
   5319  1.1  christos 				mark_header_ancient(rbtdb, header);
   5320  1.1  christos 			} else if (log) {
   5321  1.1  christos 				isc_log_write(dns_lctx, category, module,
   5322  1.1  christos 					      level, "overmem cache: "
   5323  1.1  christos 					      "reprieve by RETAIN() %s",
   5324  1.1  christos 					      printname);
   5325  1.1  christos 			}
   5326  1.1  christos 		} else if (isc_mem_isovermem(rbtdb->common.mctx) && log)
   5327  1.1  christos 			isc_log_write(dns_lctx, category, module, level,
   5328  1.1  christos 				      "overmem cache: saved %s", printname);
   5329  1.1  christos 
   5330  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   5331  1.1  christos 		    isc_rwlocktype_write);
   5332  1.1  christos 
   5333  1.1  christos 	return (ISC_R_SUCCESS);
   5334  1.1  christos }
   5335  1.1  christos 
   5336  1.1  christos static void
   5337  1.3  christos overmem(dns_db_t *db, bool over) {
   5338  1.1  christos 	/* This is an empty callback.  See adb.c:water() */
   5339  1.1  christos 
   5340  1.1  christos 	UNUSED(db);
   5341  1.1  christos 	UNUSED(over);
   5342  1.1  christos 
   5343  1.1  christos 	return;
   5344  1.1  christos }
   5345  1.1  christos 
   5346  1.1  christos static void
   5347  1.1  christos printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
   5348  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   5349  1.1  christos 	dns_rbtnode_t *rbtnode = node;
   5350  1.3  christos 	bool first;
   5351  1.3  christos 	uint32_t refs;
   5352  1.1  christos 
   5353  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   5354  1.1  christos 
   5355  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   5356  1.1  christos 		  isc_rwlocktype_read);
   5357  1.1  christos 
   5358  1.3  christos 	refs = isc_refcount_current(&rbtnode->references);
   5359  1.3  christos 	fprintf(out, "node %p, %" PRIu32 " references, locknum = %u\n",
   5360  1.3  christos 		rbtnode, refs,
   5361  1.1  christos 		rbtnode->locknum);
   5362  1.1  christos 	if (rbtnode->data != NULL) {
   5363  1.1  christos 		rdatasetheader_t *current, *top_next;
   5364  1.1  christos 
   5365  1.1  christos 		for (current = rbtnode->data; current != NULL;
   5366  1.1  christos 		     current = top_next) {
   5367  1.1  christos 			top_next = current->next;
   5368  1.3  christos 			first = true;
   5369  1.1  christos 			fprintf(out, "\ttype %u", current->type);
   5370  1.1  christos 			do {
   5371  1.1  christos 				if (!first)
   5372  1.1  christos 					fprintf(out, "\t");
   5373  1.3  christos 				first = false;
   5374  1.1  christos 				fprintf(out,
   5375  1.1  christos 					"\tserial = %lu, ttl = %u, "
   5376  1.1  christos 					"trust = %u, attributes = %u, "
   5377  1.1  christos 					"resign = %u\n",
   5378  1.1  christos 					(unsigned long)current->serial,
   5379  1.1  christos 					current->rdh_ttl,
   5380  1.1  christos 					current->trust,
   5381  1.1  christos 					current->attributes,
   5382  1.1  christos 					(current->resign << 1) |
   5383  1.1  christos 					current->resign_lsb);
   5384  1.1  christos 				current = current->down;
   5385  1.1  christos 			} while (current != NULL);
   5386  1.1  christos 		}
   5387  1.1  christos 	} else
   5388  1.1  christos 		fprintf(out, "(empty)\n");
   5389  1.1  christos 
   5390  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   5391  1.1  christos 		    isc_rwlocktype_read);
   5392  1.1  christos }
   5393  1.1  christos 
   5394  1.1  christos static isc_result_t
   5395  1.1  christos createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
   5396  1.1  christos {
   5397  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   5398  1.1  christos 	rbtdb_dbiterator_t *rbtdbiter;
   5399  1.1  christos 
   5400  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   5401  1.1  christos 
   5402  1.1  christos 	rbtdbiter = isc_mem_get(rbtdb->common.mctx, sizeof(*rbtdbiter));
   5403  1.1  christos 	if (rbtdbiter == NULL)
   5404  1.1  christos 		return (ISC_R_NOMEMORY);
   5405  1.1  christos 
   5406  1.1  christos 	rbtdbiter->common.methods = &dbiterator_methods;
   5407  1.1  christos 	rbtdbiter->common.db = NULL;
   5408  1.1  christos 	dns_db_attach(db, &rbtdbiter->common.db);
   5409  1.1  christos 	rbtdbiter->common.relative_names =
   5410  1.3  christos 		((options & DNS_DB_RELATIVENAMES) != 0);
   5411  1.1  christos 	rbtdbiter->common.magic = DNS_DBITERATOR_MAGIC;
   5412  1.3  christos 	rbtdbiter->common.cleaning = false;
   5413  1.3  christos 	rbtdbiter->paused = true;
   5414  1.1  christos 	rbtdbiter->tree_locked = isc_rwlocktype_none;
   5415  1.1  christos 	rbtdbiter->result = ISC_R_SUCCESS;
   5416  1.1  christos 	dns_fixedname_init(&rbtdbiter->name);
   5417  1.1  christos 	dns_fixedname_init(&rbtdbiter->origin);
   5418  1.1  christos 	rbtdbiter->node = NULL;
   5419  1.1  christos 	rbtdbiter->delcnt = 0;
   5420  1.3  christos 	rbtdbiter->nsec3only = ((options & DNS_DB_NSEC3ONLY) != 0);
   5421  1.3  christos 	rbtdbiter->nonsec3 = ((options & DNS_DB_NONSEC3) != 0);
   5422  1.1  christos 	memset(rbtdbiter->deletions, 0, sizeof(rbtdbiter->deletions));
   5423  1.1  christos 	dns_rbtnodechain_init(&rbtdbiter->chain, db->mctx);
   5424  1.1  christos 	dns_rbtnodechain_init(&rbtdbiter->nsec3chain, db->mctx);
   5425  1.1  christos 	if (rbtdbiter->nsec3only)
   5426  1.1  christos 		rbtdbiter->current = &rbtdbiter->nsec3chain;
   5427  1.1  christos 	else
   5428  1.1  christos 		rbtdbiter->current = &rbtdbiter->chain;
   5429  1.1  christos 
   5430  1.1  christos 	*iteratorp = (dns_dbiterator_t *)rbtdbiter;
   5431  1.1  christos 
   5432  1.1  christos 	return (ISC_R_SUCCESS);
   5433  1.1  christos }
   5434  1.1  christos 
   5435  1.1  christos static isc_result_t
   5436  1.1  christos zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
   5437  1.1  christos 		  dns_rdatatype_t type, dns_rdatatype_t covers,
   5438  1.1  christos 		  isc_stdtime_t now, dns_rdataset_t *rdataset,
   5439  1.1  christos 		  dns_rdataset_t *sigrdataset)
   5440  1.1  christos {
   5441  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   5442  1.1  christos 	dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
   5443  1.1  christos 	rdatasetheader_t *header, *header_next, *found, *foundsig;
   5444  1.1  christos 	rbtdb_serial_t serial;
   5445  1.1  christos 	rbtdb_version_t *rbtversion = version;
   5446  1.3  christos 	bool close_version = false;
   5447  1.1  christos 	rbtdb_rdatatype_t matchtype, sigmatchtype;
   5448  1.1  christos 
   5449  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   5450  1.1  christos 	REQUIRE(type != dns_rdatatype_any);
   5451  1.1  christos 	INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
   5452  1.1  christos 
   5453  1.1  christos 	if (rbtversion == NULL) {
   5454  1.1  christos 		currentversion(db, (dns_dbversion_t **) (void *)(&rbtversion));
   5455  1.3  christos 		close_version = true;
   5456  1.1  christos 	}
   5457  1.1  christos 	serial = rbtversion->serial;
   5458  1.1  christos 	now = 0;
   5459  1.1  christos 
   5460  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   5461  1.1  christos 		  isc_rwlocktype_read);
   5462  1.1  christos 
   5463  1.1  christos 	found = NULL;
   5464  1.1  christos 	foundsig = NULL;
   5465  1.1  christos 	matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
   5466  1.1  christos 	if (covers == 0)
   5467  1.1  christos 		sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
   5468  1.1  christos 	else
   5469  1.1  christos 		sigmatchtype = 0;
   5470  1.1  christos 
   5471  1.1  christos 	for (header = rbtnode->data; header != NULL; header = header_next) {
   5472  1.1  christos 		header_next = header->next;
   5473  1.1  christos 		do {
   5474  1.1  christos 			if (header->serial <= serial &&
   5475  1.1  christos 			    !IGNORE(header)) {
   5476  1.1  christos 				/*
   5477  1.1  christos 				 * Is this a "this rdataset doesn't
   5478  1.1  christos 				 * exist" record?
   5479  1.1  christos 				 */
   5480  1.1  christos 				if (NONEXISTENT(header))
   5481  1.1  christos 					header = NULL;
   5482  1.1  christos 				break;
   5483  1.1  christos 			} else
   5484  1.1  christos 				header = header->down;
   5485  1.1  christos 		} while (header != NULL);
   5486  1.1  christos 		if (header != NULL) {
   5487  1.1  christos 			/*
   5488  1.1  christos 			 * We have an active, extant rdataset.  If it's a
   5489  1.1  christos 			 * type we're looking for, remember it.
   5490  1.1  christos 			 */
   5491  1.1  christos 			if (header->type == matchtype) {
   5492  1.1  christos 				found = header;
   5493  1.1  christos 				if (foundsig != NULL)
   5494  1.1  christos 					break;
   5495  1.1  christos 			} else if (header->type == sigmatchtype) {
   5496  1.1  christos 				foundsig = header;
   5497  1.1  christos 				if (found != NULL)
   5498  1.1  christos 					break;
   5499  1.1  christos 			}
   5500  1.1  christos 		}
   5501  1.1  christos 	}
   5502  1.1  christos 	if (found != NULL) {
   5503  1.1  christos 		bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
   5504  1.1  christos 		if (foundsig != NULL)
   5505  1.1  christos 			bind_rdataset(rbtdb, rbtnode, foundsig, now,
   5506  1.1  christos 				      sigrdataset);
   5507  1.1  christos 	}
   5508  1.1  christos 
   5509  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   5510  1.1  christos 		    isc_rwlocktype_read);
   5511  1.1  christos 
   5512  1.1  christos 	if (close_version)
   5513  1.1  christos 		closeversion(db, (dns_dbversion_t **) (void *)(&rbtversion),
   5514  1.3  christos 			     false);
   5515  1.1  christos 
   5516  1.1  christos 	if (found == NULL)
   5517  1.1  christos 		return (ISC_R_NOTFOUND);
   5518  1.1  christos 
   5519  1.1  christos 	return (ISC_R_SUCCESS);
   5520  1.1  christos }
   5521  1.1  christos 
   5522  1.1  christos static isc_result_t
   5523  1.1  christos cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
   5524  1.1  christos 		   dns_rdatatype_t type, dns_rdatatype_t covers,
   5525  1.1  christos 		   isc_stdtime_t now, dns_rdataset_t *rdataset,
   5526  1.1  christos 		   dns_rdataset_t *sigrdataset)
   5527  1.1  christos {
   5528  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   5529  1.1  christos 	dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
   5530  1.1  christos 	rdatasetheader_t *header, *header_next, *found, *foundsig;
   5531  1.1  christos 	rbtdb_rdatatype_t matchtype, sigmatchtype, negtype;
   5532  1.1  christos 	isc_result_t result;
   5533  1.1  christos 	nodelock_t *lock;
   5534  1.1  christos 	isc_rwlocktype_t locktype;
   5535  1.1  christos 
   5536  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   5537  1.1  christos 	REQUIRE(type != dns_rdatatype_any);
   5538  1.1  christos 
   5539  1.1  christos 	UNUSED(version);
   5540  1.1  christos 
   5541  1.1  christos 	result = ISC_R_SUCCESS;
   5542  1.1  christos 
   5543  1.1  christos 	if (now == 0)
   5544  1.1  christos 		isc_stdtime_get(&now);
   5545  1.1  christos 
   5546  1.1  christos 	lock = &rbtdb->node_locks[rbtnode->locknum].lock;
   5547  1.1  christos 	locktype = isc_rwlocktype_read;
   5548  1.1  christos 	NODE_LOCK(lock, locktype);
   5549  1.1  christos 
   5550  1.1  christos 	found = NULL;
   5551  1.1  christos 	foundsig = NULL;
   5552  1.1  christos 	matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
   5553  1.1  christos 	negtype = RBTDB_RDATATYPE_VALUE(0, type);
   5554  1.1  christos 	if (covers == 0)
   5555  1.1  christos 		sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
   5556  1.1  christos 	else
   5557  1.1  christos 		sigmatchtype = 0;
   5558  1.1  christos 
   5559  1.1  christos 	for (header = rbtnode->data; header != NULL; header = header_next) {
   5560  1.1  christos 		header_next = header->next;
   5561  1.1  christos 		if (!ACTIVE(header, now)) {
   5562  1.1  christos 			if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
   5563  1.1  christos 			    (locktype == isc_rwlocktype_write ||
   5564  1.1  christos 			     NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
   5565  1.1  christos 				/*
   5566  1.1  christos 				 * We update the node's status only when we
   5567  1.1  christos 				 * can get write access.
   5568  1.1  christos 				 */
   5569  1.1  christos 				locktype = isc_rwlocktype_write;
   5570  1.1  christos 
   5571  1.1  christos 				/*
   5572  1.1  christos 				 * We don't check if refcurrent(rbtnode) == 0
   5573  1.1  christos 				 * and try to free like we do in cache_find(),
   5574  1.1  christos 				 * because refcurrent(rbtnode) must be
   5575  1.1  christos 				 * non-zero.  This is so because 'node' is an
   5576  1.1  christos 				 * argument to the function.
   5577  1.1  christos 				 */
   5578  1.1  christos 				mark_header_ancient(rbtdb, header);
   5579  1.1  christos 			}
   5580  1.1  christos 		} else if (EXISTS(header) && !ANCIENT(header)) {
   5581  1.1  christos 			if (header->type == matchtype)
   5582  1.1  christos 				found = header;
   5583  1.1  christos 			else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
   5584  1.1  christos 				 header->type == negtype)
   5585  1.1  christos 				found = header;
   5586  1.1  christos 			else if (header->type == sigmatchtype)
   5587  1.1  christos 				foundsig = header;
   5588  1.1  christos 		}
   5589  1.1  christos 	}
   5590  1.1  christos 	if (found != NULL) {
   5591  1.1  christos 		bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
   5592  1.1  christos 		if (!NEGATIVE(found) && foundsig != NULL)
   5593  1.1  christos 			bind_rdataset(rbtdb, rbtnode, foundsig, now,
   5594  1.1  christos 				      sigrdataset);
   5595  1.1  christos 	}
   5596  1.1  christos 
   5597  1.1  christos 	NODE_UNLOCK(lock, locktype);
   5598  1.1  christos 
   5599  1.1  christos 	if (found == NULL)
   5600  1.1  christos 		return (ISC_R_NOTFOUND);
   5601  1.1  christos 
   5602  1.1  christos 	if (NEGATIVE(found)) {
   5603  1.1  christos 		/*
   5604  1.1  christos 		 * We found a negative cache entry.
   5605  1.1  christos 		 */
   5606  1.1  christos 		if (NXDOMAIN(found))
   5607  1.1  christos 			result = DNS_R_NCACHENXDOMAIN;
   5608  1.1  christos 		else
   5609  1.1  christos 			result = DNS_R_NCACHENXRRSET;
   5610  1.1  christos 	}
   5611  1.1  christos 
   5612  1.1  christos 	update_cachestats(rbtdb, result);
   5613  1.1  christos 
   5614  1.1  christos 	return (result);
   5615  1.1  christos }
   5616  1.1  christos 
   5617  1.1  christos static isc_result_t
   5618  1.1  christos allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
   5619  1.1  christos 	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
   5620  1.1  christos {
   5621  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   5622  1.1  christos 	dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
   5623  1.1  christos 	rbtdb_version_t *rbtversion = version;
   5624  1.1  christos 	rbtdb_rdatasetiter_t *iterator;
   5625  1.1  christos 
   5626  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   5627  1.1  christos 
   5628  1.1  christos 	iterator = isc_mem_get(rbtdb->common.mctx, sizeof(*iterator));
   5629  1.1  christos 	if (iterator == NULL)
   5630  1.1  christos 		return (ISC_R_NOMEMORY);
   5631  1.1  christos 
   5632  1.1  christos 	if ((db->attributes & DNS_DBATTR_CACHE) == 0) {
   5633  1.1  christos 		now = 0;
   5634  1.1  christos 		if (rbtversion == NULL)
   5635  1.1  christos 			currentversion(db,
   5636  1.1  christos 				 (dns_dbversion_t **) (void *)(&rbtversion));
   5637  1.1  christos 		else {
   5638  1.1  christos 			INSIST(rbtversion->rbtdb == rbtdb);
   5639  1.1  christos 
   5640  1.3  christos 			(void)isc_refcount_increment(&rbtversion->references);
   5641  1.1  christos 		}
   5642  1.1  christos 	} else {
   5643  1.1  christos 		if (now == 0)
   5644  1.1  christos 			isc_stdtime_get(&now);
   5645  1.1  christos 		rbtversion = NULL;
   5646  1.1  christos 	}
   5647  1.1  christos 
   5648  1.1  christos 	iterator->common.magic = DNS_RDATASETITER_MAGIC;
   5649  1.1  christos 	iterator->common.methods = &rdatasetiter_methods;
   5650  1.1  christos 	iterator->common.db = db;
   5651  1.1  christos 	iterator->common.node = node;
   5652  1.1  christos 	iterator->common.version = (dns_dbversion_t *)rbtversion;
   5653  1.1  christos 	iterator->common.now = now;
   5654  1.1  christos 
   5655  1.3  christos 	isc_refcount_increment(&rbtnode->references);
   5656  1.1  christos 
   5657  1.1  christos 	iterator->current = NULL;
   5658  1.1  christos 
   5659  1.1  christos 	*iteratorp = (dns_rdatasetiter_t *)iterator;
   5660  1.1  christos 
   5661  1.1  christos 	return (ISC_R_SUCCESS);
   5662  1.1  christos }
   5663  1.1  christos 
   5664  1.3  christos static bool
   5665  1.1  christos cname_and_other_data(dns_rbtnode_t *node, rbtdb_serial_t serial) {
   5666  1.1  christos 	rdatasetheader_t *header, *header_next;
   5667  1.3  christos 	bool cname, other_data;
   5668  1.1  christos 	dns_rdatatype_t rdtype;
   5669  1.1  christos 
   5670  1.1  christos 	/*
   5671  1.1  christos 	 * The caller must hold the node lock.
   5672  1.1  christos 	 */
   5673  1.1  christos 
   5674  1.1  christos 	/*
   5675  1.1  christos 	 * Look for CNAME and "other data" rdatasets active in our version.
   5676  1.1  christos 	 */
   5677  1.3  christos 	cname = false;
   5678  1.3  christos 	other_data = false;
   5679  1.1  christos 	for (header = node->data; header != NULL; header = header_next) {
   5680  1.1  christos 		header_next = header->next;
   5681  1.1  christos 		if (header->type == dns_rdatatype_cname) {
   5682  1.1  christos 			/*
   5683  1.1  christos 			 * Look for an active extant CNAME.
   5684  1.1  christos 			 */
   5685  1.1  christos 			do {
   5686  1.1  christos 				if (header->serial <= serial &&
   5687  1.1  christos 				    !IGNORE(header)) {
   5688  1.1  christos 					/*
   5689  1.1  christos 					 * Is this a "this rdataset doesn't
   5690  1.1  christos 					 * exist" record?
   5691  1.1  christos 					 */
   5692  1.1  christos 					if (NONEXISTENT(header))
   5693  1.1  christos 						header = NULL;
   5694  1.1  christos 					break;
   5695  1.1  christos 				} else
   5696  1.1  christos 					header = header->down;
   5697  1.1  christos 			} while (header != NULL);
   5698  1.1  christos 			if (header != NULL)
   5699  1.3  christos 				cname = true;
   5700  1.1  christos 		} else {
   5701  1.1  christos 			/*
   5702  1.1  christos 			 * Look for active extant "other data".
   5703  1.1  christos 			 *
   5704  1.1  christos 			 * "Other data" is any rdataset whose type is not
   5705  1.1  christos 			 * KEY, NSEC, SIG or RRSIG.
   5706  1.1  christos 			 */
   5707  1.1  christos 			rdtype = RBTDB_RDATATYPE_BASE(header->type);
   5708  1.1  christos 			if (rdtype != dns_rdatatype_key &&
   5709  1.1  christos 			    rdtype != dns_rdatatype_sig &&
   5710  1.1  christos 			    rdtype != dns_rdatatype_nsec &&
   5711  1.1  christos 			    rdtype != dns_rdatatype_rrsig) {
   5712  1.1  christos 				/*
   5713  1.1  christos 				 * Is it active and extant?
   5714  1.1  christos 				 */
   5715  1.1  christos 				do {
   5716  1.1  christos 					if (header->serial <= serial &&
   5717  1.1  christos 					    !IGNORE(header)) {
   5718  1.1  christos 						/*
   5719  1.1  christos 						 * Is this a "this rdataset
   5720  1.1  christos 						 * doesn't exist" record?
   5721  1.1  christos 						 */
   5722  1.1  christos 						if (NONEXISTENT(header))
   5723  1.1  christos 							header = NULL;
   5724  1.1  christos 						break;
   5725  1.1  christos 					} else
   5726  1.1  christos 						header = header->down;
   5727  1.1  christos 				} while (header != NULL);
   5728  1.1  christos 				if (header != NULL)
   5729  1.3  christos 					other_data = true;
   5730  1.1  christos 			}
   5731  1.1  christos 		}
   5732  1.1  christos 	}
   5733  1.1  christos 
   5734  1.1  christos 	if (cname && other_data)
   5735  1.3  christos 		return (true);
   5736  1.1  christos 
   5737  1.3  christos 	return (false);
   5738  1.1  christos }
   5739  1.1  christos 
   5740  1.1  christos static isc_result_t
   5741  1.1  christos resign_insert(dns_rbtdb_t *rbtdb, int idx, rdatasetheader_t *newheader) {
   5742  1.1  christos 	isc_result_t result;
   5743  1.1  christos 
   5744  1.1  christos 	INSIST(!IS_CACHE(rbtdb));
   5745  1.1  christos 	INSIST(newheader->heap_index == 0);
   5746  1.1  christos 	INSIST(!ISC_LINK_LINKED(newheader, link));
   5747  1.1  christos 
   5748  1.1  christos 	result = isc_heap_insert(rbtdb->heaps[idx], newheader);
   5749  1.1  christos 	return (result);
   5750  1.1  christos }
   5751  1.1  christos 
   5752  1.1  christos static void
   5753  1.1  christos resign_delete(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
   5754  1.1  christos 	      rdatasetheader_t *header)
   5755  1.1  christos {
   5756  1.1  christos 	/*
   5757  1.1  christos 	 * Remove the old header from the heap
   5758  1.1  christos 	 */
   5759  1.1  christos 	if (header != NULL && header->heap_index != 0) {
   5760  1.1  christos 		isc_heap_delete(rbtdb->heaps[header->node->locknum],
   5761  1.1  christos 				header->heap_index);
   5762  1.1  christos 		header->heap_index = 0;
   5763  1.1  christos 		if (version != NULL) {
   5764  1.1  christos 			new_reference(rbtdb, header->node);
   5765  1.1  christos 			ISC_LIST_APPEND(version->resigned_list, header, link);
   5766  1.1  christos 		}
   5767  1.1  christos 	}
   5768  1.1  christos }
   5769  1.1  christos 
   5770  1.1  christos static void
   5771  1.3  christos update_recordsandbytes(bool add, rbtdb_version_t *rbtversion,
   5772  1.1  christos 		       rdatasetheader_t *header)
   5773  1.1  christos {
   5774  1.1  christos 	unsigned char *hdr = (unsigned char *)header;
   5775  1.1  christos 	size_t hdrsize = sizeof (*header);
   5776  1.1  christos 
   5777  1.1  christos 	if (add) {
   5778  1.1  christos 		rbtversion->records += dns_rdataslab_count(hdr, hdrsize);
   5779  1.1  christos 		rbtversion->bytes += dns_rdataslab_size(hdr, hdrsize);
   5780  1.1  christos 	} else {
   5781  1.1  christos 		rbtversion->records -= dns_rdataslab_count(hdr, hdrsize);
   5782  1.1  christos 		rbtversion->bytes -= dns_rdataslab_size(hdr, hdrsize);
   5783  1.1  christos 	}
   5784  1.1  christos }
   5785  1.1  christos 
   5786  1.1  christos static isc_result_t
   5787  1.1  christos add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
   5788  1.3  christos       rdatasetheader_t *newheader, unsigned int options, bool loading,
   5789  1.1  christos       dns_rdataset_t *addedrdataset, isc_stdtime_t now)
   5790  1.1  christos {
   5791  1.1  christos 	rbtdb_changed_t *changed = NULL;
   5792  1.1  christos 	rdatasetheader_t *topheader, *topheader_prev, *header, *sigheader;
   5793  1.1  christos 	unsigned char *merged;
   5794  1.1  christos 	isc_result_t result;
   5795  1.3  christos 	bool header_nx;
   5796  1.3  christos 	bool newheader_nx;
   5797  1.3  christos 	bool merge;
   5798  1.1  christos 	dns_rdatatype_t rdtype, covers;
   5799  1.1  christos 	rbtdb_rdatatype_t negtype, sigtype;
   5800  1.1  christos 	dns_trust_t trust;
   5801  1.1  christos 	int idx;
   5802  1.1  christos 
   5803  1.1  christos 	/*
   5804  1.1  christos 	 * Add an rdatasetheader_t to a node.
   5805  1.1  christos 	 */
   5806  1.1  christos 
   5807  1.1  christos 	/*
   5808  1.1  christos 	 * Caller must be holding the node lock.
   5809  1.1  christos 	 */
   5810  1.1  christos 
   5811  1.1  christos 	if ((options & DNS_DBADD_MERGE) != 0) {
   5812  1.1  christos 		REQUIRE(rbtversion != NULL);
   5813  1.3  christos 		merge = true;
   5814  1.1  christos 	} else
   5815  1.3  christos 		merge = false;
   5816  1.1  christos 
   5817  1.1  christos 	if ((options & DNS_DBADD_FORCE) != 0)
   5818  1.1  christos 		trust = dns_trust_ultimate;
   5819  1.1  christos 	else
   5820  1.1  christos 		trust = newheader->trust;
   5821  1.1  christos 
   5822  1.1  christos 	if (rbtversion != NULL && !loading) {
   5823  1.1  christos 		/*
   5824  1.1  christos 		 * We always add a changed record, even if no changes end up
   5825  1.1  christos 		 * being made to this node, because it's harmless and
   5826  1.1  christos 		 * simplifies the code.
   5827  1.1  christos 		 */
   5828  1.1  christos 		changed = add_changed(rbtdb, rbtversion, rbtnode);
   5829  1.1  christos 		if (changed == NULL) {
   5830  1.1  christos 			free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   5831  1.1  christos 			return (ISC_R_NOMEMORY);
   5832  1.1  christos 		}
   5833  1.1  christos 	}
   5834  1.1  christos 
   5835  1.3  christos 	newheader_nx = NONEXISTENT(newheader) ? true : false;
   5836  1.1  christos 	topheader_prev = NULL;
   5837  1.1  christos 	sigheader = NULL;
   5838  1.1  christos 	negtype = 0;
   5839  1.1  christos 	if (rbtversion == NULL && !newheader_nx) {
   5840  1.1  christos 		rdtype = RBTDB_RDATATYPE_BASE(newheader->type);
   5841  1.1  christos 		covers = RBTDB_RDATATYPE_EXT(newheader->type);
   5842  1.1  christos 		sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, covers);
   5843  1.1  christos 		if (NEGATIVE(newheader)) {
   5844  1.1  christos 			/*
   5845  1.1  christos 			 * We're adding a negative cache entry.
   5846  1.1  christos 			 */
   5847  1.1  christos 			if (covers == dns_rdatatype_any) {
   5848  1.1  christos 				/*
   5849  1.1  christos 				 * If we're adding an negative cache entry
   5850  1.1  christos 				 * which covers all types (NXDOMAIN,
   5851  1.1  christos 				 * NODATA(QTYPE=ANY)),
   5852  1.1  christos 				 *
   5853  1.1  christos 				 * We make all other data stale so that the
   5854  1.1  christos 				 * only rdataset that can be found at this
   5855  1.1  christos 				 * node is the negative cache entry.
   5856  1.1  christos 				 */
   5857  1.1  christos 				for (topheader = rbtnode->data;
   5858  1.1  christos 				     topheader != NULL;
   5859  1.1  christos 				     topheader = topheader->next)
   5860  1.1  christos 				{
   5861  1.1  christos 					set_ttl(rbtdb, topheader, 0);
   5862  1.1  christos 					mark_header_ancient(rbtdb, topheader);
   5863  1.1  christos 				}
   5864  1.1  christos 				goto find_header;
   5865  1.1  christos 			}
   5866  1.1  christos 			/*
   5867  1.1  christos 			 * Otherwise look for any RRSIGs of the given
   5868  1.1  christos 			 * type so they can be marked stale later.
   5869  1.1  christos 			 */
   5870  1.1  christos 			for (topheader = rbtnode->data;
   5871  1.1  christos 			     topheader != NULL;
   5872  1.1  christos 			     topheader = topheader->next)
   5873  1.1  christos 				if (topheader->type == sigtype)
   5874  1.1  christos 					sigheader = topheader;
   5875  1.1  christos 			negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
   5876  1.1  christos 		} else {
   5877  1.1  christos 			/*
   5878  1.1  christos 			 * We're adding something that isn't a
   5879  1.1  christos 			 * negative cache entry.  Look for an extant
   5880  1.1  christos 			 * non-stale NXDOMAIN/NODATA(QTYPE=ANY) negative
   5881  1.1  christos 			 * cache entry.  If we're adding an RRSIG, also
   5882  1.1  christos 			 * check for an extant non-stale NODATA ncache
   5883  1.1  christos 			 * entry which covers the same type as the RRSIG.
   5884  1.1  christos 			 */
   5885  1.1  christos 			for (topheader = rbtnode->data;
   5886  1.1  christos 			     topheader != NULL;
   5887  1.1  christos 			     topheader = topheader->next) {
   5888  1.1  christos 				if ((topheader->type ==
   5889  1.1  christos 					RBTDB_RDATATYPE_NCACHEANY) ||
   5890  1.1  christos 					(newheader->type == sigtype &&
   5891  1.1  christos 					topheader->type ==
   5892  1.1  christos 					RBTDB_RDATATYPE_VALUE(0, covers))) {
   5893  1.1  christos 						break;
   5894  1.1  christos 					}
   5895  1.1  christos 			}
   5896  1.1  christos 			if (topheader != NULL && EXISTS(topheader) &&
   5897  1.1  christos 			    ACTIVE(topheader, now)) {
   5898  1.1  christos 				/*
   5899  1.1  christos 				 * Found one.
   5900  1.1  christos 				 */
   5901  1.1  christos 				if (trust < topheader->trust) {
   5902  1.1  christos 					/*
   5903  1.1  christos 					 * The NXDOMAIN/NODATA(QTYPE=ANY)
   5904  1.1  christos 					 * is more trusted.
   5905  1.1  christos 					 */
   5906  1.1  christos 					free_rdataset(rbtdb,
   5907  1.1  christos 						      rbtdb->common.mctx,
   5908  1.1  christos 						      newheader);
   5909  1.1  christos 					if (addedrdataset != NULL)
   5910  1.1  christos 						bind_rdataset(rbtdb, rbtnode,
   5911  1.1  christos 							      topheader, now,
   5912  1.1  christos 							      addedrdataset);
   5913  1.1  christos 					return (DNS_R_UNCHANGED);
   5914  1.1  christos 				}
   5915  1.1  christos 				/*
   5916  1.1  christos 				 * The new rdataset is better.  Expire the
   5917  1.1  christos 				 * ncache entry.
   5918  1.1  christos 				 */
   5919  1.1  christos 				set_ttl(rbtdb, topheader, 0);
   5920  1.1  christos 				mark_header_ancient(rbtdb, topheader);
   5921  1.1  christos 				topheader = NULL;
   5922  1.1  christos 				goto find_header;
   5923  1.1  christos 			}
   5924  1.1  christos 			negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
   5925  1.1  christos 		}
   5926  1.1  christos 	}
   5927  1.1  christos 
   5928  1.1  christos 	for (topheader = rbtnode->data;
   5929  1.1  christos 	     topheader != NULL;
   5930  1.1  christos 	     topheader = topheader->next) {
   5931  1.1  christos 		if (topheader->type == newheader->type ||
   5932  1.1  christos 		    topheader->type == negtype)
   5933  1.1  christos 			break;
   5934  1.1  christos 		topheader_prev = topheader;
   5935  1.1  christos 	}
   5936  1.1  christos 
   5937  1.1  christos  find_header:
   5938  1.1  christos 	/*
   5939  1.1  christos 	 * If header isn't NULL, we've found the right type.  There may be
   5940  1.1  christos 	 * IGNORE rdatasets between the top of the chain and the first real
   5941  1.1  christos 	 * data.  We skip over them.
   5942  1.1  christos 	 */
   5943  1.1  christos 	header = topheader;
   5944  1.1  christos 	while (header != NULL && IGNORE(header))
   5945  1.1  christos 		header = header->down;
   5946  1.1  christos 	if (header != NULL) {
   5947  1.3  christos 		header_nx = NONEXISTENT(header) ? true : false;
   5948  1.1  christos 
   5949  1.1  christos 		/*
   5950  1.1  christos 		 * Deleting an already non-existent rdataset has no effect.
   5951  1.1  christos 		 */
   5952  1.1  christos 		if (header_nx && newheader_nx) {
   5953  1.1  christos 			free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   5954  1.1  christos 			return (DNS_R_UNCHANGED);
   5955  1.1  christos 		}
   5956  1.1  christos 
   5957  1.1  christos 		/*
   5958  1.1  christos 		 * Trying to add an rdataset with lower trust to a cache
   5959  1.1  christos 		 * DB has no effect, provided that the cache data isn't
   5960  1.1  christos 		 * stale. If the cache data is stale, new lower trust
   5961  1.1  christos 		 * data will supersede it below. Unclear what the best
   5962  1.1  christos 		 * policy is here.
   5963  1.1  christos 		 */
   5964  1.1  christos 		if (rbtversion == NULL && trust < header->trust &&
   5965  1.1  christos 		    (ACTIVE(header, now) || header_nx)) {
   5966  1.1  christos 			free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   5967  1.1  christos 			if (addedrdataset != NULL)
   5968  1.1  christos 				bind_rdataset(rbtdb, rbtnode, header, now,
   5969  1.1  christos 					      addedrdataset);
   5970  1.1  christos 			return (DNS_R_UNCHANGED);
   5971  1.1  christos 		}
   5972  1.1  christos 
   5973  1.1  christos 		/*
   5974  1.1  christos 		 * Don't merge if a nonexistent rdataset is involved.
   5975  1.1  christos 		 */
   5976  1.1  christos 		if (merge && (header_nx || newheader_nx))
   5977  1.3  christos 			merge = false;
   5978  1.1  christos 
   5979  1.1  christos 		/*
   5980  1.3  christos 		 * If 'merge' is true, we'll try to create a new rdataset
   5981  1.1  christos 		 * that is the union of 'newheader' and 'header'.
   5982  1.1  christos 		 */
   5983  1.1  christos 		if (merge) {
   5984  1.1  christos 			unsigned int flags = 0;
   5985  1.1  christos 			INSIST(rbtversion->serial >= header->serial);
   5986  1.1  christos 			merged = NULL;
   5987  1.1  christos 			result = ISC_R_SUCCESS;
   5988  1.1  christos 
   5989  1.1  christos 			if ((options & DNS_DBADD_EXACT) != 0)
   5990  1.1  christos 				flags |= DNS_RDATASLAB_EXACT;
   5991  1.1  christos 			/*
   5992  1.1  christos 			 * TTL use here is irrelevant to the cache;
   5993  1.1  christos 			 * merge is only done with zonedbs.
   5994  1.1  christos 			 */
   5995  1.1  christos 			if ((options & DNS_DBADD_EXACTTTL) != 0 &&
   5996  1.1  christos 			     newheader->rdh_ttl != header->rdh_ttl)
   5997  1.1  christos 					result = DNS_R_NOTEXACT;
   5998  1.1  christos 			else if (newheader->rdh_ttl != header->rdh_ttl)
   5999  1.1  christos 				flags |= DNS_RDATASLAB_FORCE;
   6000  1.1  christos 			if (result == ISC_R_SUCCESS)
   6001  1.1  christos 				result = dns_rdataslab_merge(
   6002  1.1  christos 					     (unsigned char *)header,
   6003  1.1  christos 					     (unsigned char *)newheader,
   6004  1.1  christos 					     (unsigned int)(sizeof(*newheader)),
   6005  1.1  christos 					     rbtdb->common.mctx,
   6006  1.1  christos 					     rbtdb->common.rdclass,
   6007  1.1  christos 					     (dns_rdatatype_t)header->type,
   6008  1.1  christos 					     flags, &merged);
   6009  1.1  christos 			if (result == ISC_R_SUCCESS) {
   6010  1.1  christos 				/*
   6011  1.1  christos 				 * If 'header' has the same serial number as
   6012  1.1  christos 				 * we do, we could clean it up now if we knew
   6013  1.1  christos 				 * that our caller had no references to it.
   6014  1.1  christos 				 * We don't know this, however, so we leave it
   6015  1.1  christos 				 * alone.  It will get cleaned up when
   6016  1.1  christos 				 * clean_zone_node() runs.
   6017  1.1  christos 				 */
   6018  1.1  christos 				free_rdataset(rbtdb, rbtdb->common.mctx,
   6019  1.1  christos 					      newheader);
   6020  1.1  christos 				newheader = (rdatasetheader_t *)merged;
   6021  1.1  christos 				init_rdataset(rbtdb, newheader);
   6022  1.1  christos 				update_newheader(newheader, header);
   6023  1.1  christos 				if (loading && RESIGN(newheader) &&
   6024  1.1  christos 				    RESIGN(header) &&
   6025  1.1  christos 				    resign_sooner(header, newheader))
   6026  1.1  christos 				{
   6027  1.1  christos 					newheader->resign = header->resign;
   6028  1.1  christos 					newheader->resign_lsb =
   6029  1.1  christos 							header->resign_lsb;
   6030  1.1  christos 				}
   6031  1.1  christos 			} else {
   6032  1.1  christos 				free_rdataset(rbtdb, rbtdb->common.mctx,
   6033  1.1  christos 					      newheader);
   6034  1.1  christos 				return (result);
   6035  1.1  christos 			}
   6036  1.1  christos 		}
   6037  1.1  christos 		/*
   6038  1.1  christos 		 * Don't replace existing NS, A and AAAA RRsets in the
   6039  1.1  christos 		 * cache if they are already exist. This prevents named
   6040  1.1  christos 		 * being locked to old servers. Don't lower trust of
   6041  1.1  christos 		 * existing record if the update is forced. Nothing
   6042  1.1  christos 		 * special to be done w.r.t stale data; it gets replaced
   6043  1.1  christos 		 * normally further down.
   6044  1.1  christos 		 */
   6045  1.1  christos 		if (IS_CACHE(rbtdb) && ACTIVE(header, now) &&
   6046  1.1  christos 		    header->type == dns_rdatatype_ns &&
   6047  1.1  christos 		    !header_nx && !newheader_nx &&
   6048  1.1  christos 		    header->trust >= newheader->trust &&
   6049  1.1  christos 		    dns_rdataslab_equalx((unsigned char *)header,
   6050  1.1  christos 					 (unsigned char *)newheader,
   6051  1.1  christos 					 (unsigned int)(sizeof(*newheader)),
   6052  1.1  christos 					 rbtdb->common.rdclass,
   6053  1.1  christos 					 (dns_rdatatype_t)header->type)) {
   6054  1.1  christos 			/*
   6055  1.1  christos 			 * Honour the new ttl if it is less than the
   6056  1.1  christos 			 * older one.
   6057  1.1  christos 			 */
   6058  1.1  christos 			if (header->rdh_ttl > newheader->rdh_ttl)
   6059  1.1  christos 				set_ttl(rbtdb, header, newheader->rdh_ttl);
   6060  1.1  christos 			if (header->noqname == NULL &&
   6061  1.1  christos 			    newheader->noqname != NULL) {
   6062  1.1  christos 				header->noqname = newheader->noqname;
   6063  1.1  christos 				newheader->noqname = NULL;
   6064  1.1  christos 			}
   6065  1.1  christos 			if (header->closest == NULL &&
   6066  1.1  christos 			    newheader->closest != NULL) {
   6067  1.1  christos 				header->closest = newheader->closest;
   6068  1.1  christos 				newheader->closest = NULL;
   6069  1.1  christos 			}
   6070  1.1  christos 			free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   6071  1.1  christos 			if (addedrdataset != NULL)
   6072  1.1  christos 				bind_rdataset(rbtdb, rbtnode, header, now,
   6073  1.1  christos 					      addedrdataset);
   6074  1.1  christos 			return (ISC_R_SUCCESS);
   6075  1.1  christos 		}
   6076  1.1  christos 		/*
   6077  1.1  christos 		 * If we have will be replacing a NS RRset force its TTL
   6078  1.1  christos 		 * to be no more than the current NS RRset's TTL.  This
   6079  1.1  christos 		 * ensures the delegations that are withdrawn are honoured.
   6080  1.1  christos 		 */
   6081  1.1  christos 		if (IS_CACHE(rbtdb) && ACTIVE(header, now) &&
   6082  1.1  christos 		    header->type == dns_rdatatype_ns &&
   6083  1.1  christos 		    !header_nx && !newheader_nx &&
   6084  1.1  christos 		    header->trust <= newheader->trust) {
   6085  1.1  christos 			if (newheader->rdh_ttl > header->rdh_ttl) {
   6086  1.1  christos 				newheader->rdh_ttl = header->rdh_ttl;
   6087  1.1  christos 			}
   6088  1.1  christos 		}
   6089  1.1  christos 		if (IS_CACHE(rbtdb) && ACTIVE(header, now) &&
   6090  1.1  christos 		    (options & DNS_DBADD_PREFETCH) == 0 &&
   6091  1.1  christos 		    (header->type == dns_rdatatype_a ||
   6092  1.1  christos 		     header->type == dns_rdatatype_aaaa ||
   6093  1.1  christos 		     header->type == dns_rdatatype_ds ||
   6094  1.1  christos 		     header->type == RBTDB_RDATATYPE_SIGDDS) &&
   6095  1.1  christos 		    !header_nx && !newheader_nx &&
   6096  1.1  christos 		    header->trust >= newheader->trust &&
   6097  1.1  christos 		    dns_rdataslab_equal((unsigned char *)header,
   6098  1.1  christos 					(unsigned char *)newheader,
   6099  1.1  christos 					(unsigned int)(sizeof(*newheader)))) {
   6100  1.1  christos 			/*
   6101  1.1  christos 			 * Honour the new ttl if it is less than the
   6102  1.1  christos 			 * older one.
   6103  1.1  christos 			 */
   6104  1.1  christos 			if (header->rdh_ttl > newheader->rdh_ttl)
   6105  1.1  christos 				set_ttl(rbtdb, header, newheader->rdh_ttl);
   6106  1.1  christos 			if (header->noqname == NULL &&
   6107  1.1  christos 			    newheader->noqname != NULL) {
   6108  1.1  christos 				header->noqname = newheader->noqname;
   6109  1.1  christos 				newheader->noqname = NULL;
   6110  1.1  christos 			}
   6111  1.1  christos 			if (header->closest == NULL &&
   6112  1.1  christos 			    newheader->closest != NULL) {
   6113  1.1  christos 				header->closest = newheader->closest;
   6114  1.1  christos 				newheader->closest = NULL;
   6115  1.1  christos 			}
   6116  1.1  christos 			free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   6117  1.1  christos 			if (addedrdataset != NULL)
   6118  1.1  christos 				bind_rdataset(rbtdb, rbtnode, header, now,
   6119  1.1  christos 					      addedrdataset);
   6120  1.1  christos 			return (ISC_R_SUCCESS);
   6121  1.1  christos 		}
   6122  1.1  christos 		INSIST(rbtversion == NULL ||
   6123  1.1  christos 		       rbtversion->serial >= topheader->serial);
   6124  1.1  christos 		if (loading) {
   6125  1.1  christos 			newheader->down = NULL;
   6126  1.1  christos 			idx = newheader->node->locknum;
   6127  1.1  christos 			if (IS_CACHE(rbtdb)) {
   6128  1.1  christos 				if (ZEROTTL(newheader))
   6129  1.1  christos 					ISC_LIST_APPEND(rbtdb->rdatasets[idx],
   6130  1.1  christos 							newheader, link);
   6131  1.1  christos 				else
   6132  1.1  christos 					ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
   6133  1.1  christos 							 newheader, link);
   6134  1.1  christos 				INSIST(rbtdb->heaps != NULL);
   6135  1.1  christos 				result = isc_heap_insert(rbtdb->heaps[idx],
   6136  1.1  christos 							 newheader);
   6137  1.1  christos 				if (result != ISC_R_SUCCESS) {
   6138  1.1  christos 					free_rdataset(rbtdb,
   6139  1.1  christos 						      rbtdb->common.mctx,
   6140  1.1  christos 						      newheader);
   6141  1.1  christos 					return (result);
   6142  1.1  christos 				}
   6143  1.1  christos 			} else if (RESIGN(newheader)) {
   6144  1.1  christos 				result = resign_insert(rbtdb, idx, newheader);
   6145  1.1  christos 				if (result != ISC_R_SUCCESS) {
   6146  1.1  christos 					free_rdataset(rbtdb,
   6147  1.1  christos 						      rbtdb->common.mctx,
   6148  1.1  christos 						      newheader);
   6149  1.1  christos 					return (result);
   6150  1.1  christos 				}
   6151  1.1  christos 				/*
   6152  1.1  christos 				 * Don't call resign_delete as we don't need
   6153  1.1  christos 				 * to reverse the delete.  The free_rdataset
   6154  1.1  christos 				 * call below will clean up the heap entry.
   6155  1.1  christos 				 */
   6156  1.1  christos 			}
   6157  1.1  christos 
   6158  1.1  christos 			/*
   6159  1.1  christos 			 * There are no other references to 'header' when
   6160  1.1  christos 			 * loading, so we MAY clean up 'header' now.
   6161  1.1  christos 			 * Since we don't generate changed records when
   6162  1.1  christos 			 * loading, we MUST clean up 'header' now.
   6163  1.1  christos 			 */
   6164  1.1  christos 			if (topheader_prev != NULL)
   6165  1.1  christos 				topheader_prev->next = newheader;
   6166  1.1  christos 			else
   6167  1.1  christos 				rbtnode->data = newheader;
   6168  1.1  christos 			newheader->next = topheader->next;
   6169  1.1  christos 			if (rbtversion != NULL && !header_nx) {
   6170  1.1  christos 				RWLOCK(&rbtversion->rwlock,
   6171  1.1  christos 				       isc_rwlocktype_write);
   6172  1.3  christos 				update_recordsandbytes(false, rbtversion,
   6173  1.1  christos 						       header);
   6174  1.1  christos 				RWUNLOCK(&rbtversion->rwlock,
   6175  1.1  christos 					 isc_rwlocktype_write);
   6176  1.1  christos 			}
   6177  1.1  christos 			free_rdataset(rbtdb, rbtdb->common.mctx, header);
   6178  1.1  christos 		} else {
   6179  1.1  christos 			idx = newheader->node->locknum;
   6180  1.1  christos 			if (IS_CACHE(rbtdb)) {
   6181  1.1  christos 				INSIST(rbtdb->heaps != NULL);
   6182  1.1  christos 				result = isc_heap_insert(rbtdb->heaps[idx],
   6183  1.1  christos 							 newheader);
   6184  1.1  christos 				if (result != ISC_R_SUCCESS) {
   6185  1.1  christos 					free_rdataset(rbtdb,
   6186  1.1  christos 						      rbtdb->common.mctx,
   6187  1.1  christos 						      newheader);
   6188  1.1  christos 					return (result);
   6189  1.1  christos 				}
   6190  1.1  christos 				if (ZEROTTL(newheader))
   6191  1.1  christos 					ISC_LIST_APPEND(rbtdb->rdatasets[idx],
   6192  1.1  christos 							newheader, link);
   6193  1.1  christos 				else
   6194  1.1  christos 					ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
   6195  1.1  christos 							 newheader, link);
   6196  1.1  christos 			} else if (RESIGN(newheader)) {
   6197  1.1  christos 				result = resign_insert(rbtdb, idx, newheader);
   6198  1.1  christos 				if (result != ISC_R_SUCCESS) {
   6199  1.1  christos 					free_rdataset(rbtdb,
   6200  1.1  christos 						      rbtdb->common.mctx,
   6201  1.1  christos 						      newheader);
   6202  1.1  christos 					return (result);
   6203  1.1  christos 				}
   6204  1.1  christos 				resign_delete(rbtdb, rbtversion, header);
   6205  1.1  christos 			}
   6206  1.1  christos 			if (topheader_prev != NULL)
   6207  1.1  christos 				topheader_prev->next = newheader;
   6208  1.1  christos 			else
   6209  1.1  christos 				rbtnode->data = newheader;
   6210  1.1  christos 			newheader->next = topheader->next;
   6211  1.1  christos 			newheader->down = topheader;
   6212  1.1  christos 			topheader->next = newheader;
   6213  1.1  christos 			rbtnode->dirty = 1;
   6214  1.1  christos 			if (changed != NULL)
   6215  1.3  christos 				changed->dirty = true;
   6216  1.1  christos 			if (rbtversion == NULL) {
   6217  1.1  christos 				set_ttl(rbtdb, header, 0);
   6218  1.1  christos 				mark_header_ancient(rbtdb, header);
   6219  1.1  christos 				if (sigheader != NULL) {
   6220  1.1  christos 					set_ttl(rbtdb, sigheader, 0);
   6221  1.1  christos 					mark_header_ancient(rbtdb, sigheader);
   6222  1.1  christos 				}
   6223  1.1  christos 			}
   6224  1.1  christos 			if (rbtversion != NULL && !header_nx) {
   6225  1.1  christos 				RWLOCK(&rbtversion->rwlock,
   6226  1.1  christos 				       isc_rwlocktype_write);
   6227  1.3  christos 				update_recordsandbytes(false, rbtversion,
   6228  1.1  christos 						       header);
   6229  1.1  christos 				RWUNLOCK(&rbtversion->rwlock,
   6230  1.1  christos 					 isc_rwlocktype_write);
   6231  1.1  christos 			}
   6232  1.1  christos 		}
   6233  1.1  christos 	} else {
   6234  1.1  christos 		/*
   6235  1.1  christos 		 * No non-IGNORED rdatasets of the given type exist at
   6236  1.1  christos 		 * this node.
   6237  1.1  christos 		 */
   6238  1.1  christos 
   6239  1.1  christos 		/*
   6240  1.1  christos 		 * If we're trying to delete the type, don't bother.
   6241  1.1  christos 		 */
   6242  1.1  christos 		if (newheader_nx) {
   6243  1.1  christos 			free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   6244  1.1  christos 			return (DNS_R_UNCHANGED);
   6245  1.1  christos 		}
   6246  1.1  christos 
   6247  1.1  christos 		idx = newheader->node->locknum;
   6248  1.1  christos 		if (IS_CACHE(rbtdb)) {
   6249  1.1  christos 			result = isc_heap_insert(rbtdb->heaps[idx], newheader);
   6250  1.1  christos 			if (result != ISC_R_SUCCESS) {
   6251  1.1  christos 				free_rdataset(rbtdb, rbtdb->common.mctx,
   6252  1.1  christos 					      newheader);
   6253  1.1  christos 				return (result);
   6254  1.1  christos 			}
   6255  1.1  christos 			if (ZEROTTL(newheader))
   6256  1.1  christos 				ISC_LIST_APPEND(rbtdb->rdatasets[idx],
   6257  1.1  christos 						newheader, link);
   6258  1.1  christos 			else
   6259  1.1  christos 				ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
   6260  1.1  christos 						 newheader, link);
   6261  1.1  christos 		} else if (RESIGN(newheader)) {
   6262  1.1  christos 			result = resign_insert(rbtdb, idx, newheader);
   6263  1.1  christos 			if (result != ISC_R_SUCCESS) {
   6264  1.1  christos 				free_rdataset(rbtdb, rbtdb->common.mctx,
   6265  1.1  christos 					      newheader);
   6266  1.1  christos 				return (result);
   6267  1.1  christos 			}
   6268  1.1  christos 			resign_delete(rbtdb, rbtversion, header);
   6269  1.1  christos 		}
   6270  1.1  christos 
   6271  1.1  christos 		if (topheader != NULL) {
   6272  1.1  christos 			/*
   6273  1.1  christos 			 * We have an list of rdatasets of the given type,
   6274  1.1  christos 			 * but they're all marked IGNORE.  We simply insert
   6275  1.1  christos 			 * the new rdataset at the head of the list.
   6276  1.1  christos 			 *
   6277  1.1  christos 			 * Ignored rdatasets cannot occur during loading, so
   6278  1.1  christos 			 * we INSIST on it.
   6279  1.1  christos 			 */
   6280  1.1  christos 			INSIST(!loading);
   6281  1.1  christos 			INSIST(rbtversion == NULL ||
   6282  1.1  christos 			       rbtversion->serial >= topheader->serial);
   6283  1.1  christos 			if (topheader_prev != NULL)
   6284  1.1  christos 				topheader_prev->next = newheader;
   6285  1.1  christos 			else
   6286  1.1  christos 				rbtnode->data = newheader;
   6287  1.1  christos 			newheader->next = topheader->next;
   6288  1.1  christos 			newheader->down = topheader;
   6289  1.1  christos 			topheader->next = newheader;
   6290  1.1  christos 			rbtnode->dirty = 1;
   6291  1.1  christos 			if (changed != NULL)
   6292  1.3  christos 				changed->dirty = true;
   6293  1.1  christos 		} else {
   6294  1.1  christos 			/*
   6295  1.1  christos 			 * No rdatasets of the given type exist at the node.
   6296  1.1  christos 			 */
   6297  1.1  christos 			newheader->next = rbtnode->data;
   6298  1.1  christos 			newheader->down = NULL;
   6299  1.1  christos 			rbtnode->data = newheader;
   6300  1.1  christos 		}
   6301  1.1  christos 	}
   6302  1.1  christos 
   6303  1.1  christos 	if (rbtversion != NULL && !newheader_nx) {
   6304  1.1  christos 		RWLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
   6305  1.3  christos 		update_recordsandbytes(true, rbtversion, newheader);
   6306  1.1  christos 		RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
   6307  1.1  christos 	}
   6308  1.1  christos 
   6309  1.1  christos 	/*
   6310  1.1  christos 	 * Check if the node now contains CNAME and other data.
   6311  1.1  christos 	 */
   6312  1.1  christos 	if (rbtversion != NULL &&
   6313  1.1  christos 	    cname_and_other_data(rbtnode, rbtversion->serial))
   6314  1.1  christos 		return (DNS_R_CNAMEANDOTHER);
   6315  1.1  christos 
   6316  1.1  christos 	if (addedrdataset != NULL)
   6317  1.1  christos 		bind_rdataset(rbtdb, rbtnode, newheader, now, addedrdataset);
   6318  1.1  christos 
   6319  1.1  christos 	return (ISC_R_SUCCESS);
   6320  1.1  christos }
   6321  1.1  christos 
   6322  1.3  christos static inline bool
   6323  1.1  christos delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
   6324  1.1  christos 		rbtdb_rdatatype_t type)
   6325  1.1  christos {
   6326  1.1  christos 	if (IS_CACHE(rbtdb)) {
   6327  1.1  christos 		if (type == dns_rdatatype_dname)
   6328  1.3  christos 			return (true);
   6329  1.1  christos 		else
   6330  1.3  christos 			return (false);
   6331  1.1  christos 	} else if (type == dns_rdatatype_dname ||
   6332  1.1  christos 		   (type == dns_rdatatype_ns &&
   6333  1.1  christos 		    (node != rbtdb->origin_node || IS_STUB(rbtdb))))
   6334  1.3  christos 		return (true);
   6335  1.3  christos 	return (false);
   6336  1.1  christos }
   6337  1.1  christos 
   6338  1.1  christos static inline isc_result_t
   6339  1.1  christos addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
   6340  1.1  christos 	   dns_rdataset_t *rdataset)
   6341  1.1  christos {
   6342  1.1  christos 	struct noqname *noqname;
   6343  1.1  christos 	isc_mem_t *mctx = rbtdb->common.mctx;
   6344  1.1  christos 	dns_name_t name;
   6345  1.1  christos 	dns_rdataset_t neg, negsig;
   6346  1.1  christos 	isc_result_t result;
   6347  1.1  christos 	isc_region_t r;
   6348  1.1  christos 
   6349  1.1  christos 	dns_name_init(&name, NULL);
   6350  1.1  christos 	dns_rdataset_init(&neg);
   6351  1.1  christos 	dns_rdataset_init(&negsig);
   6352  1.1  christos 
   6353  1.1  christos 	result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig);
   6354  1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   6355  1.1  christos 
   6356  1.1  christos 	noqname = isc_mem_get(mctx, sizeof(*noqname));
   6357  1.1  christos 	if (noqname == NULL) {
   6358  1.1  christos 		result = ISC_R_NOMEMORY;
   6359  1.1  christos 		goto cleanup;
   6360  1.1  christos 	}
   6361  1.1  christos 	dns_name_init(&noqname->name, NULL);
   6362  1.1  christos 	noqname->neg = NULL;
   6363  1.1  christos 	noqname->negsig = NULL;
   6364  1.1  christos 	noqname->type = neg.type;
   6365  1.1  christos 	result = dns_name_dup(&name, mctx, &noqname->name);
   6366  1.1  christos 	if (result != ISC_R_SUCCESS)
   6367  1.1  christos 		goto cleanup;
   6368  1.1  christos 	result = dns_rdataslab_fromrdataset(&neg, mctx, &r, 0);
   6369  1.1  christos 	if (result != ISC_R_SUCCESS)
   6370  1.1  christos 		goto cleanup;
   6371  1.1  christos 	noqname->neg = r.base;
   6372  1.1  christos 	result = dns_rdataslab_fromrdataset(&negsig, mctx, &r, 0);
   6373  1.1  christos 	if (result != ISC_R_SUCCESS)
   6374  1.1  christos 		goto cleanup;
   6375  1.1  christos 	noqname->negsig = r.base;
   6376  1.1  christos 	dns_rdataset_disassociate(&neg);
   6377  1.1  christos 	dns_rdataset_disassociate(&negsig);
   6378  1.1  christos 	newheader->noqname = noqname;
   6379  1.1  christos 	return (ISC_R_SUCCESS);
   6380  1.1  christos 
   6381  1.1  christos cleanup:
   6382  1.1  christos 	dns_rdataset_disassociate(&neg);
   6383  1.1  christos 	dns_rdataset_disassociate(&negsig);
   6384  1.1  christos 	if (noqname != NULL)
   6385  1.1  christos 		free_noqname(mctx, &noqname);
   6386  1.1  christos 	return(result);
   6387  1.1  christos }
   6388  1.1  christos 
   6389  1.1  christos static inline isc_result_t
   6390  1.1  christos addclosest(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
   6391  1.1  christos 	   dns_rdataset_t *rdataset)
   6392  1.1  christos {
   6393  1.1  christos 	struct noqname *closest;
   6394  1.1  christos 	isc_mem_t *mctx = rbtdb->common.mctx;
   6395  1.1  christos 	dns_name_t name;
   6396  1.1  christos 	dns_rdataset_t neg, negsig;
   6397  1.1  christos 	isc_result_t result;
   6398  1.1  christos 	isc_region_t r;
   6399  1.1  christos 
   6400  1.1  christos 	dns_name_init(&name, NULL);
   6401  1.1  christos 	dns_rdataset_init(&neg);
   6402  1.1  christos 	dns_rdataset_init(&negsig);
   6403  1.1  christos 
   6404  1.1  christos 	result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig);
   6405  1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   6406  1.1  christos 
   6407  1.1  christos 	closest = isc_mem_get(mctx, sizeof(*closest));
   6408  1.1  christos 	if (closest == NULL) {
   6409  1.1  christos 		result = ISC_R_NOMEMORY;
   6410  1.1  christos 		goto cleanup;
   6411  1.1  christos 	}
   6412  1.1  christos 	dns_name_init(&closest->name, NULL);
   6413  1.1  christos 	closest->neg = NULL;
   6414  1.1  christos 	closest->negsig = NULL;
   6415  1.1  christos 	closest->type = neg.type;
   6416  1.1  christos 	result = dns_name_dup(&name, mctx, &closest->name);
   6417  1.1  christos 	if (result != ISC_R_SUCCESS)
   6418  1.1  christos 		goto cleanup;
   6419  1.1  christos 	result = dns_rdataslab_fromrdataset(&neg, mctx, &r, 0);
   6420  1.1  christos 	if (result != ISC_R_SUCCESS)
   6421  1.1  christos 		goto cleanup;
   6422  1.1  christos 	closest->neg = r.base;
   6423  1.1  christos 	result = dns_rdataslab_fromrdataset(&negsig, mctx, &r, 0);
   6424  1.1  christos 	if (result != ISC_R_SUCCESS)
   6425  1.1  christos 		goto cleanup;
   6426  1.1  christos 	closest->negsig = r.base;
   6427  1.1  christos 	dns_rdataset_disassociate(&neg);
   6428  1.1  christos 	dns_rdataset_disassociate(&negsig);
   6429  1.1  christos 	newheader->closest = closest;
   6430  1.1  christos 	return (ISC_R_SUCCESS);
   6431  1.1  christos 
   6432  1.1  christos  cleanup:
   6433  1.1  christos 	dns_rdataset_disassociate(&neg);
   6434  1.1  christos 	dns_rdataset_disassociate(&negsig);
   6435  1.1  christos 	if (closest != NULL)
   6436  1.1  christos 		free_noqname(mctx, &closest);
   6437  1.1  christos 	return(result);
   6438  1.1  christos }
   6439  1.1  christos 
   6440  1.1  christos static dns_dbmethods_t zone_methods;
   6441  1.1  christos 
   6442  1.1  christos static isc_result_t
   6443  1.1  christos addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
   6444  1.1  christos 	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
   6445  1.1  christos 	    dns_rdataset_t *addedrdataset)
   6446  1.1  christos {
   6447  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   6448  1.1  christos 	dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
   6449  1.1  christos 	rbtdb_version_t *rbtversion = version;
   6450  1.1  christos 	isc_region_t region;
   6451  1.1  christos 	rdatasetheader_t *newheader;
   6452  1.1  christos 	rdatasetheader_t *header;
   6453  1.1  christos 	isc_result_t result;
   6454  1.3  christos 	bool delegating;
   6455  1.3  christos 	bool newnsec;
   6456  1.3  christos 	bool tree_locked = false;
   6457  1.3  christos 	bool cache_is_overmem = false;
   6458  1.1  christos 	dns_fixedname_t fixed;
   6459  1.1  christos 	dns_name_t *name;
   6460  1.1  christos 
   6461  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   6462  1.1  christos 	INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
   6463  1.1  christos 
   6464  1.1  christos 	if (rbtdb->common.methods == &zone_methods)
   6465  1.1  christos 		REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 &&
   6466  1.1  christos 			  (rdataset->type == dns_rdatatype_nsec3 ||
   6467  1.1  christos 			   rdataset->covers == dns_rdatatype_nsec3)) ||
   6468  1.1  christos 			 (rbtnode->nsec != DNS_RBT_NSEC_NSEC3 &&
   6469  1.1  christos 			   rdataset->type != dns_rdatatype_nsec3 &&
   6470  1.1  christos 			   rdataset->covers != dns_rdatatype_nsec3)));
   6471  1.1  christos 
   6472  1.1  christos 	if (rbtversion == NULL) {
   6473  1.1  christos 		if (now == 0)
   6474  1.1  christos 			isc_stdtime_get(&now);
   6475  1.1  christos 	} else
   6476  1.1  christos 		now = 0;
   6477  1.1  christos 
   6478  1.1  christos 	result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
   6479  1.1  christos 					    &region, sizeof(rdatasetheader_t));
   6480  1.1  christos 	if (result != ISC_R_SUCCESS)
   6481  1.1  christos 		return (result);
   6482  1.1  christos 
   6483  1.1  christos 	name = dns_fixedname_initname(&fixed);
   6484  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   6485  1.1  christos 	dns_rbt_fullnamefromnode(node, name);
   6486  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   6487  1.1  christos 	dns_rdataset_getownercase(rdataset, name);
   6488  1.1  christos 
   6489  1.1  christos 	newheader = (rdatasetheader_t *)region.base;
   6490  1.1  christos 	init_rdataset(rbtdb, newheader);
   6491  1.1  christos 	setownercase(newheader, name);
   6492  1.1  christos 	set_ttl(rbtdb, newheader, rdataset->ttl + now);
   6493  1.1  christos 	newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
   6494  1.1  christos 						rdataset->covers);
   6495  1.1  christos 	newheader->attributes = 0;
   6496  1.1  christos 	if (rdataset->ttl == 0U)
   6497  1.1  christos 		newheader->attributes |= RDATASET_ATTR_ZEROTTL;
   6498  1.1  christos 	newheader->noqname = NULL;
   6499  1.1  christos 	newheader->closest = NULL;
   6500  1.1  christos 	newheader->count = init_count++;
   6501  1.1  christos 	newheader->trust = rdataset->trust;
   6502  1.1  christos 	newheader->last_used = now;
   6503  1.1  christos 	newheader->node = rbtnode;
   6504  1.1  christos 	if (rbtversion != NULL) {
   6505  1.1  christos 		newheader->serial = rbtversion->serial;
   6506  1.1  christos 		now = 0;
   6507  1.1  christos 
   6508  1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
   6509  1.1  christos 			newheader->attributes |= RDATASET_ATTR_RESIGN;
   6510  1.1  christos 			newheader->resign = (isc_stdtime_t)
   6511  1.1  christos 				(dns_time64_from32(rdataset->resign) >> 1);
   6512  1.1  christos 			newheader->resign_lsb = rdataset->resign & 0x1;
   6513  1.1  christos 		} else {
   6514  1.1  christos 			newheader->resign = 0;
   6515  1.1  christos 			newheader->resign_lsb = 0;
   6516  1.1  christos 		}
   6517  1.1  christos 	} else {
   6518  1.1  christos 		newheader->serial = 1;
   6519  1.1  christos 		newheader->resign = 0;
   6520  1.1  christos 		newheader->resign_lsb = 0;
   6521  1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_PREFETCH) != 0)
   6522  1.1  christos 			newheader->attributes |= RDATASET_ATTR_PREFETCH;
   6523  1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
   6524  1.1  christos 			newheader->attributes |= RDATASET_ATTR_NEGATIVE;
   6525  1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
   6526  1.1  christos 			newheader->attributes |= RDATASET_ATTR_NXDOMAIN;
   6527  1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
   6528  1.1  christos 			newheader->attributes |= RDATASET_ATTR_OPTOUT;
   6529  1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
   6530  1.1  christos 			result = addnoqname(rbtdb, newheader, rdataset);
   6531  1.1  christos 			if (result != ISC_R_SUCCESS) {
   6532  1.1  christos 				free_rdataset(rbtdb, rbtdb->common.mctx,
   6533  1.1  christos 					      newheader);
   6534  1.1  christos 				return (result);
   6535  1.1  christos 			}
   6536  1.1  christos 		}
   6537  1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) {
   6538  1.1  christos 			result = addclosest(rbtdb, newheader, rdataset);
   6539  1.1  christos 			if (result != ISC_R_SUCCESS) {
   6540  1.1  christos 				free_rdataset(rbtdb, rbtdb->common.mctx,
   6541  1.1  christos 					      newheader);
   6542  1.1  christos 				return (result);
   6543  1.1  christos 			}
   6544  1.1  christos 		}
   6545  1.1  christos 	}
   6546  1.1  christos 
   6547  1.1  christos 	/*
   6548  1.1  christos 	 * If we're adding a delegation type (e.g. NS or DNAME for a zone,
   6549  1.1  christos 	 * just DNAME for the cache), then we need to set the callback bit
   6550  1.1  christos 	 * on the node.
   6551  1.1  christos 	 */
   6552  1.1  christos 	if (delegating_type(rbtdb, rbtnode, rdataset->type))
   6553  1.3  christos 		delegating = true;
   6554  1.1  christos 	else
   6555  1.3  christos 		delegating = false;
   6556  1.1  christos 
   6557  1.1  christos 	/*
   6558  1.1  christos 	 * Add to the auxiliary NSEC tree if we're adding an NSEC record.
   6559  1.1  christos 	 */
   6560  1.1  christos 	if (rbtnode->nsec != DNS_RBT_NSEC_HAS_NSEC &&
   6561  1.1  christos 	    rdataset->type == dns_rdatatype_nsec)
   6562  1.3  christos 		newnsec = true;
   6563  1.1  christos 	else
   6564  1.3  christos 		newnsec = false;
   6565  1.1  christos 
   6566  1.1  christos 	/*
   6567  1.1  christos 	 * If we're adding a delegation type, adding to the auxiliary NSEC tree,
   6568  1.1  christos 	 * or the DB is a cache in an overmem state, hold an exclusive lock on
   6569  1.1  christos 	 * the tree.  In the latter case the lock does not necessarily have to
   6570  1.1  christos 	 * be acquired but it will help purge stale entries more effectively.
   6571  1.1  christos 	 */
   6572  1.1  christos 	if (IS_CACHE(rbtdb) && isc_mem_isovermem(rbtdb->common.mctx))
   6573  1.3  christos 		cache_is_overmem = true;
   6574  1.1  christos 	if (delegating || newnsec || cache_is_overmem) {
   6575  1.3  christos 		tree_locked = true;
   6576  1.1  christos 		RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   6577  1.1  christos 	}
   6578  1.1  christos 
   6579  1.1  christos 	if (cache_is_overmem)
   6580  1.1  christos 		overmem_purge(rbtdb, rbtnode->locknum, now, tree_locked);
   6581  1.1  christos 
   6582  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   6583  1.1  christos 		  isc_rwlocktype_write);
   6584  1.1  christos 
   6585  1.1  christos 	if (rbtdb->rrsetstats != NULL) {
   6586  1.1  christos 		newheader->attributes |= RDATASET_ATTR_STATCOUNT;
   6587  1.3  christos 		update_rrsetstats(rbtdb, newheader, true);
   6588  1.1  christos 	}
   6589  1.1  christos 
   6590  1.1  christos 	if (IS_CACHE(rbtdb)) {
   6591  1.1  christos 		if (tree_locked)
   6592  1.1  christos 			cleanup_dead_nodes(rbtdb, rbtnode->locknum);
   6593  1.1  christos 
   6594  1.1  christos 		header = isc_heap_element(rbtdb->heaps[rbtnode->locknum], 1);
   6595  1.1  christos 		if (header && header->rdh_ttl < now - RBTDB_VIRTUAL)
   6596  1.1  christos 			expire_header(rbtdb, header, tree_locked,
   6597  1.1  christos 				      expire_ttl);
   6598  1.1  christos 
   6599  1.1  christos 		/*
   6600  1.1  christos 		 * If we've been holding a write lock on the tree just for
   6601  1.1  christos 		 * cleaning, we can release it now.  However, we still need the
   6602  1.1  christos 		 * node lock.
   6603  1.1  christos 		 */
   6604  1.1  christos 		if (tree_locked && !delegating && !newnsec) {
   6605  1.1  christos 			RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   6606  1.3  christos 			tree_locked = false;
   6607  1.1  christos 		}
   6608  1.1  christos 	}
   6609  1.1  christos 
   6610  1.1  christos 	result = ISC_R_SUCCESS;
   6611  1.1  christos 	if (newnsec) {
   6612  1.1  christos 		dns_rbtnode_t *nsecnode;
   6613  1.1  christos 
   6614  1.1  christos 		dns_rbt_fullnamefromnode(rbtnode, name);
   6615  1.1  christos 		nsecnode = NULL;
   6616  1.1  christos 		result = dns_rbt_addnode(rbtdb->nsec, name, &nsecnode);
   6617  1.1  christos 		if (result == ISC_R_SUCCESS) {
   6618  1.1  christos 			nsecnode->nsec = DNS_RBT_NSEC_NSEC;
   6619  1.1  christos 			rbtnode->nsec = DNS_RBT_NSEC_HAS_NSEC;
   6620  1.1  christos 		} else if (result == ISC_R_EXISTS) {
   6621  1.1  christos 			rbtnode->nsec = DNS_RBT_NSEC_HAS_NSEC;
   6622  1.1  christos 			result = ISC_R_SUCCESS;
   6623  1.1  christos 		}
   6624  1.1  christos 	}
   6625  1.1  christos 
   6626  1.1  christos 	if (result == ISC_R_SUCCESS)
   6627  1.1  christos 		result = add32(rbtdb, rbtnode, rbtversion, newheader, options,
   6628  1.3  christos 			       false, addedrdataset, now);
   6629  1.1  christos 	if (result == ISC_R_SUCCESS && delegating)
   6630  1.1  christos 		rbtnode->find_callback = 1;
   6631  1.1  christos 
   6632  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   6633  1.1  christos 		    isc_rwlocktype_write);
   6634  1.1  christos 
   6635  1.1  christos 	if (tree_locked)
   6636  1.1  christos 		RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   6637  1.1  christos 
   6638  1.1  christos 	/*
   6639  1.1  christos 	 * Update the zone's secure status.  If version is non-NULL
   6640  1.1  christos 	 * this is deferred until closeversion() is called.
   6641  1.1  christos 	 */
   6642  1.1  christos 	if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
   6643  1.1  christos 		iszonesecure(db, version, rbtdb->origin_node);
   6644  1.1  christos 
   6645  1.1  christos 	return (result);
   6646  1.1  christos }
   6647  1.1  christos 
   6648  1.1  christos static isc_result_t
   6649  1.1  christos subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
   6650  1.1  christos 		 dns_rdataset_t *rdataset, unsigned int options,
   6651  1.1  christos 		 dns_rdataset_t *newrdataset)
   6652  1.1  christos {
   6653  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   6654  1.1  christos 	dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
   6655  1.1  christos 	rbtdb_version_t *rbtversion = version;
   6656  1.1  christos 	rdatasetheader_t *topheader, *topheader_prev, *header, *newheader;
   6657  1.1  christos 	unsigned char *subresult;
   6658  1.1  christos 	isc_region_t region;
   6659  1.1  christos 	isc_result_t result;
   6660  1.1  christos 	rbtdb_changed_t *changed;
   6661  1.1  christos 
   6662  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   6663  1.1  christos 	REQUIRE(rbtversion != NULL && rbtversion->rbtdb == rbtdb);
   6664  1.1  christos 
   6665  1.1  christos 	if (rbtdb->common.methods == &zone_methods)
   6666  1.1  christos 		REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 &&
   6667  1.1  christos 			  (rdataset->type == dns_rdatatype_nsec3 ||
   6668  1.1  christos 			   rdataset->covers == dns_rdatatype_nsec3)) ||
   6669  1.1  christos 			 (rbtnode->nsec != DNS_RBT_NSEC_NSEC3 &&
   6670  1.1  christos 			   rdataset->type != dns_rdatatype_nsec3 &&
   6671  1.1  christos 			   rdataset->covers != dns_rdatatype_nsec3)));
   6672  1.1  christos 
   6673  1.1  christos 	result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
   6674  1.1  christos 					    &region, sizeof(rdatasetheader_t));
   6675  1.1  christos 	if (result != ISC_R_SUCCESS)
   6676  1.1  christos 		return (result);
   6677  1.1  christos 	newheader = (rdatasetheader_t *)region.base;
   6678  1.1  christos 	init_rdataset(rbtdb, newheader);
   6679  1.1  christos 	set_ttl(rbtdb, newheader, rdataset->ttl);
   6680  1.1  christos 	newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
   6681  1.1  christos 						rdataset->covers);
   6682  1.1  christos 	newheader->attributes = 0;
   6683  1.1  christos 	newheader->serial = rbtversion->serial;
   6684  1.1  christos 	newheader->trust = 0;
   6685  1.1  christos 	newheader->noqname = NULL;
   6686  1.1  christos 	newheader->closest = NULL;
   6687  1.1  christos 	newheader->count = init_count++;
   6688  1.1  christos 	newheader->last_used = 0;
   6689  1.1  christos 	newheader->node = rbtnode;
   6690  1.1  christos 	if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
   6691  1.1  christos 		newheader->attributes |= RDATASET_ATTR_RESIGN;
   6692  1.1  christos 		newheader->resign = (isc_stdtime_t)
   6693  1.1  christos 			(dns_time64_from32(rdataset->resign) >> 1);
   6694  1.1  christos 		newheader->resign_lsb = rdataset->resign & 0x1;
   6695  1.1  christos 	} else {
   6696  1.1  christos 		newheader->resign = 0;
   6697  1.1  christos 		newheader->resign_lsb = 0;
   6698  1.1  christos 	}
   6699  1.1  christos 
   6700  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   6701  1.1  christos 		  isc_rwlocktype_write);
   6702  1.1  christos 
   6703  1.1  christos 	changed = add_changed(rbtdb, rbtversion, rbtnode);
   6704  1.1  christos 	if (changed == NULL) {
   6705  1.1  christos 		free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   6706  1.1  christos 		NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   6707  1.1  christos 			    isc_rwlocktype_write);
   6708  1.1  christos 		return (ISC_R_NOMEMORY);
   6709  1.1  christos 	}
   6710  1.1  christos 
   6711  1.1  christos 	topheader_prev = NULL;
   6712  1.1  christos 	for (topheader = rbtnode->data;
   6713  1.1  christos 	     topheader != NULL;
   6714  1.1  christos 	     topheader = topheader->next) {
   6715  1.1  christos 		if (topheader->type == newheader->type)
   6716  1.1  christos 			break;
   6717  1.1  christos 		topheader_prev = topheader;
   6718  1.1  christos 	}
   6719  1.1  christos 	/*
   6720  1.1  christos 	 * If header isn't NULL, we've found the right type.  There may be
   6721  1.1  christos 	 * IGNORE rdatasets between the top of the chain and the first real
   6722  1.1  christos 	 * data.  We skip over them.
   6723  1.1  christos 	 */
   6724  1.1  christos 	header = topheader;
   6725  1.1  christos 	while (header != NULL && IGNORE(header))
   6726  1.1  christos 		header = header->down;
   6727  1.1  christos 	if (header != NULL && EXISTS(header)) {
   6728  1.1  christos 		unsigned int flags = 0;
   6729  1.1  christos 		subresult = NULL;
   6730  1.1  christos 		result = ISC_R_SUCCESS;
   6731  1.1  christos 		if ((options & DNS_DBSUB_EXACT) != 0) {
   6732  1.1  christos 			flags |= DNS_RDATASLAB_EXACT;
   6733  1.1  christos 			if (newheader->rdh_ttl != header->rdh_ttl)
   6734  1.1  christos 				result = DNS_R_NOTEXACT;
   6735  1.1  christos 		}
   6736  1.1  christos 		if (result == ISC_R_SUCCESS)
   6737  1.1  christos 			result = dns_rdataslab_subtract(
   6738  1.1  christos 					(unsigned char *)header,
   6739  1.1  christos 					(unsigned char *)newheader,
   6740  1.1  christos 					(unsigned int)(sizeof(*newheader)),
   6741  1.1  christos 					rbtdb->common.mctx,
   6742  1.1  christos 					rbtdb->common.rdclass,
   6743  1.1  christos 					(dns_rdatatype_t)header->type,
   6744  1.1  christos 					flags, &subresult);
   6745  1.1  christos 		if (result == ISC_R_SUCCESS) {
   6746  1.1  christos 			free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   6747  1.1  christos 			newheader = (rdatasetheader_t *)subresult;
   6748  1.1  christos 			init_rdataset(rbtdb, newheader);
   6749  1.1  christos 			update_newheader(newheader, header);
   6750  1.1  christos 			if (RESIGN(header)) {
   6751  1.1  christos 				newheader->attributes |= RDATASET_ATTR_RESIGN;
   6752  1.1  christos 				newheader->resign = header->resign;
   6753  1.1  christos 				newheader->resign_lsb = header->resign_lsb;
   6754  1.1  christos 				result = resign_insert(rbtdb, rbtnode->locknum,
   6755  1.1  christos 						       newheader);
   6756  1.1  christos 				if (result != ISC_R_SUCCESS) {
   6757  1.1  christos 					free_rdataset(rbtdb,
   6758  1.1  christos 						      rbtdb->common.mctx,
   6759  1.1  christos 						      newheader);
   6760  1.1  christos 					goto unlock;
   6761  1.1  christos 				}
   6762  1.1  christos 			}
   6763  1.1  christos 			/*
   6764  1.1  christos 			 * We have to set the serial since the rdataslab
   6765  1.1  christos 			 * subtraction routine copies the reserved portion of
   6766  1.1  christos 			 * header, not newheader.
   6767  1.1  christos 			 */
   6768  1.1  christos 			newheader->serial = rbtversion->serial;
   6769  1.1  christos 			/*
   6770  1.1  christos 			 * XXXJT: dns_rdataslab_subtract() copied the pointers
   6771  1.1  christos 			 * to additional info.  We need to clear these fields
   6772  1.1  christos 			 * to avoid having duplicated references.
   6773  1.1  christos 			 */
   6774  1.3  christos 			update_recordsandbytes(true, rbtversion, newheader);
   6775  1.1  christos 		} else if (result == DNS_R_NXRRSET) {
   6776  1.1  christos 			/*
   6777  1.1  christos 			 * This subtraction would remove all of the rdata;
   6778  1.1  christos 			 * add a nonexistent header instead.
   6779  1.1  christos 			 */
   6780  1.1  christos 			free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   6781  1.1  christos 			newheader = new_rdataset(rbtdb, rbtdb->common.mctx);
   6782  1.1  christos 			if (newheader == NULL) {
   6783  1.1  christos 				result = ISC_R_NOMEMORY;
   6784  1.1  christos 				goto unlock;
   6785  1.1  christos 			}
   6786  1.1  christos 			init_rdataset(rbtdb, newheader);
   6787  1.1  christos 			set_ttl(rbtdb, newheader, 0);
   6788  1.1  christos 			newheader->type = topheader->type;
   6789  1.1  christos 			newheader->attributes = RDATASET_ATTR_NONEXISTENT;
   6790  1.1  christos 			newheader->trust = 0;
   6791  1.1  christos 			newheader->serial = rbtversion->serial;
   6792  1.1  christos 			newheader->noqname = NULL;
   6793  1.1  christos 			newheader->closest = NULL;
   6794  1.1  christos 			newheader->count = 0;
   6795  1.1  christos 			newheader->node = rbtnode;
   6796  1.1  christos 			newheader->resign = 0;
   6797  1.1  christos 			newheader->resign_lsb = 0;
   6798  1.1  christos 			newheader->last_used = 0;
   6799  1.1  christos 		} else {
   6800  1.1  christos 			free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   6801  1.1  christos 			goto unlock;
   6802  1.1  christos 		}
   6803  1.1  christos 
   6804  1.1  christos 		/*
   6805  1.1  christos 		 * If we're here, we want to link newheader in front of
   6806  1.1  christos 		 * topheader.
   6807  1.1  christos 		 */
   6808  1.1  christos 		INSIST(rbtversion->serial >= topheader->serial);
   6809  1.3  christos 		update_recordsandbytes(false, rbtversion, header);
   6810  1.1  christos 		if (topheader_prev != NULL)
   6811  1.1  christos 			topheader_prev->next = newheader;
   6812  1.1  christos 		else
   6813  1.1  christos 			rbtnode->data = newheader;
   6814  1.1  christos 		newheader->next = topheader->next;
   6815  1.1  christos 		newheader->down = topheader;
   6816  1.1  christos 		topheader->next = newheader;
   6817  1.1  christos 		rbtnode->dirty = 1;
   6818  1.3  christos 		changed->dirty = true;
   6819  1.1  christos 		resign_delete(rbtdb, rbtversion, header);
   6820  1.1  christos 	} else {
   6821  1.1  christos 		/*
   6822  1.1  christos 		 * The rdataset doesn't exist, so we don't need to do anything
   6823  1.1  christos 		 * to satisfy the deletion request.
   6824  1.1  christos 		 */
   6825  1.1  christos 		free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
   6826  1.1  christos 		if ((options & DNS_DBSUB_EXACT) != 0)
   6827  1.1  christos 			result = DNS_R_NOTEXACT;
   6828  1.1  christos 		else
   6829  1.1  christos 			result = DNS_R_UNCHANGED;
   6830  1.1  christos 	}
   6831  1.1  christos 
   6832  1.1  christos 	if (result == ISC_R_SUCCESS && newrdataset != NULL)
   6833  1.1  christos 		bind_rdataset(rbtdb, rbtnode, newheader, 0, newrdataset);
   6834  1.1  christos 
   6835  1.1  christos 	if (result == DNS_R_NXRRSET && newrdataset != NULL &&
   6836  1.1  christos 	    (options & DNS_DBSUB_WANTOLD) != 0)
   6837  1.1  christos 		bind_rdataset(rbtdb, rbtnode, header, 0, newrdataset);
   6838  1.1  christos 
   6839  1.1  christos  unlock:
   6840  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   6841  1.1  christos 		    isc_rwlocktype_write);
   6842  1.1  christos 
   6843  1.1  christos 	/*
   6844  1.1  christos 	 * Update the zone's secure status.  If version is non-NULL
   6845  1.1  christos 	 * this is deferred until closeversion() is called.
   6846  1.1  christos 	 */
   6847  1.1  christos 	if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
   6848  1.1  christos 		iszonesecure(db, rbtdb->current_version, rbtdb->origin_node);
   6849  1.1  christos 
   6850  1.1  christos 	return (result);
   6851  1.1  christos }
   6852  1.1  christos 
   6853  1.1  christos static isc_result_t
   6854  1.1  christos deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
   6855  1.1  christos 	       dns_rdatatype_t type, dns_rdatatype_t covers)
   6856  1.1  christos {
   6857  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   6858  1.1  christos 	dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
   6859  1.1  christos 	rbtdb_version_t *rbtversion = version;
   6860  1.1  christos 	isc_result_t result;
   6861  1.1  christos 	rdatasetheader_t *newheader;
   6862  1.1  christos 
   6863  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   6864  1.1  christos 	INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
   6865  1.1  christos 
   6866  1.1  christos 	if (type == dns_rdatatype_any)
   6867  1.1  christos 		return (ISC_R_NOTIMPLEMENTED);
   6868  1.1  christos 	if (type == dns_rdatatype_rrsig && covers == 0)
   6869  1.1  christos 		return (ISC_R_NOTIMPLEMENTED);
   6870  1.1  christos 
   6871  1.1  christos 	newheader = new_rdataset(rbtdb, rbtdb->common.mctx);
   6872  1.1  christos 	if (newheader == NULL)
   6873  1.1  christos 		return (ISC_R_NOMEMORY);
   6874  1.1  christos 	init_rdataset(rbtdb, newheader);
   6875  1.1  christos 	set_ttl(rbtdb, newheader, 0);
   6876  1.1  christos 	newheader->type = RBTDB_RDATATYPE_VALUE(type, covers);
   6877  1.1  christos 	newheader->attributes = RDATASET_ATTR_NONEXISTENT;
   6878  1.1  christos 	newheader->trust = 0;
   6879  1.1  christos 	newheader->noqname = NULL;
   6880  1.1  christos 	newheader->closest = NULL;
   6881  1.1  christos 	if (rbtversion != NULL)
   6882  1.1  christos 		newheader->serial = rbtversion->serial;
   6883  1.1  christos 	else
   6884  1.1  christos 		newheader->serial = 0;
   6885  1.1  christos 	newheader->count = 0;
   6886  1.1  christos 	newheader->last_used = 0;
   6887  1.1  christos 	newheader->node = rbtnode;
   6888  1.1  christos 
   6889  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   6890  1.1  christos 		  isc_rwlocktype_write);
   6891  1.1  christos 
   6892  1.1  christos 	result = add32(rbtdb, rbtnode, rbtversion, newheader, DNS_DBADD_FORCE,
   6893  1.3  christos 		       false, NULL, 0);
   6894  1.1  christos 
   6895  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   6896  1.1  christos 		    isc_rwlocktype_write);
   6897  1.1  christos 
   6898  1.1  christos 	/*
   6899  1.1  christos 	 * Update the zone's secure status.  If version is non-NULL
   6900  1.1  christos 	 * this is deferred until closeversion() is called.
   6901  1.1  christos 	 */
   6902  1.1  christos 	if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
   6903  1.1  christos 		iszonesecure(db, rbtdb->current_version, rbtdb->origin_node);
   6904  1.1  christos 
   6905  1.1  christos 	return (result);
   6906  1.1  christos }
   6907  1.1  christos 
   6908  1.1  christos /*
   6909  1.1  christos  * load a non-NSEC3 node in the main tree and optionally to the auxiliary NSEC
   6910  1.1  christos  */
   6911  1.1  christos static isc_result_t
   6912  1.1  christos loadnode(dns_rbtdb_t *rbtdb, const dns_name_t *name, dns_rbtnode_t **nodep,
   6913  1.3  christos 	 bool hasnsec)
   6914  1.1  christos {
   6915  1.1  christos 	isc_result_t noderesult, nsecresult, tmpresult;
   6916  1.1  christos 	dns_rbtnode_t *nsecnode = NULL, *node = NULL;
   6917  1.1  christos 
   6918  1.1  christos 	noderesult = dns_rbt_addnode(rbtdb->tree, name, &node);
   6919  1.1  christos 	if (!hasnsec)
   6920  1.1  christos 		goto done;
   6921  1.1  christos 	if (noderesult == ISC_R_EXISTS) {
   6922  1.1  christos 		/*
   6923  1.1  christos 		 * Add a node to the auxiliary NSEC tree for an old node
   6924  1.1  christos 		 * just now getting an NSEC record.
   6925  1.1  christos 		 */
   6926  1.1  christos 		if (node->nsec == DNS_RBT_NSEC_HAS_NSEC)
   6927  1.1  christos 			goto done;
   6928  1.1  christos 	} else if (noderesult != ISC_R_SUCCESS)
   6929  1.1  christos 		goto done;
   6930  1.1  christos 
   6931  1.1  christos 	/*
   6932  1.1  christos 	 * Build the auxiliary tree for NSECs as we go.
   6933  1.1  christos 	 * This tree speeds searches for closest NSECs that would otherwise
   6934  1.1  christos 	 * need to examine many irrelevant nodes in large TLDs.
   6935  1.1  christos 	 *
   6936  1.1  christos 	 * Add nodes to the auxiliary tree after corresponding nodes have
   6937  1.1  christos 	 * been added to the main tree.
   6938  1.1  christos 	 */
   6939  1.1  christos 	nsecresult = dns_rbt_addnode(rbtdb->nsec, name, &nsecnode);
   6940  1.1  christos 	if (nsecresult == ISC_R_SUCCESS) {
   6941  1.1  christos 		nsecnode->nsec = DNS_RBT_NSEC_NSEC;
   6942  1.1  christos 		node->nsec = DNS_RBT_NSEC_HAS_NSEC;
   6943  1.1  christos 		goto done;
   6944  1.1  christos 	}
   6945  1.1  christos 
   6946  1.1  christos 	if (nsecresult == ISC_R_EXISTS) {
   6947  1.1  christos #if 1 /* 0 */
   6948  1.1  christos 		isc_log_write(dns_lctx,
   6949  1.1  christos 			      DNS_LOGCATEGORY_DATABASE,
   6950  1.1  christos 			      DNS_LOGMODULE_CACHE,
   6951  1.1  christos 			      ISC_LOG_WARNING,
   6952  1.1  christos 			      "addnode: NSEC node already exists");
   6953  1.1  christos #endif
   6954  1.1  christos 		node->nsec = DNS_RBT_NSEC_HAS_NSEC;
   6955  1.1  christos 		goto done;
   6956  1.1  christos 	}
   6957  1.1  christos 
   6958  1.1  christos 	if (noderesult == ISC_R_SUCCESS) {
   6959  1.1  christos 
   6960  1.1  christos 		/*
   6961  1.1  christos 		 * Remove the node we just added above.
   6962  1.1  christos 		 */
   6963  1.3  christos 		tmpresult = dns_rbt_deletenode(rbtdb->tree, node, false);
   6964  1.1  christos 		if (tmpresult != ISC_R_SUCCESS) {
   6965  1.1  christos 			isc_log_write(dns_lctx,
   6966  1.1  christos 				      DNS_LOGCATEGORY_DATABASE,
   6967  1.1  christos 				      DNS_LOGMODULE_CACHE,
   6968  1.1  christos 				      ISC_LOG_WARNING,
   6969  1.1  christos 				      "loading_addrdataset: "
   6970  1.1  christos 				      "dns_rbt_deletenode: %s after "
   6971  1.1  christos 				      "dns_rbt_addnode(NSEC): %s",
   6972  1.1  christos 				      isc_result_totext(tmpresult),
   6973  1.1  christos 				      isc_result_totext(noderesult));
   6974  1.1  christos 		}
   6975  1.1  christos 	}
   6976  1.1  christos 
   6977  1.1  christos 	/*
   6978  1.1  christos 	 * Set the error condition to be returned.
   6979  1.1  christos 	 */
   6980  1.1  christos 	noderesult = nsecresult;
   6981  1.1  christos 
   6982  1.1  christos  done:
   6983  1.1  christos 	if (noderesult == ISC_R_SUCCESS || noderesult == ISC_R_EXISTS)
   6984  1.1  christos 		*nodep = node;
   6985  1.1  christos 
   6986  1.1  christos 	return (noderesult);
   6987  1.1  christos }
   6988  1.1  christos 
   6989  1.1  christos static isc_result_t
   6990  1.1  christos loading_addrdataset(void *arg, const dns_name_t *name,
   6991  1.1  christos 		    dns_rdataset_t *rdataset)
   6992  1.1  christos {
   6993  1.1  christos 	rbtdb_load_t *loadctx = arg;
   6994  1.1  christos 	dns_rbtdb_t *rbtdb = loadctx->rbtdb;
   6995  1.1  christos 	dns_rbtnode_t *node;
   6996  1.1  christos 	isc_result_t result;
   6997  1.1  christos 	isc_region_t region;
   6998  1.1  christos 	rdatasetheader_t *newheader;
   6999  1.1  christos 
   7000  1.1  christos 	REQUIRE(rdataset->rdclass == rbtdb->common.rdclass);
   7001  1.1  christos 
   7002  1.1  christos 	/*
   7003  1.1  christos 	 * This routine does no node locking.  See comments in
   7004  1.1  christos 	 * 'load' below for more information on loading and
   7005  1.1  christos 	 * locking.
   7006  1.1  christos 	 */
   7007  1.1  christos 
   7008  1.1  christos 	/*
   7009  1.1  christos 	 * SOA records are only allowed at top of zone.
   7010  1.1  christos 	 */
   7011  1.1  christos 	if (rdataset->type == dns_rdatatype_soa &&
   7012  1.1  christos 	    !IS_CACHE(rbtdb) && !dns_name_equal(name, &rbtdb->common.origin))
   7013  1.1  christos 		return (DNS_R_NOTZONETOP);
   7014  1.1  christos 
   7015  1.1  christos 	if (rdataset->type != dns_rdatatype_nsec3 &&
   7016  1.1  christos 	    rdataset->covers != dns_rdatatype_nsec3)
   7017  1.1  christos 		add_empty_wildcards(rbtdb, name);
   7018  1.1  christos 
   7019  1.1  christos 	if (dns_name_iswildcard(name)) {
   7020  1.1  christos 		/*
   7021  1.1  christos 		 * NS record owners cannot legally be wild cards.
   7022  1.1  christos 		 */
   7023  1.1  christos 		if (rdataset->type == dns_rdatatype_ns)
   7024  1.1  christos 			return (DNS_R_INVALIDNS);
   7025  1.1  christos 		/*
   7026  1.1  christos 		 * NSEC3 record owners cannot legally be wild cards.
   7027  1.1  christos 		 */
   7028  1.1  christos 		if (rdataset->type == dns_rdatatype_nsec3)
   7029  1.1  christos 			return (DNS_R_INVALIDNSEC3);
   7030  1.1  christos 		result = add_wildcard_magic(rbtdb, name);
   7031  1.1  christos 		if (result != ISC_R_SUCCESS)
   7032  1.1  christos 			return (result);
   7033  1.1  christos 	}
   7034  1.1  christos 
   7035  1.1  christos 	node = NULL;
   7036  1.1  christos 	if (rdataset->type == dns_rdatatype_nsec3 ||
   7037  1.1  christos 	    rdataset->covers == dns_rdatatype_nsec3) {
   7038  1.1  christos 		result = dns_rbt_addnode(rbtdb->nsec3, name, &node);
   7039  1.1  christos 		if (result == ISC_R_SUCCESS)
   7040  1.1  christos 			node->nsec = DNS_RBT_NSEC_NSEC3;
   7041  1.1  christos 	} else if (rdataset->type == dns_rdatatype_nsec) {
   7042  1.3  christos 		result = loadnode(rbtdb, name, &node, true);
   7043  1.1  christos 	} else {
   7044  1.3  christos 		result = loadnode(rbtdb, name, &node, false);
   7045  1.1  christos 	}
   7046  1.1  christos 	if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
   7047  1.1  christos 		return (result);
   7048  1.1  christos 	if (result == ISC_R_SUCCESS) {
   7049  1.1  christos 		dns_name_t foundname;
   7050  1.1  christos 		dns_name_init(&foundname, NULL);
   7051  1.1  christos 		dns_rbt_namefromnode(node, &foundname);
   7052  1.1  christos 		node->locknum = node->hashval % rbtdb->node_lock_count;
   7053  1.1  christos 	}
   7054  1.1  christos 
   7055  1.1  christos 	result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
   7056  1.1  christos 					    &region,
   7057  1.1  christos 					    sizeof(rdatasetheader_t));
   7058  1.1  christos 	if (result != ISC_R_SUCCESS)
   7059  1.1  christos 		return (result);
   7060  1.1  christos 	newheader = (rdatasetheader_t *)region.base;
   7061  1.1  christos 	init_rdataset(rbtdb, newheader);
   7062  1.1  christos 	set_ttl(rbtdb, newheader,
   7063  1.1  christos 		rdataset->ttl + loadctx->now); /* XXX overflow check */
   7064  1.1  christos 	newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
   7065  1.1  christos 						rdataset->covers);
   7066  1.1  christos 	newheader->attributes = 0;
   7067  1.1  christos 	newheader->trust = rdataset->trust;
   7068  1.1  christos 	newheader->serial = 1;
   7069  1.1  christos 	newheader->noqname = NULL;
   7070  1.1  christos 	newheader->closest = NULL;
   7071  1.1  christos 	newheader->count = init_count++;
   7072  1.1  christos 	newheader->last_used = 0;
   7073  1.1  christos 	newheader->node = node;
   7074  1.1  christos 	setownercase(newheader, name);
   7075  1.1  christos 
   7076  1.1  christos 	if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
   7077  1.1  christos 		newheader->attributes |= RDATASET_ATTR_RESIGN;
   7078  1.1  christos 		newheader->resign = (isc_stdtime_t)
   7079  1.1  christos 			(dns_time64_from32(rdataset->resign) >> 1);
   7080  1.1  christos 		newheader->resign_lsb = rdataset->resign & 0x1;
   7081  1.1  christos 	} else {
   7082  1.1  christos 		newheader->resign = 0;
   7083  1.1  christos 		newheader->resign_lsb = 0;
   7084  1.1  christos 	}
   7085  1.1  christos 
   7086  1.1  christos 	result = add32(rbtdb, node, rbtdb->current_version, newheader,
   7087  1.3  christos 		       DNS_DBADD_MERGE, true, NULL, 0);
   7088  1.1  christos 	if (result == ISC_R_SUCCESS &&
   7089  1.1  christos 	    delegating_type(rbtdb, node, rdataset->type))
   7090  1.1  christos 		node->find_callback = 1;
   7091  1.1  christos 	else if (result == DNS_R_UNCHANGED)
   7092  1.1  christos 		result = ISC_R_SUCCESS;
   7093  1.1  christos 
   7094  1.1  christos 	return (result);
   7095  1.1  christos }
   7096  1.1  christos 
   7097  1.1  christos static isc_result_t
   7098  1.1  christos rbt_datafixer(dns_rbtnode_t *rbtnode, void *base, size_t filesize,
   7099  1.3  christos 	      void *arg, uint64_t *crc)
   7100  1.1  christos {
   7101  1.1  christos 	isc_result_t result;
   7102  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *) arg;
   7103  1.1  christos 	rdatasetheader_t *header;
   7104  1.1  christos 	unsigned char *limit = ((unsigned char *) base) + filesize;
   7105  1.1  christos 	unsigned char *p;
   7106  1.1  christos 	size_t size;
   7107  1.1  christos 	unsigned int count;
   7108  1.1  christos 
   7109  1.1  christos 	REQUIRE(rbtnode != NULL);
   7110  1.1  christos 
   7111  1.1  christos 	for (header = rbtnode->data; header != NULL; header = header->next) {
   7112  1.1  christos 		p = (unsigned char *) header;
   7113  1.1  christos 
   7114  1.1  christos 		size = dns_rdataslab_size(p, sizeof(*header));
   7115  1.1  christos 		count = dns_rdataslab_count(p, sizeof(*header));;
   7116  1.1  christos 		rbtdb->current_version->records += count;
   7117  1.1  christos 		rbtdb->current_version->bytes += size;
   7118  1.1  christos 		isc_crc64_update(crc, p, size);
   7119  1.1  christos #ifdef DEBUG
   7120  1.1  christos 		hexdump("hashing header", p, sizeof(rdatasetheader_t));
   7121  1.1  christos 		hexdump("hashing slab", p + sizeof(rdatasetheader_t),
   7122  1.1  christos 			size - sizeof(rdatasetheader_t));
   7123  1.1  christos #endif
   7124  1.1  christos 		header->serial = 1;
   7125  1.1  christos 		header->is_mmapped = 1;
   7126  1.1  christos 		header->node = rbtnode;
   7127  1.1  christos 		header->node_is_relative = 0;
   7128  1.1  christos 
   7129  1.1  christos 		if (rbtdb != NULL && RESIGN(header) &&
   7130  1.1  christos 		    (header->resign != 0 || header->resign_lsb != 0))
   7131  1.1  christos 		{
   7132  1.1  christos 			int idx = header->node->locknum;
   7133  1.1  christos 			result = isc_heap_insert(rbtdb->heaps[idx], header);
   7134  1.1  christos 			if (result != ISC_R_SUCCESS)
   7135  1.1  christos 				return (result);
   7136  1.1  christos 		}
   7137  1.1  christos 
   7138  1.1  christos 		if (header->next != NULL) {
   7139  1.1  christos 			size_t cooked = dns_rbt_serialize_align(size);
   7140  1.1  christos 			if ((uintptr_t)header->next !=
   7141  1.1  christos 				    (p - (unsigned char *)base) + cooked)
   7142  1.1  christos 				return (ISC_R_INVALIDFILE);
   7143  1.1  christos 			header->next = (rdatasetheader_t *)(p + cooked);
   7144  1.1  christos 			header->next_is_relative = 0;
   7145  1.1  christos 			if ((header->next < (rdatasetheader_t *) base) ||
   7146  1.1  christos 			    (header->next > (rdatasetheader_t *) limit))
   7147  1.1  christos 				return (ISC_R_INVALIDFILE);
   7148  1.1  christos 		}
   7149  1.1  christos 	}
   7150  1.1  christos 
   7151  1.1  christos 	return (ISC_R_SUCCESS);
   7152  1.1  christos }
   7153  1.1  christos 
   7154  1.1  christos /*
   7155  1.1  christos  * Load the RBT database from the image in 'f'
   7156  1.1  christos  */
   7157  1.1  christos static isc_result_t
   7158  1.1  christos deserialize32(void *arg, FILE *f, off_t offset) {
   7159  1.1  christos 	isc_result_t result;
   7160  1.1  christos 	rbtdb_load_t *loadctx = arg;
   7161  1.1  christos 	dns_rbtdb_t *rbtdb = loadctx->rbtdb;
   7162  1.1  christos 	rbtdb_file_header_t *header;
   7163  1.1  christos 	int fd;
   7164  1.1  christos 	off_t filesize = 0;
   7165  1.1  christos 	char *base;
   7166  1.1  christos 	dns_rbt_t *tree = NULL, *nsec = NULL, *nsec3 = NULL;
   7167  1.1  christos 	int protect, flags;
   7168  1.1  christos 	dns_rbtnode_t *origin_node = NULL;
   7169  1.1  christos 
   7170  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7171  1.1  christos 
   7172  1.1  christos 	/*
   7173  1.1  christos 	 * TODO CKB: since this is read-write (had to be to add nodes later)
   7174  1.1  christos 	 * we will need to lock the file or the nodes in it before modifying
   7175  1.1  christos 	 * the nodes in the file.
   7176  1.1  christos 	 */
   7177  1.1  christos 
   7178  1.1  christos 	/* Map in the whole file in one go */
   7179  1.1  christos 	fd = fileno(f);
   7180  1.1  christos 	isc_file_getsizefd(fd, &filesize);
   7181  1.1  christos 	protect = PROT_READ|PROT_WRITE;
   7182  1.1  christos 	flags = MAP_PRIVATE;
   7183  1.1  christos #ifdef MAP_FILE
   7184  1.1  christos 	flags |= MAP_FILE;
   7185  1.1  christos #endif
   7186  1.1  christos 
   7187  1.1  christos 	base = isc_file_mmap(NULL, filesize, protect, flags, fd, 0);
   7188  1.1  christos 	if (base == NULL || base == MAP_FAILED) {
   7189  1.1  christos 		return (ISC_R_FAILURE);
   7190  1.1  christos 	}
   7191  1.1  christos 
   7192  1.1  christos 	header = (rbtdb_file_header_t *)(base + offset);
   7193  1.1  christos 	if (!match_header_version(header)) {
   7194  1.1  christos 		result = ISC_R_INVALIDFILE;
   7195  1.1  christos 		goto cleanup;
   7196  1.1  christos 	}
   7197  1.1  christos 
   7198  1.1  christos 	if (header->tree != 0) {
   7199  1.1  christos 		result = dns_rbt_deserialize_tree(base, filesize,
   7200  1.1  christos 						  (off_t) header->tree,
   7201  1.1  christos 						  rbtdb->common.mctx,
   7202  1.1  christos 						  delete_callback, rbtdb,
   7203  1.1  christos 						  rbt_datafixer, rbtdb,
   7204  1.1  christos 						  NULL, &tree);
   7205  1.1  christos 		if (result != ISC_R_SUCCESS)
   7206  1.1  christos 			goto cleanup;
   7207  1.1  christos 
   7208  1.1  christos 		result = dns_rbt_findnode(tree, &rbtdb->common.origin, NULL,
   7209  1.1  christos 					  &origin_node, NULL,
   7210  1.1  christos 					  DNS_RBTFIND_EMPTYDATA, NULL, NULL);
   7211  1.1  christos 		if (result != ISC_R_SUCCESS)
   7212  1.1  christos 			goto cleanup;
   7213  1.1  christos 	}
   7214  1.1  christos 
   7215  1.1  christos 	if (header->nsec != 0) {
   7216  1.1  christos 		result = dns_rbt_deserialize_tree(base, filesize,
   7217  1.1  christos 						  (off_t) header->nsec,
   7218  1.1  christos 						  rbtdb->common.mctx,
   7219  1.1  christos 						  delete_callback, rbtdb,
   7220  1.1  christos 						  rbt_datafixer, rbtdb,
   7221  1.1  christos 						  NULL, &nsec);
   7222  1.1  christos 		if (result != ISC_R_SUCCESS)
   7223  1.1  christos 			goto cleanup;
   7224  1.1  christos 	}
   7225  1.1  christos 
   7226  1.1  christos 	if (header->nsec3 != 0) {
   7227  1.1  christos 		result = dns_rbt_deserialize_tree(base, filesize,
   7228  1.1  christos 						  (off_t) header->nsec3,
   7229  1.1  christos 						  rbtdb->common.mctx,
   7230  1.1  christos 						  delete_callback, rbtdb,
   7231  1.1  christos 						  rbt_datafixer, rbtdb,
   7232  1.1  christos 						  NULL, &nsec3);
   7233  1.1  christos 		if (result != ISC_R_SUCCESS)
   7234  1.1  christos 			goto cleanup;
   7235  1.1  christos 	}
   7236  1.1  christos 
   7237  1.1  christos 	/*
   7238  1.1  christos 	 * We have a successfully loaded all the rbt trees now update
   7239  1.1  christos 	 * rbtdb to use them.
   7240  1.1  christos 	 */
   7241  1.1  christos 
   7242  1.1  christos 	rbtdb->mmap_location = base;
   7243  1.1  christos 	rbtdb->mmap_size = (size_t) filesize;
   7244  1.1  christos 
   7245  1.1  christos 	if (tree != NULL) {
   7246  1.1  christos 		dns_rbt_destroy(&rbtdb->tree);
   7247  1.1  christos 		rbtdb->tree = tree;
   7248  1.1  christos 		rbtdb->origin_node = origin_node;
   7249  1.1  christos 	}
   7250  1.1  christos 
   7251  1.1  christos 	if (nsec != NULL) {
   7252  1.1  christos 		dns_rbt_destroy(&rbtdb->nsec);
   7253  1.1  christos 		rbtdb->nsec = nsec;
   7254  1.1  christos 	}
   7255  1.1  christos 
   7256  1.1  christos 	if (nsec3 != NULL) {
   7257  1.1  christos 		dns_rbt_destroy(&rbtdb->nsec3);
   7258  1.1  christos 		rbtdb->nsec3 = nsec3;
   7259  1.1  christos 	}
   7260  1.1  christos 
   7261  1.1  christos 	return (ISC_R_SUCCESS);
   7262  1.1  christos 
   7263  1.1  christos  cleanup:
   7264  1.1  christos 	if (tree != NULL)
   7265  1.1  christos 		dns_rbt_destroy(&tree);
   7266  1.1  christos 	if (nsec != NULL)
   7267  1.1  christos 		dns_rbt_destroy(&nsec);
   7268  1.1  christos 	if (nsec3 != NULL)
   7269  1.1  christos 		dns_rbt_destroy(&nsec3);
   7270  1.1  christos 	isc_file_munmap(base, (size_t) filesize);
   7271  1.1  christos 	return (result);
   7272  1.1  christos }
   7273  1.1  christos 
   7274  1.1  christos static isc_result_t
   7275  1.1  christos beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
   7276  1.1  christos 	rbtdb_load_t *loadctx;
   7277  1.1  christos 	dns_rbtdb_t *rbtdb;
   7278  1.1  christos 	rbtdb = (dns_rbtdb_t *)db;
   7279  1.1  christos 
   7280  1.1  christos 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
   7281  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7282  1.1  christos 
   7283  1.1  christos 	loadctx = isc_mem_get(rbtdb->common.mctx, sizeof(*loadctx));
   7284  1.1  christos 	if (loadctx == NULL)
   7285  1.1  christos 		return (ISC_R_NOMEMORY);
   7286  1.1  christos 
   7287  1.1  christos 	loadctx->rbtdb = rbtdb;
   7288  1.1  christos 	if (IS_CACHE(rbtdb))
   7289  1.1  christos 		isc_stdtime_get(&loadctx->now);
   7290  1.1  christos 	else
   7291  1.1  christos 		loadctx->now = 0;
   7292  1.1  christos 
   7293  1.1  christos 	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
   7294  1.1  christos 
   7295  1.1  christos 	REQUIRE((rbtdb->attributes & (RBTDB_ATTR_LOADED|RBTDB_ATTR_LOADING))
   7296  1.1  christos 		== 0);
   7297  1.1  christos 	rbtdb->attributes |= RBTDB_ATTR_LOADING;
   7298  1.1  christos 
   7299  1.1  christos 	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
   7300  1.1  christos 
   7301  1.1  christos 	callbacks->add = loading_addrdataset;
   7302  1.1  christos 	callbacks->add_private = loadctx;
   7303  1.1  christos 	callbacks->deserialize = deserialize32;
   7304  1.1  christos 	callbacks->deserialize_private = loadctx;
   7305  1.1  christos 
   7306  1.1  christos 	return (ISC_R_SUCCESS);
   7307  1.1  christos }
   7308  1.1  christos 
   7309  1.1  christos static isc_result_t
   7310  1.1  christos endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
   7311  1.1  christos 	rbtdb_load_t *loadctx;
   7312  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7313  1.1  christos 
   7314  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7315  1.1  christos 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
   7316  1.1  christos 	loadctx = callbacks->add_private;
   7317  1.1  christos 	REQUIRE(loadctx != NULL);
   7318  1.1  christos 	REQUIRE(loadctx->rbtdb == rbtdb);
   7319  1.1  christos 
   7320  1.1  christos 	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
   7321  1.1  christos 
   7322  1.1  christos 	REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADING) != 0);
   7323  1.1  christos 	REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADED) == 0);
   7324  1.1  christos 
   7325  1.1  christos 	rbtdb->attributes &= ~RBTDB_ATTR_LOADING;
   7326  1.1  christos 	rbtdb->attributes |= RBTDB_ATTR_LOADED;
   7327  1.1  christos 
   7328  1.1  christos 	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
   7329  1.1  christos 
   7330  1.1  christos 	/*
   7331  1.1  christos 	 * If there's a KEY rdataset at the zone origin containing a
   7332  1.1  christos 	 * zone key, we consider the zone secure.
   7333  1.1  christos 	 */
   7334  1.1  christos 	if (! IS_CACHE(rbtdb) && rbtdb->origin_node != NULL)
   7335  1.1  christos 		iszonesecure(db, rbtdb->current_version, rbtdb->origin_node);
   7336  1.1  christos 
   7337  1.1  christos 	callbacks->add = NULL;
   7338  1.1  christos 	callbacks->add_private = NULL;
   7339  1.1  christos 	callbacks->deserialize = NULL;
   7340  1.1  christos 	callbacks->deserialize_private = NULL;
   7341  1.1  christos 
   7342  1.1  christos 	isc_mem_put(rbtdb->common.mctx, loadctx, sizeof(*loadctx));
   7343  1.1  christos 
   7344  1.1  christos 	return (ISC_R_SUCCESS);
   7345  1.1  christos }
   7346  1.1  christos 
   7347  1.1  christos /*
   7348  1.1  christos  * helper function to handle writing out the rdataset data pointed to
   7349  1.1  christos  * by the void *data pointer in the dns_rbtnode
   7350  1.1  christos  */
   7351  1.1  christos static isc_result_t
   7352  1.1  christos rbt_datawriter(FILE *rbtfile, unsigned char *data, void *arg,
   7353  1.3  christos 	       uint64_t *crc)
   7354  1.1  christos {
   7355  1.1  christos 	rbtdb_version_t *version = (rbtdb_version_t *) arg;
   7356  1.1  christos 	rbtdb_serial_t serial;
   7357  1.1  christos 	rdatasetheader_t newheader;
   7358  1.1  christos 	rdatasetheader_t *header = (rdatasetheader_t *) data, *next;
   7359  1.1  christos 	off_t where;
   7360  1.1  christos 	size_t cooked, size;
   7361  1.1  christos 	unsigned char *p;
   7362  1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   7363  1.1  christos 	char pad[sizeof(char *)];
   7364  1.1  christos 	uintptr_t off;
   7365  1.1  christos 
   7366  1.1  christos 	REQUIRE(rbtfile != NULL);
   7367  1.1  christos 	REQUIRE(data != NULL);
   7368  1.1  christos 	REQUIRE(version != NULL);
   7369  1.1  christos 
   7370  1.1  christos 	serial = version->serial;
   7371  1.1  christos 
   7372  1.1  christos 	for (; header != NULL; header = next) {
   7373  1.1  christos 		next = header->next;
   7374  1.1  christos 		do {
   7375  1.1  christos 			if (header->serial <= serial && !IGNORE(header)) {
   7376  1.1  christos 				if (NONEXISTENT(header))
   7377  1.1  christos 					header = NULL;
   7378  1.1  christos 				break;
   7379  1.1  christos 			} else
   7380  1.1  christos 				header = header->down;
   7381  1.1  christos 		} while (header != NULL);
   7382  1.1  christos 
   7383  1.1  christos 		if (header == NULL)
   7384  1.1  christos 			continue;
   7385  1.1  christos 
   7386  1.1  christos 		CHECK(isc_stdio_tell(rbtfile, &where));
   7387  1.1  christos 		size = dns_rdataslab_size((unsigned char *) header,
   7388  1.1  christos 					  sizeof(rdatasetheader_t));
   7389  1.1  christos 
   7390  1.1  christos 		p = (unsigned char *) header;
   7391  1.1  christos 		memmove(&newheader, p, sizeof(rdatasetheader_t));
   7392  1.1  christos 		newheader.down = NULL;
   7393  1.1  christos 		newheader.next = NULL;
   7394  1.1  christos 		off = where;
   7395  1.1  christos 		if ((off_t)off != where)
   7396  1.1  christos 			return (ISC_R_RANGE);
   7397  1.1  christos 		newheader.node = (dns_rbtnode_t *) off;
   7398  1.1  christos 		newheader.node_is_relative = 1;
   7399  1.1  christos 		newheader.serial = 1;
   7400  1.1  christos 
   7401  1.1  christos 		/*
   7402  1.1  christos 		 * Round size up to the next pointer sized offset so it
   7403  1.1  christos 		 * will be properly aligned when read back in.
   7404  1.1  christos 		 */
   7405  1.1  christos 		cooked = dns_rbt_serialize_align(size);
   7406  1.1  christos 		if (next != NULL) {
   7407  1.1  christos 			newheader.next = (rdatasetheader_t *) (off + cooked);
   7408  1.1  christos 			newheader.next_is_relative = 1;
   7409  1.1  christos 		}
   7410  1.1  christos 
   7411  1.1  christos #ifdef DEBUG
   7412  1.1  christos 		hexdump("writing header", (unsigned char *) &newheader,
   7413  1.1  christos 			sizeof(rdatasetheader_t));
   7414  1.1  christos 		hexdump("writing slab", p + sizeof(rdatasetheader_t),
   7415  1.1  christos 			size - sizeof(rdatasetheader_t));
   7416  1.1  christos #endif
   7417  1.1  christos 		isc_crc64_update(crc, (unsigned char *) &newheader,
   7418  1.1  christos 				 sizeof(rdatasetheader_t));
   7419  1.1  christos 		CHECK(isc_stdio_write(&newheader, sizeof(rdatasetheader_t), 1,
   7420  1.1  christos 				      rbtfile, NULL));
   7421  1.1  christos 
   7422  1.1  christos 		isc_crc64_update(crc, p + sizeof(rdatasetheader_t),
   7423  1.1  christos 				 size - sizeof(rdatasetheader_t));
   7424  1.1  christos 		CHECK(isc_stdio_write(p + sizeof(rdatasetheader_t),
   7425  1.1  christos 				      size - sizeof(rdatasetheader_t), 1,
   7426  1.1  christos 				      rbtfile, NULL));
   7427  1.1  christos 		/*
   7428  1.1  christos 		 * Pad to force alignment.
   7429  1.1  christos 		 */
   7430  1.1  christos 		if (size != (size_t) cooked) {
   7431  1.1  christos 			memset(pad, 0, sizeof(pad));
   7432  1.1  christos 			CHECK(isc_stdio_write(pad, cooked - size, 1,
   7433  1.1  christos 					      rbtfile, NULL));
   7434  1.1  christos 		}
   7435  1.1  christos 	}
   7436  1.1  christos 
   7437  1.1  christos  failure:
   7438  1.1  christos 	return (result);
   7439  1.1  christos }
   7440  1.1  christos 
   7441  1.1  christos /*
   7442  1.1  christos  * Write out a zeroed header as a placeholder.  Doing this ensures
   7443  1.1  christos  * that the file will not read while it is partially written, should
   7444  1.1  christos  * writing fail or be interrupted.
   7445  1.1  christos  */
   7446  1.1  christos static isc_result_t
   7447  1.1  christos rbtdb_zero_header(FILE *rbtfile) {
   7448  1.1  christos 	char buffer[RBTDB_HEADER_LENGTH];
   7449  1.1  christos 	isc_result_t result;
   7450  1.1  christos 
   7451  1.1  christos 	memset(buffer, 0, RBTDB_HEADER_LENGTH);
   7452  1.1  christos 	result = isc_stdio_write(buffer, 1, RBTDB_HEADER_LENGTH, rbtfile, NULL);
   7453  1.1  christos 	fflush(rbtfile);
   7454  1.1  christos 
   7455  1.1  christos 	return (result);
   7456  1.1  christos }
   7457  1.1  christos 
   7458  1.1  christos static isc_once_t once = ISC_ONCE_INIT;
   7459  1.1  christos 
   7460  1.1  christos static void
   7461  1.1  christos init_file_version(void) {
   7462  1.1  christos 	int n;
   7463  1.1  christos 
   7464  1.1  christos 	memset(FILE_VERSION, 0, sizeof(FILE_VERSION));
   7465  1.1  christos 	n = snprintf(FILE_VERSION, sizeof(FILE_VERSION),
   7466  1.1  christos 		 "RBTDB Image %s %s", dns_major, dns_mapapi);
   7467  1.1  christos 	INSIST(n > 0 && (unsigned int)n < sizeof(FILE_VERSION));
   7468  1.1  christos }
   7469  1.1  christos 
   7470  1.1  christos /*
   7471  1.1  christos  * Write the file header out, recording the locations of the three
   7472  1.1  christos  * RBT's used in the rbtdb: tree, nsec, and nsec3, and including NodeDump
   7473  1.1  christos  * version information and any information stored in the rbtdb object
   7474  1.1  christos  * itself that should be stored here.
   7475  1.1  christos  */
   7476  1.1  christos static isc_result_t
   7477  1.1  christos rbtdb_write_header(FILE *rbtfile, off_t tree_location, off_t nsec_location,
   7478  1.1  christos 		   off_t nsec3_location)
   7479  1.1  christos {
   7480  1.1  christos 	rbtdb_file_header_t header;
   7481  1.1  christos 	isc_result_t result;
   7482  1.1  christos 
   7483  1.1  christos 	RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS);
   7484  1.1  christos 
   7485  1.1  christos 	memset(&header, 0, sizeof(rbtdb_file_header_t));
   7486  1.1  christos 	memmove(header.version1, FILE_VERSION, sizeof(header.version1));
   7487  1.1  christos 	memmove(header.version2, FILE_VERSION, sizeof(header.version2));
   7488  1.3  christos 	header.ptrsize = (uint32_t) sizeof(void *);
   7489  1.1  christos 	header.bigendian = (1 == htonl(1)) ? 1 : 0;
   7490  1.3  christos 	header.tree = (uint64_t) tree_location;
   7491  1.3  christos 	header.nsec = (uint64_t) nsec_location;
   7492  1.3  christos 	header.nsec3 = (uint64_t) nsec3_location;
   7493  1.1  christos 	result = isc_stdio_write(&header, 1, sizeof(rbtdb_file_header_t),
   7494  1.1  christos 			      rbtfile, NULL);
   7495  1.1  christos 	fflush(rbtfile);
   7496  1.1  christos 
   7497  1.1  christos 	return (result);
   7498  1.1  christos }
   7499  1.1  christos 
   7500  1.3  christos static bool
   7501  1.1  christos match_header_version(rbtdb_file_header_t *header) {
   7502  1.1  christos 	RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS);
   7503  1.1  christos 
   7504  1.1  christos 	if (memcmp(header->version1, FILE_VERSION,
   7505  1.1  christos 		   sizeof(header->version1)) != 0 ||
   7506  1.1  christos 	    memcmp(header->version2, FILE_VERSION,
   7507  1.1  christos 		   sizeof(header->version1)) != 0)
   7508  1.1  christos 	{
   7509  1.3  christos 		return (false);
   7510  1.1  christos 	}
   7511  1.1  christos 
   7512  1.3  christos 	return (true);
   7513  1.1  christos }
   7514  1.1  christos 
   7515  1.1  christos static isc_result_t
   7516  1.1  christos serialize(dns_db_t *db, dns_dbversion_t *ver, FILE *rbtfile) {
   7517  1.1  christos 	rbtdb_version_t *version = (rbtdb_version_t *) ver;
   7518  1.1  christos 	dns_rbtdb_t *rbtdb;
   7519  1.1  christos 	isc_result_t result;
   7520  1.1  christos 	off_t tree_location, nsec_location, nsec3_location, header_location;
   7521  1.1  christos 
   7522  1.1  christos 	rbtdb = (dns_rbtdb_t *)db;
   7523  1.1  christos 
   7524  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7525  1.1  christos 	REQUIRE(rbtfile != NULL);
   7526  1.1  christos 
   7527  1.1  christos 	/* Ensure we're writing to a plain file */
   7528  1.1  christos 	CHECK(isc_file_isplainfilefd(fileno(rbtfile)));
   7529  1.1  christos 
   7530  1.1  christos 	/*
   7531  1.1  christos 	 * first, write out a zeroed header to store rbtdb information
   7532  1.1  christos 	 *
   7533  1.1  christos 	 * then for each of the three trees, store the current position
   7534  1.1  christos 	 * in the file and call dns_rbt_serialize_tree
   7535  1.1  christos 	 *
   7536  1.1  christos 	 * finally, write out the rbtdb header, storing the locations of the
   7537  1.1  christos 	 * rbtheaders
   7538  1.1  christos 	 *
   7539  1.1  christos 	 * NOTE: need to do something better with the return codes, &= will
   7540  1.1  christos 	 * not work.
   7541  1.1  christos 	 */
   7542  1.1  christos 	CHECK(isc_stdio_tell(rbtfile, &header_location));
   7543  1.1  christos 	CHECK(rbtdb_zero_header(rbtfile));
   7544  1.1  christos 	CHECK(dns_rbt_serialize_tree(rbtfile, rbtdb->tree, rbt_datawriter,
   7545  1.1  christos 				     version, &tree_location));
   7546  1.1  christos 	CHECK(dns_rbt_serialize_tree(rbtfile, rbtdb->nsec, rbt_datawriter,
   7547  1.1  christos 				     version, &nsec_location));
   7548  1.1  christos 	CHECK(dns_rbt_serialize_tree(rbtfile, rbtdb->nsec3, rbt_datawriter,
   7549  1.1  christos 				     version, &nsec3_location));
   7550  1.1  christos 
   7551  1.1  christos 	CHECK(isc_stdio_seek(rbtfile, header_location, SEEK_SET));
   7552  1.1  christos 	CHECK(rbtdb_write_header(rbtfile, tree_location, nsec_location,
   7553  1.1  christos 				 nsec3_location));
   7554  1.1  christos  failure:
   7555  1.1  christos 	return (result);
   7556  1.1  christos }
   7557  1.1  christos 
   7558  1.1  christos static isc_result_t
   7559  1.1  christos dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
   7560  1.1  christos      dns_masterformat_t masterformat)
   7561  1.1  christos {
   7562  1.1  christos 	dns_rbtdb_t *rbtdb;
   7563  1.1  christos 	rbtdb_version_t *rbtversion = version;
   7564  1.1  christos 
   7565  1.1  christos 	rbtdb = (dns_rbtdb_t *)db;
   7566  1.1  christos 
   7567  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7568  1.1  christos 	INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
   7569  1.1  christos 
   7570  1.3  christos 	return (dns_master_dump(rbtdb->common.mctx, db, version,
   7571  1.3  christos 				&dns_master_style_default,
   7572  1.3  christos 				filename, masterformat, NULL));
   7573  1.1  christos }
   7574  1.1  christos 
   7575  1.1  christos static void
   7576  1.1  christos delete_callback(void *data, void *arg) {
   7577  1.1  christos 	dns_rbtdb_t *rbtdb = arg;
   7578  1.1  christos 	rdatasetheader_t *current, *next;
   7579  1.1  christos 	unsigned int locknum;
   7580  1.1  christos 
   7581  1.1  christos 	current = data;
   7582  1.1  christos 	locknum = current->node->locknum;
   7583  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write);
   7584  1.1  christos 	while (current != NULL) {
   7585  1.1  christos 		next = current->next;
   7586  1.1  christos 		free_rdataset(rbtdb, rbtdb->common.mctx, current);
   7587  1.1  christos 		current = next;
   7588  1.1  christos 	}
   7589  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write);
   7590  1.1  christos }
   7591  1.1  christos 
   7592  1.3  christos static bool
   7593  1.1  christos issecure(dns_db_t *db) {
   7594  1.1  christos 	dns_rbtdb_t *rbtdb;
   7595  1.3  christos 	bool secure;
   7596  1.1  christos 
   7597  1.1  christos 	rbtdb = (dns_rbtdb_t *)db;
   7598  1.1  christos 
   7599  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7600  1.1  christos 
   7601  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7602  1.3  christos 	secure = (rbtdb->current_version->secure == dns_db_secure);
   7603  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7604  1.1  christos 
   7605  1.1  christos 	return (secure);
   7606  1.1  christos }
   7607  1.1  christos 
   7608  1.3  christos static bool
   7609  1.1  christos isdnssec(dns_db_t *db) {
   7610  1.1  christos 	dns_rbtdb_t *rbtdb;
   7611  1.3  christos 	bool dnssec;
   7612  1.1  christos 
   7613  1.1  christos 	rbtdb = (dns_rbtdb_t *)db;
   7614  1.1  christos 
   7615  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7616  1.1  christos 
   7617  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7618  1.3  christos 	dnssec = (rbtdb->current_version->secure != dns_db_insecure);
   7619  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7620  1.1  christos 
   7621  1.1  christos 	return (dnssec);
   7622  1.1  christos }
   7623  1.1  christos 
   7624  1.1  christos static unsigned int
   7625  1.1  christos nodecount(dns_db_t *db) {
   7626  1.1  christos 	dns_rbtdb_t *rbtdb;
   7627  1.1  christos 	unsigned int count;
   7628  1.1  christos 
   7629  1.1  christos 	rbtdb = (dns_rbtdb_t *)db;
   7630  1.1  christos 
   7631  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7632  1.1  christos 
   7633  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7634  1.1  christos 	count = dns_rbt_nodecount(rbtdb->tree);
   7635  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7636  1.1  christos 
   7637  1.1  christos 	return (count);
   7638  1.1  christos }
   7639  1.1  christos 
   7640  1.1  christos static size_t
   7641  1.1  christos hashsize(dns_db_t *db) {
   7642  1.1  christos 	dns_rbtdb_t *rbtdb;
   7643  1.1  christos 	size_t size;
   7644  1.1  christos 
   7645  1.1  christos 	rbtdb = (dns_rbtdb_t *)db;
   7646  1.1  christos 
   7647  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7648  1.1  christos 
   7649  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7650  1.1  christos 	size = dns_rbt_hashsize(rbtdb->tree);
   7651  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7652  1.1  christos 
   7653  1.1  christos 	return (size);
   7654  1.1  christos }
   7655  1.1  christos 
   7656  1.1  christos static void
   7657  1.1  christos settask(dns_db_t *db, isc_task_t *task) {
   7658  1.1  christos 	dns_rbtdb_t *rbtdb;
   7659  1.1  christos 
   7660  1.1  christos 	rbtdb = (dns_rbtdb_t *)db;
   7661  1.1  christos 
   7662  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7663  1.1  christos 
   7664  1.1  christos 	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
   7665  1.1  christos 	if (rbtdb->task != NULL)
   7666  1.1  christos 		isc_task_detach(&rbtdb->task);
   7667  1.1  christos 	if (task != NULL)
   7668  1.1  christos 		isc_task_attach(task, &rbtdb->task);
   7669  1.1  christos 	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
   7670  1.1  christos }
   7671  1.1  christos 
   7672  1.3  christos static bool
   7673  1.1  christos ispersistent(dns_db_t *db) {
   7674  1.1  christos 	UNUSED(db);
   7675  1.3  christos 	return (false);
   7676  1.1  christos }
   7677  1.1  christos 
   7678  1.1  christos static isc_result_t
   7679  1.1  christos getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
   7680  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7681  1.1  christos 	dns_rbtnode_t *onode;
   7682  1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   7683  1.1  christos 
   7684  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7685  1.1  christos 	REQUIRE(nodep != NULL && *nodep == NULL);
   7686  1.1  christos 
   7687  1.1  christos 	/* Note that the access to origin_node doesn't require a DB lock */
   7688  1.1  christos 	onode = (dns_rbtnode_t *)rbtdb->origin_node;
   7689  1.1  christos 	if (onode != NULL) {
   7690  1.1  christos 		new_reference(rbtdb, onode);
   7691  1.1  christos 
   7692  1.1  christos 		*nodep = rbtdb->origin_node;
   7693  1.1  christos 	} else {
   7694  1.1  christos 		INSIST(IS_CACHE(rbtdb));
   7695  1.1  christos 		result = ISC_R_NOTFOUND;
   7696  1.1  christos 	}
   7697  1.1  christos 
   7698  1.1  christos 	return (result);
   7699  1.1  christos }
   7700  1.1  christos 
   7701  1.1  christos static isc_result_t
   7702  1.1  christos getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash,
   7703  1.3  christos 		   uint8_t *flags, uint16_t *iterations,
   7704  1.1  christos 		   unsigned char *salt, size_t *salt_length)
   7705  1.1  christos {
   7706  1.1  christos 	dns_rbtdb_t *rbtdb;
   7707  1.1  christos 	isc_result_t result = ISC_R_NOTFOUND;
   7708  1.1  christos 	rbtdb_version_t *rbtversion = version;
   7709  1.1  christos 
   7710  1.1  christos 	rbtdb = (dns_rbtdb_t *)db;
   7711  1.1  christos 
   7712  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7713  1.1  christos 	INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
   7714  1.1  christos 
   7715  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7716  1.1  christos 
   7717  1.1  christos 	if (rbtversion == NULL)
   7718  1.1  christos 		rbtversion = rbtdb->current_version;
   7719  1.1  christos 
   7720  1.1  christos 	if (rbtversion->havensec3) {
   7721  1.1  christos 		if (hash != NULL)
   7722  1.1  christos 			*hash = rbtversion->hash;
   7723  1.1  christos 		if (salt != NULL && salt_length != NULL) {
   7724  1.1  christos 			REQUIRE(*salt_length >= rbtversion->salt_length);
   7725  1.1  christos 			memmove(salt, rbtversion->salt,
   7726  1.1  christos 				rbtversion->salt_length);
   7727  1.1  christos 		}
   7728  1.1  christos 		if (salt_length != NULL)
   7729  1.1  christos 			*salt_length = rbtversion->salt_length;
   7730  1.1  christos 		if (iterations != NULL)
   7731  1.1  christos 			*iterations = rbtversion->iterations;
   7732  1.1  christos 		if (flags != NULL)
   7733  1.1  christos 			*flags = rbtversion->flags;
   7734  1.1  christos 		result = ISC_R_SUCCESS;
   7735  1.1  christos 	}
   7736  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7737  1.1  christos 
   7738  1.1  christos 	return (result);
   7739  1.1  christos }
   7740  1.1  christos 
   7741  1.1  christos static isc_result_t
   7742  1.3  christos getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
   7743  1.3  christos 	uint64_t *bytes)
   7744  1.1  christos {
   7745  1.1  christos 	dns_rbtdb_t *rbtdb;
   7746  1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   7747  1.1  christos 	rbtdb_version_t *rbtversion = version;
   7748  1.1  christos 
   7749  1.1  christos 	rbtdb = (dns_rbtdb_t *)db;
   7750  1.1  christos 
   7751  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7752  1.1  christos 	INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
   7753  1.1  christos 
   7754  1.1  christos 	if (rbtversion == NULL)
   7755  1.1  christos 		rbtversion = rbtdb->current_version;
   7756  1.1  christos 
   7757  1.1  christos 	RWLOCK(&rbtversion->rwlock, isc_rwlocktype_read);
   7758  1.1  christos 	if (records != NULL)
   7759  1.1  christos 		*records = rbtversion->records;
   7760  1.1  christos 
   7761  1.1  christos 	if (bytes != NULL)
   7762  1.1  christos 		*bytes = rbtversion->bytes;
   7763  1.1  christos 	RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_read);
   7764  1.1  christos 
   7765  1.1  christos 	return (result);
   7766  1.1  christos }
   7767  1.1  christos 
   7768  1.1  christos static isc_result_t
   7769  1.1  christos setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) {
   7770  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7771  1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   7772  1.1  christos 	rdatasetheader_t *header, oldheader;
   7773  1.1  christos 
   7774  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7775  1.1  christos 	REQUIRE(!IS_CACHE(rbtdb));
   7776  1.1  christos 	REQUIRE(rdataset != NULL);
   7777  1.1  christos 
   7778  1.1  christos 	header = rdataset->private3;
   7779  1.1  christos 	header--;
   7780  1.1  christos 
   7781  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[header->node->locknum].lock,
   7782  1.1  christos 		  isc_rwlocktype_write);
   7783  1.1  christos 
   7784  1.1  christos 	oldheader = *header;
   7785  1.1  christos 	/*
   7786  1.1  christos 	 * Only break the heap invariant (by adjusting resign and resign_lsb)
   7787  1.1  christos 	 * if we are going to be restoring it by calling isc_heap_increased
   7788  1.1  christos 	 * or isc_heap_decreased.
   7789  1.1  christos 	 */
   7790  1.1  christos 	if (resign != 0) {
   7791  1.1  christos 		header->resign =
   7792  1.1  christos 			 (isc_stdtime_t)(dns_time64_from32(resign) >> 1);
   7793  1.1  christos 		header->resign_lsb = resign & 0x1;
   7794  1.1  christos 	}
   7795  1.1  christos 	if (header->heap_index != 0) {
   7796  1.1  christos 		INSIST(RESIGN(header));
   7797  1.1  christos 		if (resign == 0) {
   7798  1.1  christos 			isc_heap_delete(rbtdb->heaps[header->node->locknum],
   7799  1.1  christos 					header->heap_index);
   7800  1.1  christos 			header->heap_index = 0;
   7801  1.1  christos 		} else if (resign_sooner(header, &oldheader)) {
   7802  1.1  christos 			isc_heap_increased(rbtdb->heaps[header->node->locknum],
   7803  1.1  christos 					   header->heap_index);
   7804  1.1  christos 		} else if (resign_sooner(&oldheader, header)) {
   7805  1.1  christos 			isc_heap_decreased(rbtdb->heaps[header->node->locknum],
   7806  1.1  christos 					   header->heap_index);
   7807  1.1  christos 		}
   7808  1.1  christos 	} else if (resign != 0) {
   7809  1.1  christos 		header->attributes |= RDATASET_ATTR_RESIGN;
   7810  1.1  christos 		result = resign_insert(rbtdb, header->node->locknum, header);
   7811  1.1  christos 	}
   7812  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[header->node->locknum].lock,
   7813  1.1  christos 		    isc_rwlocktype_write);
   7814  1.1  christos 	return (result);
   7815  1.1  christos }
   7816  1.1  christos 
   7817  1.1  christos static isc_result_t
   7818  1.1  christos getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
   7819  1.1  christos 	       dns_name_t *foundname)
   7820  1.1  christos {
   7821  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7822  1.1  christos 	rdatasetheader_t *header = NULL, *this;
   7823  1.1  christos 	unsigned int i;
   7824  1.1  christos 	isc_result_t result = ISC_R_NOTFOUND;
   7825  1.1  christos 	unsigned int locknum;
   7826  1.1  christos 
   7827  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7828  1.1  christos 
   7829  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7830  1.1  christos 
   7831  1.1  christos 	for (i = 0; i < rbtdb->node_lock_count; i++) {
   7832  1.1  christos 		NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_read);
   7833  1.1  christos 		this = isc_heap_element(rbtdb->heaps[i], 1);
   7834  1.1  christos 		if (this == NULL) {
   7835  1.1  christos 			NODE_UNLOCK(&rbtdb->node_locks[i].lock,
   7836  1.1  christos 				    isc_rwlocktype_read);
   7837  1.1  christos 			continue;
   7838  1.1  christos 		}
   7839  1.1  christos 		if (header == NULL)
   7840  1.1  christos 			header = this;
   7841  1.1  christos 		else if (resign_sooner(this, header)) {
   7842  1.1  christos 			locknum = header->node->locknum;
   7843  1.1  christos 			NODE_UNLOCK(&rbtdb->node_locks[locknum].lock,
   7844  1.1  christos 				    isc_rwlocktype_read);
   7845  1.1  christos 			header = this;
   7846  1.1  christos 		} else
   7847  1.1  christos 			NODE_UNLOCK(&rbtdb->node_locks[i].lock,
   7848  1.1  christos 				    isc_rwlocktype_read);
   7849  1.1  christos 	}
   7850  1.1  christos 
   7851  1.1  christos 	if (header == NULL)
   7852  1.1  christos 		goto unlock;
   7853  1.1  christos 
   7854  1.1  christos 	bind_rdataset(rbtdb, header->node, header, 0, rdataset);
   7855  1.1  christos 
   7856  1.1  christos 	if (foundname != NULL)
   7857  1.1  christos 		dns_rbt_fullnamefromnode(header->node, foundname);
   7858  1.1  christos 
   7859  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[header->node->locknum].lock,
   7860  1.1  christos 		    isc_rwlocktype_read);
   7861  1.1  christos 
   7862  1.1  christos 	result = ISC_R_SUCCESS;
   7863  1.1  christos 
   7864  1.1  christos  unlock:
   7865  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7866  1.1  christos 
   7867  1.1  christos 	return (result);
   7868  1.1  christos }
   7869  1.1  christos 
   7870  1.1  christos static void
   7871  1.1  christos resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)
   7872  1.1  christos {
   7873  1.1  christos 	rbtdb_version_t *rbtversion = (rbtdb_version_t *)version;
   7874  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7875  1.1  christos 	dns_rbtnode_t *node;
   7876  1.1  christos 	rdatasetheader_t *header;
   7877  1.1  christos 
   7878  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7879  1.1  christos 	REQUIRE(rdataset != NULL);
   7880  1.1  christos 	REQUIRE(rdataset->methods == &rdataset_methods);
   7881  1.1  christos 	REQUIRE(rbtdb->future_version == rbtversion);
   7882  1.1  christos 	REQUIRE(rbtversion != NULL);
   7883  1.1  christos 	REQUIRE(rbtversion->writer);
   7884  1.1  christos 	REQUIRE(rbtversion->rbtdb == rbtdb);
   7885  1.1  christos 
   7886  1.1  christos 	node = rdataset->private2;
   7887  1.1  christos 	INSIST(node != NULL);
   7888  1.1  christos 	header = rdataset->private3;
   7889  1.1  christos 	INSIST(header != NULL);
   7890  1.1  christos 	header--;
   7891  1.1  christos 
   7892  1.1  christos 	if (header->heap_index == 0)
   7893  1.1  christos 		return;
   7894  1.1  christos 
   7895  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   7896  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[node->locknum].lock,
   7897  1.1  christos 		  isc_rwlocktype_write);
   7898  1.1  christos 	/*
   7899  1.1  christos 	 * Delete from heap and save to re-signed list so that it can
   7900  1.1  christos 	 * be restored if we backout of this change.
   7901  1.1  christos 	 */
   7902  1.1  christos 	resign_delete(rbtdb, rbtversion, header);
   7903  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[node->locknum].lock,
   7904  1.1  christos 		    isc_rwlocktype_write);
   7905  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   7906  1.1  christos }
   7907  1.1  christos 
   7908  1.1  christos static isc_result_t
   7909  1.1  christos setcachestats(dns_db_t *db, isc_stats_t *stats) {
   7910  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7911  1.1  christos 
   7912  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7913  1.1  christos 	REQUIRE(IS_CACHE(rbtdb)); /* current restriction */
   7914  1.1  christos 	REQUIRE(stats != NULL);
   7915  1.1  christos 
   7916  1.1  christos 	isc_stats_attach(stats, &rbtdb->cachestats);
   7917  1.1  christos 	return (ISC_R_SUCCESS);
   7918  1.1  christos }
   7919  1.1  christos 
   7920  1.1  christos static isc_result_t
   7921  1.1  christos setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
   7922  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7923  1.1  christos 
   7924  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7925  1.1  christos 	REQUIRE(!IS_CACHE(rbtdb) && !IS_STUB(rbtdb));
   7926  1.1  christos 	REQUIRE(stats != NULL);
   7927  1.1  christos 
   7928  1.1  christos 	isc_stats_attach(stats, &rbtdb->gluecachestats);
   7929  1.1  christos 	return (ISC_R_SUCCESS);
   7930  1.1  christos }
   7931  1.1  christos 
   7932  1.1  christos static dns_stats_t *
   7933  1.1  christos getrrsetstats(dns_db_t *db) {
   7934  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7935  1.1  christos 
   7936  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7937  1.1  christos 	REQUIRE(IS_CACHE(rbtdb)); /* current restriction */
   7938  1.1  christos 
   7939  1.1  christos 	return (rbtdb->rrsetstats);
   7940  1.1  christos }
   7941  1.1  christos 
   7942  1.1  christos static isc_result_t
   7943  1.1  christos nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) {
   7944  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7945  1.1  christos 	dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
   7946  1.1  christos 	isc_result_t result;
   7947  1.1  christos 
   7948  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7949  1.1  christos 	REQUIRE(node != NULL);
   7950  1.1  christos 	REQUIRE(name != NULL);
   7951  1.1  christos 
   7952  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7953  1.1  christos 	result = dns_rbt_fullnamefromnode(rbtnode, name);
   7954  1.1  christos 	RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   7955  1.1  christos 
   7956  1.1  christos 	return (result);
   7957  1.1  christos }
   7958  1.1  christos 
   7959  1.1  christos static isc_result_t
   7960  1.1  christos setservestalettl(dns_db_t *db, dns_ttl_t ttl) {
   7961  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7962  1.1  christos 
   7963  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7964  1.1  christos 	REQUIRE(IS_CACHE(rbtdb));
   7965  1.1  christos 
   7966  1.1  christos 	/* currently no bounds checking.  0 means disable. */
   7967  1.1  christos 	rbtdb->serve_stale_ttl = ttl;
   7968  1.1  christos 	return (ISC_R_SUCCESS);
   7969  1.1  christos }
   7970  1.1  christos 
   7971  1.1  christos static isc_result_t
   7972  1.1  christos getservestalettl(dns_db_t *db, dns_ttl_t *ttl) {
   7973  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
   7974  1.1  christos 
   7975  1.1  christos 	REQUIRE(VALID_RBTDB(rbtdb));
   7976  1.1  christos 	REQUIRE(IS_CACHE(rbtdb));
   7977  1.1  christos 
   7978  1.1  christos 	*ttl = rbtdb->serve_stale_ttl;
   7979  1.1  christos 	return (ISC_R_SUCCESS);
   7980  1.1  christos }
   7981  1.1  christos 
   7982  1.1  christos 
   7983  1.1  christos static dns_dbmethods_t zone_methods = {
   7984  1.1  christos 	attach,
   7985  1.1  christos 	detach,
   7986  1.1  christos 	beginload,
   7987  1.1  christos 	endload,
   7988  1.1  christos 	serialize,
   7989  1.1  christos 	dump,
   7990  1.1  christos 	currentversion,
   7991  1.1  christos 	newversion,
   7992  1.1  christos 	attachversion,
   7993  1.1  christos 	closeversion,
   7994  1.1  christos 	findnode,
   7995  1.1  christos 	zone_find,
   7996  1.1  christos 	zone_findzonecut,
   7997  1.1  christos 	attachnode,
   7998  1.1  christos 	detachnode,
   7999  1.1  christos 	expirenode,
   8000  1.1  christos 	printnode,
   8001  1.1  christos 	createiterator,
   8002  1.1  christos 	zone_findrdataset,
   8003  1.1  christos 	allrdatasets,
   8004  1.1  christos 	addrdataset,
   8005  1.1  christos 	subtractrdataset,
   8006  1.1  christos 	deleterdataset,
   8007  1.1  christos 	issecure,
   8008  1.1  christos 	nodecount,
   8009  1.1  christos 	ispersistent,
   8010  1.1  christos 	overmem,
   8011  1.1  christos 	settask,
   8012  1.1  christos 	getoriginnode,
   8013  1.1  christos 	NULL,			/* transfernode */
   8014  1.1  christos 	getnsec3parameters,
   8015  1.1  christos 	findnsec3node,
   8016  1.1  christos 	setsigningtime,
   8017  1.1  christos 	getsigningtime,
   8018  1.1  christos 	resigned,
   8019  1.1  christos 	isdnssec,
   8020  1.1  christos 	NULL,			/* getrrsetstats */
   8021  1.1  christos 	NULL,			/* rpz_attach */
   8022  1.1  christos 	NULL,			/* rpz_ready */
   8023  1.1  christos 	NULL,			/* findnodeext */
   8024  1.1  christos 	NULL,			/* findext */
   8025  1.1  christos 	NULL,			/* setcachestats */
   8026  1.1  christos 	hashsize,
   8027  1.1  christos 	nodefullname,
   8028  1.1  christos 	getsize,
   8029  1.1  christos 	NULL,			/* setservestalettl */
   8030  1.1  christos 	NULL,			/* getservestalettl */
   8031  1.1  christos 	setgluecachestats
   8032  1.1  christos };
   8033  1.1  christos 
   8034  1.1  christos static dns_dbmethods_t cache_methods = {
   8035  1.1  christos 	attach,
   8036  1.1  christos 	detach,
   8037  1.1  christos 	beginload,
   8038  1.1  christos 	endload,
   8039  1.1  christos 	NULL,			/* serialize */
   8040  1.1  christos 	dump,
   8041  1.1  christos 	currentversion,
   8042  1.1  christos 	newversion,
   8043  1.1  christos 	attachversion,
   8044  1.1  christos 	closeversion,
   8045  1.1  christos 	findnode,
   8046  1.1  christos 	cache_find,
   8047  1.1  christos 	cache_findzonecut,
   8048  1.1  christos 	attachnode,
   8049  1.1  christos 	detachnode,
   8050  1.1  christos 	expirenode,
   8051  1.1  christos 	printnode,
   8052  1.1  christos 	createiterator,
   8053  1.1  christos 	cache_findrdataset,
   8054  1.1  christos 	allrdatasets,
   8055  1.1  christos 	addrdataset,
   8056  1.1  christos 	subtractrdataset,
   8057  1.1  christos 	deleterdataset,
   8058  1.1  christos 	issecure,
   8059  1.1  christos 	nodecount,
   8060  1.1  christos 	ispersistent,
   8061  1.1  christos 	overmem,
   8062  1.1  christos 	settask,
   8063  1.1  christos 	getoriginnode,
   8064  1.1  christos 	NULL,			/* transfernode */
   8065  1.1  christos 	NULL,			/* getnsec3parameters */
   8066  1.1  christos 	NULL,			/* findnsec3node */
   8067  1.1  christos 	NULL,			/* setsigningtime */
   8068  1.1  christos 	NULL,			/* getsigningtime */
   8069  1.1  christos 	NULL,			/* resigned */
   8070  1.1  christos 	isdnssec,
   8071  1.1  christos 	getrrsetstats,
   8072  1.1  christos 	NULL,			/* rpz_attach */
   8073  1.1  christos 	NULL,			/* rpz_ready */
   8074  1.1  christos 	NULL,			/* findnodeext */
   8075  1.1  christos 	NULL,			/* findext */
   8076  1.1  christos 	setcachestats,
   8077  1.1  christos 	hashsize,
   8078  1.1  christos 	nodefullname,
   8079  1.1  christos 	NULL,			/* getsize */
   8080  1.1  christos 	setservestalettl,
   8081  1.1  christos 	getservestalettl,
   8082  1.1  christos 	NULL
   8083  1.1  christos };
   8084  1.1  christos 
   8085  1.1  christos isc_result_t
   8086  1.3  christos dns_rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
   8087  1.1  christos 		 dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
   8088  1.1  christos 		 void *driverarg, dns_db_t **dbp)
   8089  1.1  christos {
   8090  1.1  christos 	dns_rbtdb_t *rbtdb;
   8091  1.1  christos 	isc_result_t result;
   8092  1.1  christos 	int i;
   8093  1.1  christos 	dns_name_t name;
   8094  1.3  christos 	bool (*sooner)(void *, void *);
   8095  1.1  christos 	isc_mem_t *hmctx = mctx;
   8096  1.1  christos 
   8097  1.1  christos 	/* Keep the compiler happy. */
   8098  1.1  christos 	UNUSED(driverarg);
   8099  1.1  christos 
   8100  1.1  christos 	rbtdb = isc_mem_get(mctx, sizeof(*rbtdb));
   8101  1.1  christos 	if (rbtdb == NULL)
   8102  1.1  christos 		return (ISC_R_NOMEMORY);
   8103  1.1  christos 
   8104  1.1  christos 	/*
   8105  1.1  christos 	 * If argv[0] exists, it points to a memory context to use for heap
   8106  1.1  christos 	 */
   8107  1.1  christos 	if (argc != 0)
   8108  1.1  christos 		hmctx = (isc_mem_t *) argv[0];
   8109  1.1  christos 
   8110  1.1  christos 	memset(rbtdb, '\0', sizeof(*rbtdb));
   8111  1.1  christos 	dns_name_init(&rbtdb->common.origin, NULL);
   8112  1.1  christos 	rbtdb->common.attributes = 0;
   8113  1.1  christos 	if (type == dns_dbtype_cache) {
   8114  1.1  christos 		rbtdb->common.methods = &cache_methods;
   8115  1.1  christos 		rbtdb->common.attributes |= DNS_DBATTR_CACHE;
   8116  1.1  christos 	} else if (type == dns_dbtype_stub) {
   8117  1.1  christos 		rbtdb->common.methods = &zone_methods;
   8118  1.1  christos 		rbtdb->common.attributes |= DNS_DBATTR_STUB;
   8119  1.1  christos 	} else
   8120  1.1  christos 		rbtdb->common.methods = &zone_methods;
   8121  1.1  christos 	rbtdb->common.rdclass = rdclass;
   8122  1.1  christos 	rbtdb->common.mctx = NULL;
   8123  1.1  christos 
   8124  1.1  christos 	ISC_LIST_INIT(rbtdb->common.update_listeners);
   8125  1.1  christos 
   8126  1.1  christos 	result = RBTDB_INITLOCK(&rbtdb->lock);
   8127  1.1  christos 	if (result != ISC_R_SUCCESS)
   8128  1.1  christos 		goto cleanup_rbtdb;
   8129  1.1  christos 
   8130  1.1  christos 	result = isc_rwlock_init(&rbtdb->tree_lock, 0, 0);
   8131  1.1  christos 	if (result != ISC_R_SUCCESS)
   8132  1.1  christos 		goto cleanup_lock;
   8133  1.1  christos 
   8134  1.1  christos 	/*
   8135  1.1  christos 	 * Initialize node_lock_count in a generic way to support future
   8136  1.1  christos 	 * extension which allows the user to specify this value on creation.
   8137  1.1  christos 	 * Note that when specified for a cache DB it must be larger than 1
   8138  1.1  christos 	 * as commented with the definition of DEFAULT_CACHE_NODE_LOCK_COUNT.
   8139  1.1  christos 	 */
   8140  1.1  christos 	if (rbtdb->node_lock_count == 0) {
   8141  1.1  christos 		if (IS_CACHE(rbtdb))
   8142  1.1  christos 			rbtdb->node_lock_count = DEFAULT_CACHE_NODE_LOCK_COUNT;
   8143  1.1  christos 		else
   8144  1.1  christos 			rbtdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT;
   8145  1.1  christos 	} else if (rbtdb->node_lock_count < 2 && IS_CACHE(rbtdb)) {
   8146  1.1  christos 		result = ISC_R_RANGE;
   8147  1.1  christos 		goto cleanup_tree_lock;
   8148  1.1  christos 	}
   8149  1.1  christos 	INSIST(rbtdb->node_lock_count < (1 << DNS_RBT_LOCKLENGTH));
   8150  1.1  christos 	rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count *
   8151  1.1  christos 					sizeof(rbtdb_nodelock_t));
   8152  1.1  christos 	if (rbtdb->node_locks == NULL) {
   8153  1.1  christos 		result = ISC_R_NOMEMORY;
   8154  1.1  christos 		goto cleanup_tree_lock;
   8155  1.1  christos 	}
   8156  1.1  christos 
   8157  1.1  christos 	rbtdb->cachestats = NULL;
   8158  1.1  christos 	rbtdb->gluecachestats = NULL;
   8159  1.1  christos 
   8160  1.1  christos 	rbtdb->rrsetstats = NULL;
   8161  1.1  christos 	if (IS_CACHE(rbtdb)) {
   8162  1.1  christos 		result = dns_rdatasetstats_create(mctx, &rbtdb->rrsetstats);
   8163  1.1  christos 		if (result != ISC_R_SUCCESS)
   8164  1.1  christos 			goto cleanup_node_locks;
   8165  1.1  christos 		rbtdb->rdatasets = isc_mem_get(mctx, rbtdb->node_lock_count *
   8166  1.1  christos 					       sizeof(rdatasetheaderlist_t));
   8167  1.1  christos 		if (rbtdb->rdatasets == NULL) {
   8168  1.1  christos 			result = ISC_R_NOMEMORY;
   8169  1.1  christos 			goto cleanup_rrsetstats;
   8170  1.1  christos 		}
   8171  1.1  christos 		for (i = 0; i < (int)rbtdb->node_lock_count; i++)
   8172  1.1  christos 			ISC_LIST_INIT(rbtdb->rdatasets[i]);
   8173  1.1  christos 	} else
   8174  1.1  christos 		rbtdb->rdatasets = NULL;
   8175  1.1  christos 
   8176  1.1  christos 	/*
   8177  1.1  christos 	 * Create the heaps.
   8178  1.1  christos 	 */
   8179  1.1  christos 	rbtdb->heaps = isc_mem_get(hmctx, rbtdb->node_lock_count *
   8180  1.1  christos 				   sizeof(isc_heap_t *));
   8181  1.1  christos 	if (rbtdb->heaps == NULL) {
   8182  1.1  christos 		result = ISC_R_NOMEMORY;
   8183  1.1  christos 		goto cleanup_rdatasets;
   8184  1.1  christos 	}
   8185  1.1  christos 	for (i = 0; i < (int)rbtdb->node_lock_count; i++)
   8186  1.1  christos 		rbtdb->heaps[i] = NULL;
   8187  1.1  christos 	sooner = IS_CACHE(rbtdb) ? ttl_sooner : resign_sooner;
   8188  1.1  christos 	for (i = 0; i < (int)rbtdb->node_lock_count; i++) {
   8189  1.1  christos 		result = isc_heap_create(hmctx, sooner, set_index, 0,
   8190  1.1  christos 					 &rbtdb->heaps[i]);
   8191  1.1  christos 		if (result != ISC_R_SUCCESS)
   8192  1.1  christos 			goto cleanup_heaps;
   8193  1.1  christos 	}
   8194  1.1  christos 
   8195  1.1  christos 	/*
   8196  1.1  christos 	 * Create deadnode lists.
   8197  1.1  christos 	 */
   8198  1.1  christos 	rbtdb->deadnodes = isc_mem_get(mctx, rbtdb->node_lock_count *
   8199  1.1  christos 				       sizeof(rbtnodelist_t));
   8200  1.1  christos 	if (rbtdb->deadnodes == NULL) {
   8201  1.1  christos 		result = ISC_R_NOMEMORY;
   8202  1.1  christos 		goto cleanup_heaps;
   8203  1.1  christos 	}
   8204  1.1  christos 	for (i = 0; i < (int)rbtdb->node_lock_count; i++)
   8205  1.1  christos 		ISC_LIST_INIT(rbtdb->deadnodes[i]);
   8206  1.1  christos 
   8207  1.1  christos 	rbtdb->active = rbtdb->node_lock_count;
   8208  1.1  christos 
   8209  1.1  christos 	for (i = 0; i < (int)(rbtdb->node_lock_count); i++) {
   8210  1.1  christos 		result = NODE_INITLOCK(&rbtdb->node_locks[i].lock);
   8211  1.1  christos 		if (result == ISC_R_SUCCESS) {
   8212  1.3  christos 			isc_refcount_init(&rbtdb->node_locks[i].references, 0);
   8213  1.1  christos 		}
   8214  1.1  christos 		if (result != ISC_R_SUCCESS) {
   8215  1.1  christos 			while (i-- > 0) {
   8216  1.1  christos 				NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
   8217  1.1  christos 				isc_refcount_destroy(&rbtdb->node_locks[i].references);
   8218  1.1  christos 			}
   8219  1.1  christos 			goto cleanup_deadnodes;
   8220  1.1  christos 		}
   8221  1.3  christos 		rbtdb->node_locks[i].exiting = false;
   8222  1.1  christos 	}
   8223  1.1  christos 
   8224  1.1  christos 	/*
   8225  1.1  christos 	 * Attach to the mctx.  The database will persist so long as there
   8226  1.1  christos 	 * are references to it, and attaching to the mctx ensures that our
   8227  1.1  christos 	 * mctx won't disappear out from under us.
   8228  1.1  christos 	 */
   8229  1.1  christos 	isc_mem_attach(mctx, &rbtdb->common.mctx);
   8230  1.1  christos 	isc_mem_attach(hmctx, &rbtdb->hmctx);
   8231  1.1  christos 
   8232  1.1  christos 	/*
   8233  1.1  christos 	 * Make a copy of the origin name.
   8234  1.1  christos 	 */
   8235  1.1  christos 	result = dns_name_dupwithoffsets(origin, mctx, &rbtdb->common.origin);
   8236  1.1  christos 	if (result != ISC_R_SUCCESS) {
   8237  1.3  christos 		free_rbtdb(rbtdb, false, NULL);
   8238  1.1  christos 		return (result);
   8239  1.1  christos 	}
   8240  1.1  christos 
   8241  1.1  christos 	/*
   8242  1.1  christos 	 * Make the Red-Black Trees.
   8243  1.1  christos 	 */
   8244  1.1  christos 	result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree);
   8245  1.1  christos 	if (result != ISC_R_SUCCESS) {
   8246  1.3  christos 		free_rbtdb(rbtdb, false, NULL);
   8247  1.1  christos 		return (result);
   8248  1.1  christos 	}
   8249  1.1  christos 
   8250  1.1  christos 	result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->nsec);
   8251  1.1  christos 	if (result != ISC_R_SUCCESS) {
   8252  1.3  christos 		free_rbtdb(rbtdb, false, NULL);
   8253  1.1  christos 		return (result);
   8254  1.1  christos 	}
   8255  1.1  christos 
   8256  1.1  christos 	result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->nsec3);
   8257  1.1  christos 	if (result != ISC_R_SUCCESS) {
   8258  1.3  christos 		free_rbtdb(rbtdb, false, NULL);
   8259  1.1  christos 		return (result);
   8260  1.1  christos 	}
   8261  1.1  christos 
   8262  1.1  christos 	/*
   8263  1.1  christos 	 * In order to set the node callback bit correctly in zone databases,
   8264  1.1  christos 	 * we need to know if the node has the origin name of the zone.
   8265  1.1  christos 	 * In loading_addrdataset() we could simply compare the new name
   8266  1.1  christos 	 * to the origin name, but this is expensive.  Also, we don't know the
   8267  1.1  christos 	 * node name in addrdataset(), so we need another way of knowing the
   8268  1.1  christos 	 * zone's top.
   8269  1.1  christos 	 *
   8270  1.1  christos 	 * We now explicitly create a node for the zone's origin, and then
   8271  1.1  christos 	 * we simply remember the node's address.  This is safe, because
   8272  1.1  christos 	 * the top-of-zone node can never be deleted, nor can its address
   8273  1.1  christos 	 * change.
   8274  1.1  christos 	 */
   8275  1.1  christos 	if (!IS_CACHE(rbtdb)) {
   8276  1.1  christos 		rbtdb->origin_node = NULL;
   8277  1.1  christos 		result = dns_rbt_addnode(rbtdb->tree, &rbtdb->common.origin,
   8278  1.1  christos 					 &rbtdb->origin_node);
   8279  1.1  christos 		if (result != ISC_R_SUCCESS) {
   8280  1.1  christos 			INSIST(result != ISC_R_EXISTS);
   8281  1.3  christos 			free_rbtdb(rbtdb, false, NULL);
   8282  1.1  christos 			return (result);
   8283  1.1  christos 		}
   8284  1.1  christos 		INSIST(rbtdb->origin_node != NULL);
   8285  1.1  christos 		rbtdb->origin_node->nsec = DNS_RBT_NSEC_NORMAL;
   8286  1.1  christos 		/*
   8287  1.1  christos 		 * We need to give the origin node the right locknum.
   8288  1.1  christos 		 */
   8289  1.1  christos 		dns_name_init(&name, NULL);
   8290  1.1  christos 		dns_rbt_namefromnode(rbtdb->origin_node, &name);
   8291  1.1  christos 		rbtdb->origin_node->locknum =
   8292  1.1  christos 			rbtdb->origin_node->hashval %
   8293  1.1  christos 			rbtdb->node_lock_count;
   8294  1.1  christos 		/*
   8295  1.1  christos 		 * Add an apex node to the NSEC3 tree so that NSEC3 searches
   8296  1.1  christos 		 * return partial matches when there is only a single NSEC3
   8297  1.1  christos 		 * record in the tree.
   8298  1.1  christos 		 */
   8299  1.1  christos 		rbtdb->nsec3_origin_node = NULL;
   8300  1.1  christos 		result = dns_rbt_addnode(rbtdb->nsec3, &rbtdb->common.origin,
   8301  1.1  christos 					 &rbtdb->nsec3_origin_node);
   8302  1.1  christos 		if (result != ISC_R_SUCCESS) {
   8303  1.1  christos 			INSIST(result != ISC_R_EXISTS);
   8304  1.3  christos 			free_rbtdb(rbtdb, false, NULL);
   8305  1.1  christos 			return (result);
   8306  1.1  christos 		}
   8307  1.1  christos 		rbtdb->nsec3_origin_node->nsec = DNS_RBT_NSEC_NSEC3;
   8308  1.1  christos 		/*
   8309  1.1  christos 		 * We need to give the nsec3 origin node the right locknum.
   8310  1.1  christos 		 */
   8311  1.1  christos 		dns_name_init(&name, NULL);
   8312  1.1  christos 		dns_rbt_namefromnode(rbtdb->nsec3_origin_node, &name);
   8313  1.1  christos 		rbtdb->nsec3_origin_node->locknum =
   8314  1.1  christos 			rbtdb->nsec3_origin_node->hashval %
   8315  1.1  christos 			rbtdb->node_lock_count;
   8316  1.1  christos 	}
   8317  1.1  christos 
   8318  1.1  christos 	/*
   8319  1.1  christos 	 * Misc. Initialization.
   8320  1.1  christos 	 */
   8321  1.3  christos 	isc_refcount_init(&rbtdb->references, 1);
   8322  1.1  christos 	rbtdb->attributes = 0;
   8323  1.1  christos 	rbtdb->task = NULL;
   8324  1.1  christos 	rbtdb->serve_stale_ttl = 0;
   8325  1.1  christos 
   8326  1.1  christos 	/*
   8327  1.1  christos 	 * Version Initialization.
   8328  1.1  christos 	 */
   8329  1.1  christos 	rbtdb->current_serial = 1;
   8330  1.1  christos 	rbtdb->least_serial = 1;
   8331  1.1  christos 	rbtdb->next_serial = 2;
   8332  1.3  christos 	rbtdb->current_version = allocate_version(mctx, 1, 1, false);
   8333  1.1  christos 	if (rbtdb->current_version == NULL) {
   8334  1.3  christos 		INSIST(isc_refcount_decrement(&rbtdb->references) > 0);
   8335  1.3  christos 		free_rbtdb(rbtdb, false, NULL);
   8336  1.1  christos 		return (ISC_R_NOMEMORY);
   8337  1.1  christos 	}
   8338  1.1  christos 	rbtdb->current_version->rbtdb = rbtdb;
   8339  1.1  christos 	rbtdb->current_version->secure = dns_db_insecure;
   8340  1.3  christos 	rbtdb->current_version->havensec3 = false;
   8341  1.1  christos 	rbtdb->current_version->flags = 0;
   8342  1.1  christos 	rbtdb->current_version->iterations = 0;
   8343  1.1  christos 	rbtdb->current_version->hash = 0;
   8344  1.1  christos 	rbtdb->current_version->salt_length = 0;
   8345  1.1  christos 	memset(rbtdb->current_version->salt, 0,
   8346  1.1  christos 	       sizeof(rbtdb->current_version->salt));
   8347  1.1  christos 	result = isc_rwlock_init(&rbtdb->current_version->rwlock, 0, 0);
   8348  1.1  christos 	if (result != ISC_R_SUCCESS) {
   8349  1.1  christos 		free_gluetable(rbtdb->current_version);
   8350  1.1  christos 		isc_rwlock_destroy(&rbtdb->current_version->glue_rwlock);
   8351  1.1  christos 		isc_refcount_destroy(&rbtdb->current_version->references);
   8352  1.1  christos 		isc_mem_put(mctx, rbtdb->current_version,
   8353  1.1  christos 			    sizeof(*rbtdb->current_version));
   8354  1.1  christos 		rbtdb->current_version = NULL;
   8355  1.3  christos 		INSIST(isc_refcount_decrement(&rbtdb->references) > 0);
   8356  1.3  christos 		free_rbtdb(rbtdb, false, NULL);
   8357  1.1  christos 		return (result);
   8358  1.1  christos 	}
   8359  1.1  christos 
   8360  1.1  christos 	rbtdb->current_version->records = 0;
   8361  1.1  christos 	rbtdb->current_version->bytes = 0;
   8362  1.1  christos 	rbtdb->future_version = NULL;
   8363  1.1  christos 	ISC_LIST_INIT(rbtdb->open_versions);
   8364  1.1  christos 	/*
   8365  1.1  christos 	 * Keep the current version in the open list so that list operation
   8366  1.1  christos 	 * won't happen in normal lookup operations.
   8367  1.1  christos 	 */
   8368  1.1  christos 	PREPEND(rbtdb->open_versions, rbtdb->current_version, link);
   8369  1.1  christos 
   8370  1.1  christos 	rbtdb->common.magic = DNS_DB_MAGIC;
   8371  1.1  christos 	rbtdb->common.impmagic = RBTDB_MAGIC;
   8372  1.1  christos 
   8373  1.1  christos 	*dbp = (dns_db_t *)rbtdb;
   8374  1.1  christos 
   8375  1.1  christos 	return (ISC_R_SUCCESS);
   8376  1.1  christos 
   8377  1.1  christos  cleanup_deadnodes:
   8378  1.1  christos 	isc_mem_put(mctx, rbtdb->deadnodes,
   8379  1.1  christos 		    rbtdb->node_lock_count * sizeof(rbtnodelist_t));
   8380  1.1  christos 
   8381  1.1  christos  cleanup_heaps:
   8382  1.1  christos 	if (rbtdb->heaps != NULL) {
   8383  1.1  christos 		for (i = 0 ; i < (int)rbtdb->node_lock_count ; i++)
   8384  1.1  christos 			if (rbtdb->heaps[i] != NULL)
   8385  1.1  christos 				isc_heap_destroy(&rbtdb->heaps[i]);
   8386  1.1  christos 		isc_mem_put(hmctx, rbtdb->heaps,
   8387  1.1  christos 			    rbtdb->node_lock_count * sizeof(isc_heap_t *));
   8388  1.1  christos 	}
   8389  1.1  christos 
   8390  1.1  christos  cleanup_rdatasets:
   8391  1.1  christos 	if (rbtdb->rdatasets != NULL)
   8392  1.1  christos 		isc_mem_put(mctx, rbtdb->rdatasets, rbtdb->node_lock_count *
   8393  1.1  christos 			    sizeof(rdatasetheaderlist_t));
   8394  1.1  christos  cleanup_rrsetstats:
   8395  1.1  christos 	if (rbtdb->rrsetstats != NULL)
   8396  1.1  christos 		dns_stats_detach(&rbtdb->rrsetstats);
   8397  1.1  christos 
   8398  1.1  christos  cleanup_node_locks:
   8399  1.1  christos 	isc_mem_put(mctx, rbtdb->node_locks,
   8400  1.1  christos 		    rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));
   8401  1.1  christos 
   8402  1.1  christos  cleanup_tree_lock:
   8403  1.1  christos 	isc_rwlock_destroy(&rbtdb->tree_lock);
   8404  1.1  christos 
   8405  1.1  christos  cleanup_lock:
   8406  1.1  christos 	RBTDB_DESTROYLOCK(&rbtdb->lock);
   8407  1.1  christos 
   8408  1.1  christos  cleanup_rbtdb:
   8409  1.1  christos 	isc_mem_put(mctx, rbtdb,  sizeof(*rbtdb));
   8410  1.1  christos 	return (result);
   8411  1.1  christos }
   8412  1.1  christos 
   8413  1.1  christos 
   8414  1.1  christos /*
   8415  1.1  christos  * Slabbed Rdataset Methods
   8416  1.1  christos  */
   8417  1.1  christos 
   8418  1.1  christos static void
   8419  1.1  christos rdataset_disassociate(dns_rdataset_t *rdataset) {
   8420  1.1  christos 	dns_db_t *db = rdataset->private1;
   8421  1.1  christos 	dns_dbnode_t *node = rdataset->private2;
   8422  1.1  christos 
   8423  1.1  christos 	detachnode(db, &node);
   8424  1.1  christos }
   8425  1.1  christos 
   8426  1.1  christos static isc_result_t
   8427  1.1  christos rdataset_first(dns_rdataset_t *rdataset) {
   8428  1.1  christos 	unsigned char *raw = rdataset->private3;        /* RDATASLAB */
   8429  1.1  christos 	unsigned int count;
   8430  1.1  christos 
   8431  1.1  christos 	count = raw[0] * 256 + raw[1];
   8432  1.1  christos 	if (count == 0) {
   8433  1.1  christos 		rdataset->private5 = NULL;
   8434  1.1  christos 		return (ISC_R_NOMORE);
   8435  1.1  christos 	}
   8436  1.1  christos 
   8437  1.1  christos #if DNS_RDATASET_FIXED
   8438  1.1  christos 	if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0)
   8439  1.1  christos 		raw += 2 + (4 * count);
   8440  1.1  christos 	else
   8441  1.1  christos #endif
   8442  1.1  christos 		raw += 2;
   8443  1.1  christos 
   8444  1.1  christos 	/*
   8445  1.1  christos 	 * The privateuint4 field is the number of rdata beyond the
   8446  1.1  christos 	 * cursor position, so we decrement the total count by one
   8447  1.1  christos 	 * before storing it.
   8448  1.1  christos 	 *
   8449  1.1  christos 	 * If DNS_RDATASETATTR_LOADORDER is not set 'raw' points to the
   8450  1.1  christos 	 * first record.  If DNS_RDATASETATTR_LOADORDER is set 'raw' points
   8451  1.1  christos 	 * to the first entry in the offset table.
   8452  1.1  christos 	 */
   8453  1.1  christos 	count--;
   8454  1.1  christos 	rdataset->privateuint4 = count;
   8455  1.1  christos 	rdataset->private5 = raw;
   8456  1.1  christos 
   8457  1.1  christos 	return (ISC_R_SUCCESS);
   8458  1.1  christos }
   8459  1.1  christos 
   8460  1.1  christos static isc_result_t
   8461  1.1  christos rdataset_next(dns_rdataset_t *rdataset) {
   8462  1.1  christos 	unsigned int count;
   8463  1.1  christos 	unsigned int length;
   8464  1.1  christos 	unsigned char *raw;     /* RDATASLAB */
   8465  1.1  christos 
   8466  1.1  christos 	count = rdataset->privateuint4;
   8467  1.1  christos 	if (count == 0)
   8468  1.1  christos 		return (ISC_R_NOMORE);
   8469  1.1  christos 	count--;
   8470  1.1  christos 	rdataset->privateuint4 = count;
   8471  1.1  christos 
   8472  1.1  christos 	/*
   8473  1.1  christos 	 * Skip forward one record (length + 4) or one offset (4).
   8474  1.1  christos 	 */
   8475  1.1  christos 	raw = rdataset->private5;
   8476  1.1  christos #if DNS_RDATASET_FIXED
   8477  1.1  christos 	if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0) {
   8478  1.1  christos #endif
   8479  1.1  christos 		length = raw[0] * 256 + raw[1];
   8480  1.1  christos 		raw += length;
   8481  1.1  christos #if DNS_RDATASET_FIXED
   8482  1.1  christos 	}
   8483  1.1  christos 	rdataset->private5 = raw + 4;           /* length(2) + order(2) */
   8484  1.1  christos #else
   8485  1.1  christos 	rdataset->private5 = raw + 2;           /* length(2) */
   8486  1.1  christos #endif
   8487  1.1  christos 
   8488  1.1  christos 	return (ISC_R_SUCCESS);
   8489  1.1  christos }
   8490  1.1  christos 
   8491  1.1  christos static void
   8492  1.1  christos rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
   8493  1.1  christos 	unsigned char *raw = rdataset->private5;        /* RDATASLAB */
   8494  1.1  christos #if DNS_RDATASET_FIXED
   8495  1.1  christos 	unsigned int offset;
   8496  1.1  christos #endif
   8497  1.1  christos 	unsigned int length;
   8498  1.1  christos 	isc_region_t r;
   8499  1.1  christos 	unsigned int flags = 0;
   8500  1.1  christos 
   8501  1.1  christos 	REQUIRE(raw != NULL);
   8502  1.1  christos 
   8503  1.1  christos 	/*
   8504  1.1  christos 	 * Find the start of the record if not already in private5
   8505  1.1  christos 	 * then skip the length and order fields.
   8506  1.1  christos 	 */
   8507  1.1  christos #if DNS_RDATASET_FIXED
   8508  1.1  christos 	if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) != 0) {
   8509  1.1  christos 		offset = (raw[0] << 24) + (raw[1] << 16) +
   8510  1.1  christos 			 (raw[2] << 8) + raw[3];
   8511  1.1  christos 		raw = rdataset->private3;
   8512  1.1  christos 		raw += offset;
   8513  1.1  christos 	}
   8514  1.1  christos #endif
   8515  1.1  christos 	length = raw[0] * 256 + raw[1];
   8516  1.1  christos #if DNS_RDATASET_FIXED
   8517  1.1  christos 	raw += 4;
   8518  1.1  christos #else
   8519  1.1  christos 	raw += 2;
   8520  1.1  christos #endif
   8521  1.1  christos 	if (rdataset->type == dns_rdatatype_rrsig) {
   8522  1.1  christos 		if (*raw & DNS_RDATASLAB_OFFLINE)
   8523  1.1  christos 			flags |= DNS_RDATA_OFFLINE;
   8524  1.1  christos 		length--;
   8525  1.1  christos 		raw++;
   8526  1.1  christos 	}
   8527  1.1  christos 	r.length = length;
   8528  1.1  christos 	r.base = raw;
   8529  1.1  christos 	dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
   8530  1.1  christos 	rdata->flags |= flags;
   8531  1.1  christos }
   8532  1.1  christos 
   8533  1.1  christos static void
   8534  1.1  christos rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
   8535  1.1  christos 	dns_db_t *db = source->private1;
   8536  1.1  christos 	dns_dbnode_t *node = source->private2;
   8537  1.1  christos 	dns_dbnode_t *cloned_node = NULL;
   8538  1.1  christos 
   8539  1.1  christos 	attachnode(db, node, &cloned_node);
   8540  1.1  christos 	INSIST(!ISC_LINK_LINKED(target, link));
   8541  1.1  christos 	*target = *source;
   8542  1.1  christos 	ISC_LINK_INIT(target, link);
   8543  1.1  christos 
   8544  1.1  christos 	/*
   8545  1.1  christos 	 * Reset iterator state.
   8546  1.1  christos 	 */
   8547  1.1  christos 	target->privateuint4 = 0;
   8548  1.1  christos 	target->private5 = NULL;
   8549  1.1  christos }
   8550  1.1  christos 
   8551  1.1  christos static unsigned int
   8552  1.1  christos rdataset_count(dns_rdataset_t *rdataset) {
   8553  1.1  christos 	unsigned char *raw = rdataset->private3;        /* RDATASLAB */
   8554  1.1  christos 	unsigned int count;
   8555  1.1  christos 
   8556  1.1  christos 	count = raw[0] * 256 + raw[1];
   8557  1.1  christos 
   8558  1.1  christos 	return (count);
   8559  1.1  christos }
   8560  1.1  christos 
   8561  1.1  christos static isc_result_t
   8562  1.1  christos rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
   8563  1.1  christos 		    dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
   8564  1.1  christos {
   8565  1.1  christos 	dns_db_t *db = rdataset->private1;
   8566  1.1  christos 	dns_dbnode_t *node = rdataset->private2;
   8567  1.1  christos 	dns_dbnode_t *cloned_node;
   8568  1.1  christos 	const struct noqname *noqname = rdataset->private6;
   8569  1.1  christos 
   8570  1.1  christos 	cloned_node = NULL;
   8571  1.1  christos 	attachnode(db, node, &cloned_node);
   8572  1.1  christos 	nsec->methods = &slab_methods;
   8573  1.1  christos 	nsec->rdclass = db->rdclass;
   8574  1.1  christos 	nsec->type = noqname->type;
   8575  1.1  christos 	nsec->covers = 0;
   8576  1.1  christos 	nsec->ttl = rdataset->ttl;
   8577  1.1  christos 	nsec->trust = rdataset->trust;
   8578  1.1  christos 	nsec->private1 = rdataset->private1;
   8579  1.1  christos 	nsec->private2 = rdataset->private2;
   8580  1.1  christos 	nsec->private3 = noqname->neg;
   8581  1.1  christos 	nsec->privateuint4 = 0;
   8582  1.1  christos 	nsec->private5 = NULL;
   8583  1.1  christos 	nsec->private6 = NULL;
   8584  1.1  christos 	nsec->private7 = NULL;
   8585  1.1  christos 
   8586  1.1  christos 	cloned_node = NULL;
   8587  1.1  christos 	attachnode(db, node, &cloned_node);
   8588  1.1  christos 	nsecsig->methods = &slab_methods;
   8589  1.1  christos 	nsecsig->rdclass = db->rdclass;
   8590  1.1  christos 	nsecsig->type = dns_rdatatype_rrsig;
   8591  1.1  christos 	nsecsig->covers = noqname->type;
   8592  1.1  christos 	nsecsig->ttl = rdataset->ttl;
   8593  1.1  christos 	nsecsig->trust = rdataset->trust;
   8594  1.1  christos 	nsecsig->private1 = rdataset->private1;
   8595  1.1  christos 	nsecsig->private2 = rdataset->private2;
   8596  1.1  christos 	nsecsig->private3 = noqname->negsig;
   8597  1.1  christos 	nsecsig->privateuint4 = 0;
   8598  1.1  christos 	nsecsig->private5 = NULL;
   8599  1.1  christos 	nsec->private6 = NULL;
   8600  1.1  christos 	nsec->private7 = NULL;
   8601  1.1  christos 
   8602  1.1  christos 	dns_name_clone(&noqname->name, name);
   8603  1.1  christos 
   8604  1.1  christos 	return (ISC_R_SUCCESS);
   8605  1.1  christos }
   8606  1.1  christos 
   8607  1.1  christos static isc_result_t
   8608  1.1  christos rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
   8609  1.1  christos 		    dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
   8610  1.1  christos {
   8611  1.1  christos 	dns_db_t *db = rdataset->private1;
   8612  1.1  christos 	dns_dbnode_t *node = rdataset->private2;
   8613  1.1  christos 	dns_dbnode_t *cloned_node;
   8614  1.1  christos 	const struct noqname *closest = rdataset->private7;
   8615  1.1  christos 
   8616  1.1  christos 	cloned_node = NULL;
   8617  1.1  christos 	attachnode(db, node, &cloned_node);
   8618  1.1  christos 	nsec->methods = &slab_methods;
   8619  1.1  christos 	nsec->rdclass = db->rdclass;
   8620  1.1  christos 	nsec->type = closest->type;
   8621  1.1  christos 	nsec->covers = 0;
   8622  1.1  christos 	nsec->ttl = rdataset->ttl;
   8623  1.1  christos 	nsec->trust = rdataset->trust;
   8624  1.1  christos 	nsec->private1 = rdataset->private1;
   8625  1.1  christos 	nsec->private2 = rdataset->private2;
   8626  1.1  christos 	nsec->private3 = closest->neg;
   8627  1.1  christos 	nsec->privateuint4 = 0;
   8628  1.1  christos 	nsec->private5 = NULL;
   8629  1.1  christos 	nsec->private6 = NULL;
   8630  1.1  christos 	nsec->private7 = NULL;
   8631  1.1  christos 
   8632  1.1  christos 	cloned_node = NULL;
   8633  1.1  christos 	attachnode(db, node, &cloned_node);
   8634  1.1  christos 	nsecsig->methods = &slab_methods;
   8635  1.1  christos 	nsecsig->rdclass = db->rdclass;
   8636  1.1  christos 	nsecsig->type = dns_rdatatype_rrsig;
   8637  1.1  christos 	nsecsig->covers = closest->type;
   8638  1.1  christos 	nsecsig->ttl = rdataset->ttl;
   8639  1.1  christos 	nsecsig->trust = rdataset->trust;
   8640  1.1  christos 	nsecsig->private1 = rdataset->private1;
   8641  1.1  christos 	nsecsig->private2 = rdataset->private2;
   8642  1.1  christos 	nsecsig->private3 = closest->negsig;
   8643  1.1  christos 	nsecsig->privateuint4 = 0;
   8644  1.1  christos 	nsecsig->private5 = NULL;
   8645  1.1  christos 	nsec->private6 = NULL;
   8646  1.1  christos 	nsec->private7 = NULL;
   8647  1.1  christos 
   8648  1.1  christos 	dns_name_clone(&closest->name, name);
   8649  1.1  christos 
   8650  1.1  christos 	return (ISC_R_SUCCESS);
   8651  1.1  christos }
   8652  1.1  christos 
   8653  1.1  christos static void
   8654  1.1  christos rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
   8655  1.1  christos 	dns_rbtdb_t *rbtdb = rdataset->private1;
   8656  1.1  christos 	dns_rbtnode_t *rbtnode = rdataset->private2;
   8657  1.1  christos 	rdatasetheader_t *header = rdataset->private3;
   8658  1.1  christos 
   8659  1.1  christos 	header--;
   8660  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8661  1.1  christos 		  isc_rwlocktype_write);
   8662  1.1  christos 	header->trust = rdataset->trust = trust;
   8663  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8664  1.1  christos 		  isc_rwlocktype_write);
   8665  1.1  christos }
   8666  1.1  christos 
   8667  1.1  christos static void
   8668  1.1  christos rdataset_expire(dns_rdataset_t *rdataset) {
   8669  1.1  christos 	dns_rbtdb_t *rbtdb = rdataset->private1;
   8670  1.1  christos 	dns_rbtnode_t *rbtnode = rdataset->private2;
   8671  1.1  christos 	rdatasetheader_t *header = rdataset->private3;
   8672  1.1  christos 
   8673  1.1  christos 	header--;
   8674  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8675  1.1  christos 		  isc_rwlocktype_write);
   8676  1.3  christos 	expire_header(rbtdb, header, false, expire_flush);
   8677  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8678  1.1  christos 		  isc_rwlocktype_write);
   8679  1.1  christos }
   8680  1.1  christos 
   8681  1.1  christos static void
   8682  1.1  christos rdataset_clearprefetch(dns_rdataset_t *rdataset) {
   8683  1.1  christos 	dns_rbtdb_t *rbtdb = rdataset->private1;
   8684  1.1  christos 	dns_rbtnode_t *rbtnode = rdataset->private2;
   8685  1.1  christos 	rdatasetheader_t *header = rdataset->private3;
   8686  1.1  christos 
   8687  1.1  christos 	header--;
   8688  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8689  1.1  christos 		  isc_rwlocktype_write);
   8690  1.1  christos 	header->attributes &= ~RDATASET_ATTR_PREFETCH;
   8691  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8692  1.1  christos 		  isc_rwlocktype_write);
   8693  1.1  christos }
   8694  1.1  christos 
   8695  1.1  christos /*
   8696  1.1  christos  * Rdataset Iterator Methods
   8697  1.1  christos  */
   8698  1.1  christos 
   8699  1.1  christos static void
   8700  1.1  christos rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
   8701  1.1  christos 	rbtdb_rdatasetiter_t *rbtiterator;
   8702  1.1  christos 
   8703  1.1  christos 	rbtiterator = (rbtdb_rdatasetiter_t *)(*iteratorp);
   8704  1.1  christos 
   8705  1.1  christos 	if (rbtiterator->common.version != NULL)
   8706  1.1  christos 		closeversion(rbtiterator->common.db,
   8707  1.3  christos 			     &rbtiterator->common.version, false);
   8708  1.1  christos 	detachnode(rbtiterator->common.db, &rbtiterator->common.node);
   8709  1.1  christos 	isc_mem_put(rbtiterator->common.db->mctx, rbtiterator,
   8710  1.1  christos 		    sizeof(*rbtiterator));
   8711  1.1  christos 
   8712  1.1  christos 	*iteratorp = NULL;
   8713  1.1  christos }
   8714  1.1  christos 
   8715  1.1  christos static isc_result_t
   8716  1.1  christos rdatasetiter_first(dns_rdatasetiter_t *iterator) {
   8717  1.1  christos 	rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
   8718  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
   8719  1.1  christos 	dns_rbtnode_t *rbtnode = rbtiterator->common.node;
   8720  1.1  christos 	rbtdb_version_t *rbtversion = rbtiterator->common.version;
   8721  1.1  christos 	rdatasetheader_t *header, *top_next;
   8722  1.1  christos 	rbtdb_serial_t serial;
   8723  1.1  christos 	isc_stdtime_t now;
   8724  1.1  christos 
   8725  1.1  christos 	if (IS_CACHE(rbtdb)) {
   8726  1.1  christos 		serial = 1;
   8727  1.1  christos 		now = rbtiterator->common.now;
   8728  1.1  christos 	} else {
   8729  1.1  christos 		serial = rbtversion->serial;
   8730  1.1  christos 		now = 0;
   8731  1.1  christos 	}
   8732  1.1  christos 
   8733  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8734  1.1  christos 		  isc_rwlocktype_read);
   8735  1.1  christos 
   8736  1.1  christos 	for (header = rbtnode->data; header != NULL; header = top_next) {
   8737  1.1  christos 		top_next = header->next;
   8738  1.1  christos 		do {
   8739  1.1  christos 			if (header->serial <= serial && !IGNORE(header)) {
   8740  1.1  christos 				/*
   8741  1.1  christos 				 * Is this a "this rdataset doesn't exist"
   8742  1.1  christos 				 * record?  Or is it too old in the cache?
   8743  1.1  christos 				 *
   8744  1.1  christos 				 * Note: unlike everywhere else, we
   8745  1.1  christos 				 * check for now > header->rdh_ttl instead
   8746  1.1  christos 				 * of now >= header->rdh_ttl.  This allows
   8747  1.1  christos 				 * ANY and RRSIG queries for 0 TTL
   8748  1.1  christos 				 * rdatasets to work.
   8749  1.1  christos 				 */
   8750  1.1  christos 				if (NONEXISTENT(header) ||
   8751  1.1  christos 				    (now != 0 && now > header->rdh_ttl
   8752  1.1  christos 						     + rbtdb->serve_stale_ttl))
   8753  1.1  christos 					header = NULL;
   8754  1.1  christos 				break;
   8755  1.1  christos 			} else
   8756  1.1  christos 				header = header->down;
   8757  1.1  christos 		} while (header != NULL);
   8758  1.1  christos 		if (header != NULL)
   8759  1.1  christos 			break;
   8760  1.1  christos 	}
   8761  1.1  christos 
   8762  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8763  1.1  christos 		    isc_rwlocktype_read);
   8764  1.1  christos 
   8765  1.1  christos 	rbtiterator->current = header;
   8766  1.1  christos 
   8767  1.1  christos 	if (header == NULL)
   8768  1.1  christos 		return (ISC_R_NOMORE);
   8769  1.1  christos 
   8770  1.1  christos 	return (ISC_R_SUCCESS);
   8771  1.1  christos }
   8772  1.1  christos 
   8773  1.1  christos static isc_result_t
   8774  1.1  christos rdatasetiter_next(dns_rdatasetiter_t *iterator) {
   8775  1.1  christos 	rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
   8776  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
   8777  1.1  christos 	dns_rbtnode_t *rbtnode = rbtiterator->common.node;
   8778  1.1  christos 	rbtdb_version_t *rbtversion = rbtiterator->common.version;
   8779  1.1  christos 	rdatasetheader_t *header, *top_next;
   8780  1.1  christos 	rbtdb_serial_t serial;
   8781  1.1  christos 	isc_stdtime_t now;
   8782  1.1  christos 	rbtdb_rdatatype_t type, negtype;
   8783  1.1  christos 	dns_rdatatype_t rdtype, covers;
   8784  1.1  christos 
   8785  1.1  christos 	header = rbtiterator->current;
   8786  1.1  christos 	if (header == NULL)
   8787  1.1  christos 		return (ISC_R_NOMORE);
   8788  1.1  christos 
   8789  1.1  christos 	if (IS_CACHE(rbtdb)) {
   8790  1.1  christos 		serial = 1;
   8791  1.1  christos 		now = rbtiterator->common.now;
   8792  1.1  christos 	} else {
   8793  1.1  christos 		serial = rbtversion->serial;
   8794  1.1  christos 		now = 0;
   8795  1.1  christos 	}
   8796  1.1  christos 
   8797  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8798  1.1  christos 		  isc_rwlocktype_read);
   8799  1.1  christos 
   8800  1.1  christos 	type = header->type;
   8801  1.1  christos 	rdtype = RBTDB_RDATATYPE_BASE(header->type);
   8802  1.1  christos 	if (NEGATIVE(header)) {
   8803  1.1  christos 		covers = RBTDB_RDATATYPE_EXT(header->type);
   8804  1.1  christos 		negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
   8805  1.1  christos 	} else
   8806  1.1  christos 		negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
   8807  1.1  christos 	for (header = header->next; header != NULL; header = top_next) {
   8808  1.1  christos 		top_next = header->next;
   8809  1.1  christos 		/*
   8810  1.1  christos 		 * If not walking back up the down list.
   8811  1.1  christos 		 */
   8812  1.1  christos 		if (header->type != type && header->type != negtype) {
   8813  1.1  christos 			do {
   8814  1.1  christos 				if (header->serial <= serial &&
   8815  1.1  christos 				    !IGNORE(header)) {
   8816  1.1  christos 					/*
   8817  1.1  christos 					 * Is this a "this rdataset doesn't
   8818  1.1  christos 					 * exist" record?
   8819  1.1  christos 					 *
   8820  1.1  christos 					 * Note: unlike everywhere else, we
   8821  1.1  christos 					 * check for now > header->ttl instead
   8822  1.1  christos 					 * of now >= header->ttl.  This allows
   8823  1.1  christos 					 * ANY and RRSIG queries for 0 TTL
   8824  1.1  christos 					 * rdatasets to work.
   8825  1.1  christos 					 */
   8826  1.1  christos 					if (NONEXISTENT(header) ||
   8827  1.1  christos 					    (now != 0 && now > header->rdh_ttl))
   8828  1.1  christos 						header = NULL;
   8829  1.1  christos 					break;
   8830  1.1  christos 				} else
   8831  1.1  christos 					header = header->down;
   8832  1.1  christos 			} while (header != NULL);
   8833  1.1  christos 			if (header != NULL)
   8834  1.1  christos 				break;
   8835  1.1  christos 		}
   8836  1.1  christos 	}
   8837  1.1  christos 
   8838  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8839  1.1  christos 		    isc_rwlocktype_read);
   8840  1.1  christos 
   8841  1.1  christos 	rbtiterator->current = header;
   8842  1.1  christos 
   8843  1.1  christos 	if (header == NULL)
   8844  1.1  christos 		return (ISC_R_NOMORE);
   8845  1.1  christos 
   8846  1.1  christos 	return (ISC_R_SUCCESS);
   8847  1.1  christos }
   8848  1.1  christos 
   8849  1.1  christos static void
   8850  1.1  christos rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
   8851  1.1  christos 	rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
   8852  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
   8853  1.1  christos 	dns_rbtnode_t *rbtnode = rbtiterator->common.node;
   8854  1.1  christos 	rdatasetheader_t *header;
   8855  1.1  christos 
   8856  1.1  christos 	header = rbtiterator->current;
   8857  1.1  christos 	REQUIRE(header != NULL);
   8858  1.1  christos 
   8859  1.1  christos 	NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8860  1.1  christos 		  isc_rwlocktype_read);
   8861  1.1  christos 
   8862  1.1  christos 	bind_rdataset(rbtdb, rbtnode, header, rbtiterator->common.now,
   8863  1.1  christos 		      rdataset);
   8864  1.1  christos 
   8865  1.1  christos 	NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
   8866  1.1  christos 		    isc_rwlocktype_read);
   8867  1.1  christos }
   8868  1.1  christos 
   8869  1.1  christos 
   8870  1.1  christos /*
   8871  1.1  christos  * Database Iterator Methods
   8872  1.1  christos  */
   8873  1.1  christos 
   8874  1.1  christos static inline void
   8875  1.1  christos reference_iter_node(rbtdb_dbiterator_t *rbtdbiter) {
   8876  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
   8877  1.1  christos 	dns_rbtnode_t *node = rbtdbiter->node;
   8878  1.1  christos 
   8879  1.1  christos 	if (node == NULL)
   8880  1.1  christos 		return;
   8881  1.1  christos 
   8882  1.1  christos 	INSIST(rbtdbiter->tree_locked != isc_rwlocktype_none);
   8883  1.1  christos 	reactivate_node(rbtdb, node, rbtdbiter->tree_locked);
   8884  1.1  christos }
   8885  1.1  christos 
   8886  1.1  christos static inline void
   8887  1.1  christos dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter) {
   8888  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
   8889  1.1  christos 	dns_rbtnode_t *node = rbtdbiter->node;
   8890  1.1  christos 	nodelock_t *lock;
   8891  1.1  christos 
   8892  1.1  christos 	if (node == NULL)
   8893  1.1  christos 		return;
   8894  1.1  christos 
   8895  1.1  christos 	lock = &rbtdb->node_locks[node->locknum].lock;
   8896  1.1  christos 	NODE_LOCK(lock, isc_rwlocktype_read);
   8897  1.1  christos 	decrement_reference(rbtdb, node, 0, isc_rwlocktype_read,
   8898  1.3  christos 			    rbtdbiter->tree_locked, false);
   8899  1.1  christos 	NODE_UNLOCK(lock, isc_rwlocktype_read);
   8900  1.1  christos 
   8901  1.1  christos 	rbtdbiter->node = NULL;
   8902  1.1  christos }
   8903  1.1  christos 
   8904  1.1  christos static void
   8905  1.1  christos flush_deletions(rbtdb_dbiterator_t *rbtdbiter) {
   8906  1.1  christos 	dns_rbtnode_t *node;
   8907  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
   8908  1.3  christos 	bool was_read_locked = false;
   8909  1.1  christos 	nodelock_t *lock;
   8910  1.1  christos 	int i;
   8911  1.1  christos 
   8912  1.1  christos 	if (rbtdbiter->delcnt != 0) {
   8913  1.1  christos 		/*
   8914  1.1  christos 		 * Note that "%d node of %d in tree" can report things like
   8915  1.1  christos 		 * "flush_deletions: 59 nodes of 41 in tree".  This means
   8916  1.1  christos 		 * That some nodes appear on the deletions list more than
   8917  1.1  christos 		 * once.  Only the last occurence will actually be deleted.
   8918  1.1  christos 		 */
   8919  1.1  christos 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
   8920  1.1  christos 			      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
   8921  1.1  christos 			      "flush_deletions: %d nodes of %d in tree",
   8922  1.1  christos 			      rbtdbiter->delcnt,
   8923  1.1  christos 			      dns_rbt_nodecount(rbtdb->tree));
   8924  1.1  christos 
   8925  1.1  christos 		if (rbtdbiter->tree_locked == isc_rwlocktype_read) {
   8926  1.1  christos 			RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   8927  1.3  christos 			was_read_locked = true;
   8928  1.1  christos 		}
   8929  1.1  christos 		RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   8930  1.1  christos 		rbtdbiter->tree_locked = isc_rwlocktype_write;
   8931  1.1  christos 
   8932  1.1  christos 		for (i = 0; i < rbtdbiter->delcnt; i++) {
   8933  1.1  christos 			node = rbtdbiter->deletions[i];
   8934  1.1  christos 			lock = &rbtdb->node_locks[node->locknum].lock;
   8935  1.1  christos 
   8936  1.1  christos 			NODE_LOCK(lock, isc_rwlocktype_read);
   8937  1.1  christos 			decrement_reference(rbtdb, node, 0,
   8938  1.1  christos 					    isc_rwlocktype_read,
   8939  1.3  christos 					    rbtdbiter->tree_locked, false);
   8940  1.1  christos 			NODE_UNLOCK(lock, isc_rwlocktype_read);
   8941  1.1  christos 		}
   8942  1.1  christos 
   8943  1.1  christos 		rbtdbiter->delcnt = 0;
   8944  1.1  christos 
   8945  1.1  christos 		RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
   8946  1.1  christos 		if (was_read_locked) {
   8947  1.1  christos 			RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   8948  1.1  christos 			rbtdbiter->tree_locked = isc_rwlocktype_read;
   8949  1.1  christos 
   8950  1.1  christos 		} else {
   8951  1.1  christos 			rbtdbiter->tree_locked = isc_rwlocktype_none;
   8952  1.1  christos 		}
   8953  1.1  christos 	}
   8954  1.1  christos }
   8955  1.1  christos 
   8956  1.1  christos static inline void
   8957  1.1  christos resume_iteration(rbtdb_dbiterator_t *rbtdbiter) {
   8958  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
   8959  1.1  christos 
   8960  1.1  christos 	REQUIRE(rbtdbiter->paused);
   8961  1.1  christos 	REQUIRE(rbtdbiter->tree_locked == isc_rwlocktype_none);
   8962  1.1  christos 
   8963  1.1  christos 	RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   8964  1.1  christos 	rbtdbiter->tree_locked = isc_rwlocktype_read;
   8965  1.1  christos 
   8966  1.3  christos 	rbtdbiter->paused = false;
   8967  1.1  christos }
   8968  1.1  christos 
   8969  1.1  christos static void
   8970  1.1  christos dbiterator_destroy(dns_dbiterator_t **iteratorp) {
   8971  1.1  christos 	rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)(*iteratorp);
   8972  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
   8973  1.1  christos 	dns_db_t *db = NULL;
   8974  1.1  christos 
   8975  1.1  christos 	if (rbtdbiter->tree_locked == isc_rwlocktype_read) {
   8976  1.1  christos 		RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   8977  1.1  christos 		rbtdbiter->tree_locked = isc_rwlocktype_none;
   8978  1.1  christos 	} else
   8979  1.1  christos 		INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none);
   8980  1.1  christos 
   8981  1.1  christos 	dereference_iter_node(rbtdbiter);
   8982  1.1  christos 
   8983  1.1  christos 	flush_deletions(rbtdbiter);
   8984  1.1  christos 
   8985  1.1  christos 	dns_db_attach(rbtdbiter->common.db, &db);
   8986  1.1  christos 	dns_db_detach(&rbtdbiter->common.db);
   8987  1.1  christos 
   8988  1.1  christos 	dns_rbtnodechain_reset(&rbtdbiter->chain);
   8989  1.1  christos 	dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
   8990  1.1  christos 	isc_mem_put(db->mctx, rbtdbiter, sizeof(*rbtdbiter));
   8991  1.1  christos 	dns_db_detach(&db);
   8992  1.1  christos 
   8993  1.1  christos 	*iteratorp = NULL;
   8994  1.1  christos }
   8995  1.1  christos 
   8996  1.1  christos static isc_result_t
   8997  1.1  christos dbiterator_first(dns_dbiterator_t *iterator) {
   8998  1.1  christos 	isc_result_t result;
   8999  1.1  christos 	rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
   9000  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
   9001  1.1  christos 	dns_name_t *name, *origin;
   9002  1.1  christos 
   9003  1.1  christos 	if (rbtdbiter->result != ISC_R_SUCCESS &&
   9004  1.1  christos 	    rbtdbiter->result != ISC_R_NOTFOUND &&
   9005  1.1  christos 	    rbtdbiter->result != DNS_R_PARTIALMATCH &&
   9006  1.1  christos 	    rbtdbiter->result != ISC_R_NOMORE)
   9007  1.1  christos 		return (rbtdbiter->result);
   9008  1.1  christos 
   9009  1.1  christos 	if (rbtdbiter->paused)
   9010  1.1  christos 		resume_iteration(rbtdbiter);
   9011  1.1  christos 
   9012  1.1  christos 	dereference_iter_node(rbtdbiter);
   9013  1.1  christos 
   9014  1.1  christos 	name = dns_fixedname_name(&rbtdbiter->name);
   9015  1.1  christos 	origin = dns_fixedname_name(&rbtdbiter->origin);
   9016  1.1  christos 	dns_rbtnodechain_reset(&rbtdbiter->chain);
   9017  1.1  christos 	dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
   9018  1.1  christos 
   9019  1.1  christos 	if (rbtdbiter->nsec3only) {
   9020  1.1  christos 		rbtdbiter->current = &rbtdbiter->nsec3chain;
   9021  1.1  christos 		result = dns_rbtnodechain_first(rbtdbiter->current,
   9022  1.1  christos 						rbtdb->nsec3, name, origin);
   9023  1.1  christos 	} else {
   9024  1.1  christos 		rbtdbiter->current = &rbtdbiter->chain;
   9025  1.1  christos 		result = dns_rbtnodechain_first(rbtdbiter->current,
   9026  1.1  christos 						rbtdb->tree, name, origin);
   9027  1.1  christos 		if (!rbtdbiter->nonsec3 && result == ISC_R_NOTFOUND) {
   9028  1.1  christos 			rbtdbiter->current = &rbtdbiter->nsec3chain;
   9029  1.1  christos 			result = dns_rbtnodechain_first(rbtdbiter->current,
   9030  1.1  christos 							rbtdb->nsec3, name,
   9031  1.1  christos 							origin);
   9032  1.1  christos 		}
   9033  1.1  christos 	}
   9034  1.1  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
   9035  1.1  christos 		result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
   9036  1.1  christos 						  NULL, &rbtdbiter->node);
   9037  1.1  christos 		if (result == ISC_R_SUCCESS) {
   9038  1.3  christos 			rbtdbiter->new_origin = true;
   9039  1.1  christos 			reference_iter_node(rbtdbiter);
   9040  1.1  christos 		}
   9041  1.1  christos 	} else {
   9042  1.1  christos 		INSIST(result == ISC_R_NOTFOUND);
   9043  1.1  christos 		result = ISC_R_NOMORE; /* The tree is empty. */
   9044  1.1  christos 	}
   9045  1.1  christos 
   9046  1.1  christos 	rbtdbiter->result = result;
   9047  1.1  christos 
   9048  1.1  christos 	if (result != ISC_R_SUCCESS)
   9049  1.1  christos 		ENSURE(!rbtdbiter->paused);
   9050  1.1  christos 
   9051  1.1  christos 	return (result);
   9052  1.1  christos }
   9053  1.1  christos 
   9054  1.1  christos static isc_result_t
   9055  1.1  christos dbiterator_last(dns_dbiterator_t *iterator) {
   9056  1.1  christos 	isc_result_t result;
   9057  1.1  christos 	rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
   9058  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
   9059  1.1  christos 	dns_name_t *name, *origin;
   9060  1.1  christos 
   9061  1.1  christos 	if (rbtdbiter->result != ISC_R_SUCCESS &&
   9062  1.1  christos 	    rbtdbiter->result != ISC_R_NOTFOUND &&
   9063  1.1  christos 	    rbtdbiter->result != DNS_R_PARTIALMATCH &&
   9064  1.1  christos 	    rbtdbiter->result != ISC_R_NOMORE)
   9065  1.1  christos 		return (rbtdbiter->result);
   9066  1.1  christos 
   9067  1.1  christos 	if (rbtdbiter->paused)
   9068  1.1  christos 		resume_iteration(rbtdbiter);
   9069  1.1  christos 
   9070  1.1  christos 	dereference_iter_node(rbtdbiter);
   9071  1.1  christos 
   9072  1.1  christos 	name = dns_fixedname_name(&rbtdbiter->name);
   9073  1.1  christos 	origin = dns_fixedname_name(&rbtdbiter->origin);
   9074  1.1  christos 	dns_rbtnodechain_reset(&rbtdbiter->chain);
   9075  1.1  christos 	dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
   9076  1.1  christos 
   9077  1.1  christos 	result = ISC_R_NOTFOUND;
   9078  1.1  christos 	if (rbtdbiter->nsec3only && !rbtdbiter->nonsec3) {
   9079  1.1  christos 		rbtdbiter->current = &rbtdbiter->nsec3chain;
   9080  1.1  christos 		result = dns_rbtnodechain_last(rbtdbiter->current,
   9081  1.1  christos 					       rbtdb->nsec3, name, origin);
   9082  1.1  christos 	}
   9083  1.1  christos 	if (!rbtdbiter->nsec3only && result == ISC_R_NOTFOUND) {
   9084  1.1  christos 		rbtdbiter->current = &rbtdbiter->chain;
   9085  1.1  christos 		result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->tree,
   9086  1.1  christos 					       name, origin);
   9087  1.1  christos 	}
   9088  1.1  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
   9089  1.1  christos 		result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
   9090  1.1  christos 						  NULL, &rbtdbiter->node);
   9091  1.1  christos 		if (result == ISC_R_SUCCESS) {
   9092  1.3  christos 			rbtdbiter->new_origin = true;
   9093  1.1  christos 			reference_iter_node(rbtdbiter);
   9094  1.1  christos 		}
   9095  1.1  christos 	} else {
   9096  1.1  christos 		INSIST(result == ISC_R_NOTFOUND);
   9097  1.1  christos 		result = ISC_R_NOMORE; /* The tree is empty. */
   9098  1.1  christos 	}
   9099  1.1  christos 
   9100  1.1  christos 	rbtdbiter->result = result;
   9101  1.1  christos 
   9102  1.1  christos 	return (result);
   9103  1.1  christos }
   9104  1.1  christos 
   9105  1.1  christos static isc_result_t
   9106  1.1  christos dbiterator_seek(dns_dbiterator_t *iterator, const dns_name_t *name) {
   9107  1.1  christos 	isc_result_t result, tresult;
   9108  1.1  christos 	rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
   9109  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
   9110  1.1  christos 	dns_name_t *iname, *origin;
   9111  1.1  christos 
   9112  1.1  christos 	if (rbtdbiter->result != ISC_R_SUCCESS &&
   9113  1.1  christos 	    rbtdbiter->result != ISC_R_NOTFOUND &&
   9114  1.1  christos 	    rbtdbiter->result != DNS_R_PARTIALMATCH &&
   9115  1.1  christos 	    rbtdbiter->result != ISC_R_NOMORE)
   9116  1.1  christos 		return (rbtdbiter->result);
   9117  1.1  christos 
   9118  1.1  christos 	if (rbtdbiter->paused)
   9119  1.1  christos 		resume_iteration(rbtdbiter);
   9120  1.1  christos 
   9121  1.1  christos 	dereference_iter_node(rbtdbiter);
   9122  1.1  christos 
   9123  1.1  christos 	iname = dns_fixedname_name(&rbtdbiter->name);
   9124  1.1  christos 	origin = dns_fixedname_name(&rbtdbiter->origin);
   9125  1.1  christos 	dns_rbtnodechain_reset(&rbtdbiter->chain);
   9126  1.1  christos 	dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
   9127  1.1  christos 
   9128  1.1  christos 	if (rbtdbiter->nsec3only) {
   9129  1.1  christos 		rbtdbiter->current = &rbtdbiter->nsec3chain;
   9130  1.1  christos 		result = dns_rbt_findnode(rbtdb->nsec3, name, NULL,
   9131  1.1  christos 					  &rbtdbiter->node,
   9132  1.1  christos 					  rbtdbiter->current,
   9133  1.1  christos 					  DNS_RBTFIND_EMPTYDATA, NULL, NULL);
   9134  1.1  christos 	} else if (rbtdbiter->nonsec3) {
   9135  1.1  christos 		rbtdbiter->current = &rbtdbiter->chain;
   9136  1.1  christos 		result = dns_rbt_findnode(rbtdb->tree, name, NULL,
   9137  1.1  christos 					  &rbtdbiter->node,
   9138  1.1  christos 					  rbtdbiter->current,
   9139  1.1  christos 					  DNS_RBTFIND_EMPTYDATA, NULL, NULL);
   9140  1.1  christos 	} else {
   9141  1.1  christos 		/*
   9142  1.1  christos 		 * Stay on main chain if not found on either chain.
   9143  1.1  christos 		 */
   9144  1.1  christos 		rbtdbiter->current = &rbtdbiter->chain;
   9145  1.1  christos 		result = dns_rbt_findnode(rbtdb->tree, name, NULL,
   9146  1.1  christos 					  &rbtdbiter->node,
   9147  1.1  christos 					  rbtdbiter->current,
   9148  1.1  christos 					  DNS_RBTFIND_EMPTYDATA, NULL, NULL);
   9149  1.1  christos 		if (result == DNS_R_PARTIALMATCH) {
   9150  1.1  christos 			dns_rbtnode_t *node = NULL;
   9151  1.1  christos 			tresult = dns_rbt_findnode(rbtdb->nsec3, name, NULL,
   9152  1.1  christos 						  &node, &rbtdbiter->nsec3chain,
   9153  1.1  christos 						  DNS_RBTFIND_EMPTYDATA,
   9154  1.1  christos 						  NULL, NULL);
   9155  1.1  christos 			if (tresult == ISC_R_SUCCESS) {
   9156  1.1  christos 				rbtdbiter->node = node;
   9157  1.1  christos 				rbtdbiter->current = &rbtdbiter->nsec3chain;
   9158  1.1  christos 				result = tresult;
   9159  1.1  christos 			}
   9160  1.1  christos 		}
   9161  1.1  christos 	}
   9162  1.1  christos 
   9163  1.1  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
   9164  1.1  christos 		tresult = dns_rbtnodechain_current(rbtdbiter->current, iname,
   9165  1.1  christos 						   origin, NULL);
   9166  1.1  christos 		if (tresult == ISC_R_SUCCESS) {
   9167  1.3  christos 			rbtdbiter->new_origin = true;
   9168  1.1  christos 			reference_iter_node(rbtdbiter);
   9169  1.1  christos 		} else {
   9170  1.1  christos 			result = tresult;
   9171  1.1  christos 			rbtdbiter->node = NULL;
   9172  1.1  christos 		}
   9173  1.1  christos 	} else
   9174  1.1  christos 		rbtdbiter->node = NULL;
   9175  1.1  christos 
   9176  1.1  christos 	rbtdbiter->result = (result == DNS_R_PARTIALMATCH) ?
   9177  1.1  christos 			    ISC_R_SUCCESS : result;
   9178  1.1  christos 
   9179  1.1  christos 	return (result);
   9180  1.1  christos }
   9181  1.1  christos 
   9182  1.1  christos static isc_result_t
   9183  1.1  christos dbiterator_prev(dns_dbiterator_t *iterator) {
   9184  1.1  christos 	isc_result_t result;
   9185  1.1  christos 	rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
   9186  1.1  christos 	dns_name_t *name, *origin;
   9187  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
   9188  1.1  christos 
   9189  1.1  christos 	REQUIRE(rbtdbiter->node != NULL);
   9190  1.1  christos 
   9191  1.1  christos 	if (rbtdbiter->result != ISC_R_SUCCESS)
   9192  1.1  christos 		return (rbtdbiter->result);
   9193  1.1  christos 
   9194  1.1  christos 	if (rbtdbiter->paused)
   9195  1.1  christos 		resume_iteration(rbtdbiter);
   9196  1.1  christos 
   9197  1.1  christos 	name = dns_fixedname_name(&rbtdbiter->name);
   9198  1.1  christos 	origin = dns_fixedname_name(&rbtdbiter->origin);
   9199  1.1  christos 	result = dns_rbtnodechain_prev(rbtdbiter->current, name, origin);
   9200  1.1  christos 	if (result == ISC_R_NOMORE && !rbtdbiter->nsec3only &&
   9201  1.1  christos 	    !rbtdbiter->nonsec3 &&
   9202  1.1  christos 	    &rbtdbiter->nsec3chain == rbtdbiter->current) {
   9203  1.1  christos 		rbtdbiter->current = &rbtdbiter->chain;
   9204  1.1  christos 		dns_rbtnodechain_reset(rbtdbiter->current);
   9205  1.1  christos 		result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->tree,
   9206  1.1  christos 					       name, origin);
   9207  1.1  christos 		if (result == ISC_R_NOTFOUND)
   9208  1.1  christos 			result = ISC_R_NOMORE;
   9209  1.1  christos 	}
   9210  1.1  christos 
   9211  1.1  christos 	dereference_iter_node(rbtdbiter);
   9212  1.1  christos 
   9213  1.1  christos 	if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
   9214  1.3  christos 		rbtdbiter->new_origin = (result == DNS_R_NEWORIGIN);
   9215  1.1  christos 		result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
   9216  1.1  christos 						  NULL, &rbtdbiter->node);
   9217  1.1  christos 	}
   9218  1.1  christos 
   9219  1.1  christos 	if (result == ISC_R_SUCCESS)
   9220  1.1  christos 		reference_iter_node(rbtdbiter);
   9221  1.1  christos 
   9222  1.1  christos 	rbtdbiter->result = result;
   9223  1.1  christos 
   9224  1.1  christos 	return (result);
   9225  1.1  christos }
   9226  1.1  christos 
   9227  1.1  christos static isc_result_t
   9228  1.1  christos dbiterator_next(dns_dbiterator_t *iterator) {
   9229  1.1  christos 	isc_result_t result;
   9230  1.1  christos 	rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
   9231  1.1  christos 	dns_name_t *name, *origin;
   9232  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
   9233  1.1  christos 
   9234  1.1  christos 	REQUIRE(rbtdbiter->node != NULL);
   9235  1.1  christos 
   9236  1.1  christos 	if (rbtdbiter->result != ISC_R_SUCCESS)
   9237  1.1  christos 		return (rbtdbiter->result);
   9238  1.1  christos 
   9239  1.1  christos 	if (rbtdbiter->paused)
   9240  1.1  christos 		resume_iteration(rbtdbiter);
   9241  1.1  christos 
   9242  1.1  christos 	name = dns_fixedname_name(&rbtdbiter->name);
   9243  1.1  christos 	origin = dns_fixedname_name(&rbtdbiter->origin);
   9244  1.1  christos 	result = dns_rbtnodechain_next(rbtdbiter->current, name, origin);
   9245  1.1  christos 	if (result == ISC_R_NOMORE && !rbtdbiter->nsec3only &&
   9246  1.1  christos 	    !rbtdbiter->nonsec3 && &rbtdbiter->chain == rbtdbiter->current) {
   9247  1.1  christos 		rbtdbiter->current = &rbtdbiter->nsec3chain;
   9248  1.1  christos 		dns_rbtnodechain_reset(rbtdbiter->current);
   9249  1.1  christos 		result = dns_rbtnodechain_first(rbtdbiter->current,
   9250  1.1  christos 						rbtdb->nsec3, name, origin);
   9251  1.1  christos 		if (result == ISC_R_NOTFOUND)
   9252  1.1  christos 			result = ISC_R_NOMORE;
   9253  1.1  christos 	}
   9254  1.1  christos 
   9255  1.1  christos 	dereference_iter_node(rbtdbiter);
   9256  1.1  christos 
   9257  1.1  christos 	if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
   9258  1.3  christos 		rbtdbiter->new_origin = (result == DNS_R_NEWORIGIN);
   9259  1.1  christos 		result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
   9260  1.1  christos 						  NULL, &rbtdbiter->node);
   9261  1.1  christos 	}
   9262  1.1  christos 	if (result == ISC_R_SUCCESS)
   9263  1.1  christos 		reference_iter_node(rbtdbiter);
   9264  1.1  christos 
   9265  1.1  christos 	rbtdbiter->result = result;
   9266  1.1  christos 
   9267  1.1  christos 	return (result);
   9268  1.1  christos }
   9269  1.1  christos 
   9270  1.1  christos static isc_result_t
   9271  1.1  christos dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
   9272  1.1  christos 		   dns_name_t *name)
   9273  1.1  christos {
   9274  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
   9275  1.1  christos 	rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
   9276  1.1  christos 	dns_rbtnode_t *node = rbtdbiter->node;
   9277  1.1  christos 	isc_result_t result;
   9278  1.1  christos 	dns_name_t *nodename = dns_fixedname_name(&rbtdbiter->name);
   9279  1.1  christos 	dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin);
   9280  1.1  christos 
   9281  1.1  christos 	REQUIRE(rbtdbiter->result == ISC_R_SUCCESS);
   9282  1.1  christos 	REQUIRE(rbtdbiter->node != NULL);
   9283  1.1  christos 
   9284  1.1  christos 	if (rbtdbiter->paused)
   9285  1.1  christos 		resume_iteration(rbtdbiter);
   9286  1.1  christos 
   9287  1.1  christos 	if (name != NULL) {
   9288  1.1  christos 		if (rbtdbiter->common.relative_names)
   9289  1.1  christos 			origin = NULL;
   9290  1.1  christos 		result = dns_name_concatenate(nodename, origin, name, NULL);
   9291  1.1  christos 		if (result != ISC_R_SUCCESS)
   9292  1.1  christos 			return (result);
   9293  1.1  christos 		if (rbtdbiter->common.relative_names && rbtdbiter->new_origin)
   9294  1.1  christos 			result = DNS_R_NEWORIGIN;
   9295  1.1  christos 	} else
   9296  1.1  christos 		result = ISC_R_SUCCESS;
   9297  1.1  christos 
   9298  1.1  christos 	new_reference(rbtdb, node);
   9299  1.1  christos 
   9300  1.1  christos 	*nodep = rbtdbiter->node;
   9301  1.1  christos 
   9302  1.1  christos 	if (iterator->cleaning && result == ISC_R_SUCCESS) {
   9303  1.1  christos 		isc_result_t expire_result;
   9304  1.1  christos 
   9305  1.1  christos 		/*
   9306  1.1  christos 		 * If the deletion array is full, flush it before trying
   9307  1.1  christos 		 * to expire the current node.  The current node can't
   9308  1.1  christos 		 * fully deleted while the iteration cursor is still on it.
   9309  1.1  christos 		 */
   9310  1.1  christos 		if (rbtdbiter->delcnt == DELETION_BATCH_MAX)
   9311  1.1  christos 			flush_deletions(rbtdbiter);
   9312  1.1  christos 
   9313  1.1  christos 		expire_result = expirenode(iterator->db, *nodep, 0);
   9314  1.1  christos 
   9315  1.1  christos 		/*
   9316  1.1  christos 		 * expirenode() currently always returns success.
   9317  1.1  christos 		 */
   9318  1.1  christos 		if (expire_result == ISC_R_SUCCESS && node->down == NULL) {
   9319  1.1  christos 			rbtdbiter->deletions[rbtdbiter->delcnt++] = node;
   9320  1.3  christos 			isc_refcount_increment(&node->references);
   9321  1.1  christos 		}
   9322  1.1  christos 	}
   9323  1.1  christos 
   9324  1.1  christos 	return (result);
   9325  1.1  christos }
   9326  1.1  christos 
   9327  1.1  christos static isc_result_t
   9328  1.1  christos dbiterator_pause(dns_dbiterator_t *iterator) {
   9329  1.1  christos 	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
   9330  1.1  christos 	rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
   9331  1.1  christos 
   9332  1.1  christos 	if (rbtdbiter->result != ISC_R_SUCCESS &&
   9333  1.1  christos 	    rbtdbiter->result != ISC_R_NOTFOUND &&
   9334  1.1  christos 	    rbtdbiter->result != DNS_R_PARTIALMATCH &&
   9335  1.1  christos 	    rbtdbiter->result != ISC_R_NOMORE)
   9336  1.1  christos 		return (rbtdbiter->result);
   9337  1.1  christos 
   9338  1.1  christos 	if (rbtdbiter->paused)
   9339  1.1  christos 		return (ISC_R_SUCCESS);
   9340  1.1  christos 
   9341  1.3  christos 	rbtdbiter->paused = true;
   9342  1.1  christos 
   9343  1.1  christos 	if (rbtdbiter->tree_locked != isc_rwlocktype_none) {
   9344  1.1  christos 		INSIST(rbtdbiter->tree_locked == isc_rwlocktype_read);
   9345  1.1  christos 		RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
   9346  1.1  christos 		rbtdbiter->tree_locked = isc_rwlocktype_none;
   9347  1.1  christos 	}
   9348  1.1  christos 
   9349  1.1  christos 	flush_deletions(rbtdbiter);
   9350  1.1  christos 
   9351  1.1  christos 	return (ISC_R_SUCCESS);
   9352  1.1  christos }
   9353  1.1  christos 
   9354  1.1  christos static isc_result_t
   9355  1.1  christos dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
   9356  1.1  christos 	rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
   9357  1.1  christos 	dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin);
   9358  1.1  christos 
   9359  1.1  christos 	if (rbtdbiter->result != ISC_R_SUCCESS)
   9360  1.1  christos 		return (rbtdbiter->result);
   9361  1.1  christos 
   9362  1.1  christos 	return (dns_name_copy(origin, name, NULL));
   9363  1.1  christos }
   9364  1.1  christos 
   9365  1.1  christos static void
   9366  1.1  christos setownercase(rdatasetheader_t *header, const dns_name_t *name) {
   9367  1.1  christos 	unsigned int i;
   9368  1.3  christos 	bool fully_lower;
   9369  1.1  christos 
   9370  1.1  christos 	/*
   9371  1.1  christos 	 * We do not need to worry about label lengths as they are all
   9372  1.1  christos 	 * less than or equal to 63.
   9373  1.1  christos 	 */
   9374  1.1  christos 	memset(header->upper, 0, sizeof(header->upper));
   9375  1.3  christos 	fully_lower = true;
   9376  1.1  christos 	for (i = 0; i < name->length; i++)
   9377  1.1  christos 		if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a) {
   9378  1.1  christos 			header->upper[i/8] |= 1 << (i%8);
   9379  1.3  christos 			fully_lower = false;
   9380  1.1  christos 		}
   9381  1.1  christos 	header->attributes |= RDATASET_ATTR_CASESET;
   9382  1.1  christos 	if (ISC_LIKELY(fully_lower))
   9383  1.1  christos 		header->attributes |= RDATASET_ATTR_CASEFULLYLOWER;
   9384  1.1  christos }
   9385  1.1  christos 
   9386  1.1  christos static void
   9387  1.1  christos rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
   9388  1.1  christos 	unsigned char *raw = rdataset->private3;        /* RDATASLAB */
   9389  1.1  christos 	rdatasetheader_t *header;
   9390  1.1  christos 
   9391  1.1  christos 	header = (struct rdatasetheader *)(raw - sizeof(*header));
   9392  1.1  christos 	setownercase(header, name);
   9393  1.1  christos }
   9394  1.1  christos 
   9395  1.1  christos static const unsigned char charmask[] = {
   9396  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9397  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9398  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9399  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9400  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9401  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9402  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9403  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9404  1.1  christos 	0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   9405  1.1  christos 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   9406  1.1  christos 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   9407  1.1  christos 	0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
   9408  1.1  christos 	0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   9409  1.1  christos 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   9410  1.1  christos 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   9411  1.1  christos 	0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
   9412  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9413  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9414  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9415  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9416  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9417  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9418  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9419  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9420  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9421  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9422  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9423  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9424  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9425  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9426  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   9427  1.1  christos 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
   9428  1.1  christos };
   9429  1.1  christos 
   9430  1.1  christos static const unsigned char maptolower[] = {
   9431  1.1  christos 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
   9432  1.1  christos 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   9433  1.1  christos 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
   9434  1.1  christos 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   9435  1.1  christos 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
   9436  1.1  christos 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   9437  1.1  christos 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
   9438  1.1  christos 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   9439  1.1  christos 	0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
   9440  1.1  christos 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
   9441  1.1  christos 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
   9442  1.1  christos 	0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
   9443  1.1  christos 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
   9444  1.1  christos 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
   9445  1.1  christos 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
   9446  1.1  christos 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
   9447  1.1  christos 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
   9448  1.1  christos 	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
   9449  1.1  christos 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
   9450  1.1  christos 	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
   9451  1.1  christos 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
   9452  1.1  christos 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
   9453  1.1  christos 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
   9454  1.1  christos 	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
   9455  1.1  christos 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
   9456  1.1  christos 	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
   9457  1.1  christos 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
   9458  1.1  christos 	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
   9459  1.1  christos 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
   9460  1.1  christos 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
   9461  1.1  christos 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
   9462  1.1  christos 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
   9463  1.1  christos };
   9464  1.1  christos 
   9465  1.1  christos static void
   9466  1.1  christos rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
   9467  1.1  christos 	const unsigned char *raw = rdataset->private3;        /* RDATASLAB */
   9468  1.1  christos 	const rdatasetheader_t *header;
   9469  1.1  christos 	unsigned int i, j;
   9470  1.1  christos 	unsigned char bits;
   9471  1.1  christos 	unsigned char c, flip;
   9472  1.1  christos 
   9473  1.1  christos 	header = (const struct rdatasetheader *)(raw - sizeof(*header));
   9474  1.1  christos 
   9475  1.1  christos 	if (!CASESET(header))
   9476  1.1  christos 		return;
   9477  1.1  christos 
   9478  1.1  christos #if 0
   9479  1.1  christos 	/*
   9480  1.1  christos 	 * This was the original code, and is implemented differently in
   9481  1.1  christos 	 * the #else block that follows.
   9482  1.1  christos 	 */
   9483  1.1  christos 	for (i = 0; i < name->length; i++) {
   9484  1.1  christos 		/*
   9485  1.1  christos 		 * Set the case bit if it does not match the recorded bit.
   9486  1.1  christos 		 */
   9487  1.1  christos 		if (name->ndata[i] >= 0x61 && name->ndata[i] <= 0x7a &&
   9488  1.1  christos 		    (header->upper[i/8] & (1 << (i%8))) != 0)
   9489  1.1  christos 			name->ndata[i] &= ~0x20; /* clear the lower case bit */
   9490  1.1  christos 		else if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a &&
   9491  1.1  christos 			 (header->upper[i/8] & (1 << (i%8))) == 0)
   9492  1.1  christos 			name->ndata[i] |= 0x20; /* set the lower case bit */
   9493  1.1  christos 	}
   9494  1.1  christos #else
   9495  1.1  christos 
   9496  1.1  christos 	if (ISC_LIKELY(CASEFULLYLOWER(header))) {
   9497  1.1  christos 		unsigned char *bp, *be;
   9498  1.1  christos 		bp = name->ndata;
   9499  1.1  christos 		be = bp + name->length;
   9500  1.1  christos 
   9501  1.1  christos 		while (bp <= be - 4) {
   9502  1.1  christos 			c = bp[0];
   9503  1.1  christos 			bp[0] = maptolower[c];
   9504  1.1  christos 			c = bp[1];
   9505  1.1  christos 			bp[1] = maptolower[c];
   9506  1.1  christos 			c = bp[2];
   9507  1.1  christos 			bp[2] = maptolower[c];
   9508  1.1  christos 			c = bp[3];
   9509  1.1  christos 			bp[3] = maptolower[c];
   9510  1.1  christos 			bp += 4;
   9511  1.1  christos 		}
   9512  1.1  christos 		while (bp < be) {
   9513  1.1  christos 			c = *bp;
   9514  1.1  christos 			*bp++ = maptolower[c];
   9515  1.1  christos 		}
   9516  1.1  christos 		return;
   9517  1.1  christos 	}
   9518  1.1  christos 
   9519  1.1  christos 	i = 0;
   9520  1.1  christos 	for (j = 0; j < (name->length >> 3); j++) {
   9521  1.1  christos 		unsigned int k;
   9522  1.1  christos 
   9523  1.1  christos 		bits = ~(header->upper[j]);
   9524  1.1  christos 
   9525  1.1  christos 		for (k = 0; k < 8; k++) {
   9526  1.1  christos 			c = name->ndata[i];
   9527  1.1  christos 			flip = (bits & 1) << 5;
   9528  1.1  christos 			flip ^= c;
   9529  1.1  christos 			flip &= charmask[c];
   9530  1.1  christos 			name->ndata[i] ^= flip;
   9531  1.1  christos 
   9532  1.1  christos 			i++;
   9533  1.1  christos 			bits >>= 1;
   9534  1.1  christos 		}
   9535  1.1  christos 	}
   9536  1.1  christos 
   9537  1.1  christos 	if (ISC_UNLIKELY(i == name->length))
   9538  1.1  christos 		return;
   9539  1.1  christos 
   9540  1.1  christos 	bits = ~(header->upper[j]);
   9541  1.1  christos 
   9542  1.1  christos 	for (; i < name->length; i++) {
   9543  1.1  christos 		c = name->ndata[i];
   9544  1.1  christos 		flip = (bits & 1) << 5;
   9545  1.1  christos 		flip ^= c;
   9546  1.1  christos 		flip &= charmask[c];
   9547  1.1  christos 		name->ndata[i] ^= flip;
   9548  1.1  christos 
   9549  1.1  christos 		bits >>= 1;
   9550  1.1  christos 	}
   9551  1.1  christos #endif
   9552  1.1  christos }
   9553  1.1  christos 
   9554  1.1  christos struct rbtdb_glue {
   9555  1.1  christos 	struct rbtdb_glue *next;
   9556  1.1  christos 	dns_fixedname_t fixedname;
   9557  1.1  christos 	dns_rdataset_t rdataset_a;
   9558  1.1  christos 	dns_rdataset_t sigrdataset_a;
   9559  1.1  christos 	dns_rdataset_t rdataset_aaaa;
   9560  1.1  christos 	dns_rdataset_t sigrdataset_aaaa;
   9561  1.1  christos };
   9562  1.1  christos 
   9563  1.1  christos typedef struct {
   9564  1.1  christos 	rbtdb_glue_t *glue_list;
   9565  1.1  christos 	dns_rbtdb_t *rbtdb;
   9566  1.1  christos 	rbtdb_version_t *rbtversion;
   9567  1.1  christos } rbtdb_glue_additionaldata_ctx_t;
   9568  1.1  christos 
   9569  1.1  christos static void
   9570  1.1  christos free_gluelist(rbtdb_glue_t *glue_list, dns_rbtdb_t *rbtdb) {
   9571  1.1  christos 	rbtdb_glue_t *cur, *cur_next;
   9572  1.1  christos 
   9573  1.1  christos 	if (glue_list == (void *) -1)
   9574  1.1  christos 		return;
   9575  1.1  christos 
   9576  1.1  christos 	cur = glue_list;
   9577  1.1  christos 	while (cur != NULL) {
   9578  1.1  christos 		cur_next = cur->next;
   9579  1.1  christos 
   9580  1.1  christos 		if (dns_rdataset_isassociated(&cur->rdataset_a))
   9581  1.1  christos 			dns_rdataset_disassociate(&cur->rdataset_a);
   9582  1.1  christos 		if (dns_rdataset_isassociated(&cur->sigrdataset_a))
   9583  1.1  christos 			dns_rdataset_disassociate(&cur->sigrdataset_a);
   9584  1.1  christos 
   9585  1.1  christos 		if (dns_rdataset_isassociated(&cur->rdataset_aaaa))
   9586  1.1  christos 			dns_rdataset_disassociate(&cur->rdataset_aaaa);
   9587  1.1  christos 		if (dns_rdataset_isassociated(&cur->sigrdataset_aaaa))
   9588  1.1  christos 			dns_rdataset_disassociate(&cur->sigrdataset_aaaa);
   9589  1.1  christos 
   9590  1.1  christos 		dns_rdataset_invalidate(&cur->rdataset_a);
   9591  1.1  christos 		dns_rdataset_invalidate(&cur->sigrdataset_a);
   9592  1.1  christos 		dns_rdataset_invalidate(&cur->rdataset_aaaa);
   9593  1.1  christos 		dns_rdataset_invalidate(&cur->sigrdataset_aaaa);
   9594  1.1  christos 
   9595  1.1  christos 		isc_mem_put(rbtdb->common.mctx, cur, sizeof(*cur));
   9596  1.1  christos 		cur = cur_next;
   9597  1.1  christos 	}
   9598  1.1  christos }
   9599  1.1  christos 
   9600  1.1  christos static void
   9601  1.1  christos free_gluetable(rbtdb_version_t *version) {
   9602  1.1  christos 	dns_rbtdb_t *rbtdb;
   9603  1.1  christos 	size_t i;
   9604  1.1  christos 
   9605  1.1  christos 	RWLOCK(&version->glue_rwlock, isc_rwlocktype_write);
   9606  1.1  christos 
   9607  1.1  christos 	rbtdb = version->rbtdb;
   9608  1.1  christos 
   9609  1.1  christos 	for (i = 0; i < version->glue_table_size; i++) {
   9610  1.1  christos 		rbtdb_glue_table_node_t *cur, *cur_next;
   9611  1.1  christos 
   9612  1.1  christos 		cur = version->glue_table[i];
   9613  1.1  christos 		while (cur != NULL) {
   9614  1.1  christos 			cur_next = cur->next;
   9615  1.3  christos 			/* isc_refcount_decrement(&cur->node->references); */
   9616  1.1  christos 			cur->node = NULL;
   9617  1.1  christos 			free_gluelist(cur->glue_list, rbtdb);
   9618  1.1  christos 			cur->glue_list = NULL;
   9619  1.1  christos 			isc_mem_put(rbtdb->common.mctx, cur, sizeof(*cur));
   9620  1.1  christos 			cur = cur_next;
   9621  1.1  christos 		}
   9622  1.1  christos 		version->glue_table[i] = NULL;
   9623  1.1  christos 	}
   9624  1.1  christos 
   9625  1.1  christos 	isc_mem_put(rbtdb->common.mctx, version->glue_table,
   9626  1.1  christos 		    (sizeof(*version->glue_table) *
   9627  1.1  christos 		     version->glue_table_size));
   9628  1.1  christos 
   9629  1.1  christos 	RWUNLOCK(&version->glue_rwlock, isc_rwlocktype_write);
   9630  1.1  christos }
   9631  1.1  christos 
   9632  1.3  christos static bool
   9633  1.1  christos rehash_gluetable(rbtdb_version_t *version) {
   9634  1.1  christos 	size_t oldsize, i;
   9635  1.1  christos 	rbtdb_glue_table_node_t **oldtable;
   9636  1.1  christos 	rbtdb_glue_table_node_t *gluenode;
   9637  1.1  christos 	rbtdb_glue_table_node_t *nextgluenode;
   9638  1.3  christos 	uint32_t hash;
   9639  1.1  christos 
   9640  1.1  christos 	if (ISC_LIKELY(version->glue_table_nodecount <
   9641  1.1  christos 		       (version->glue_table_size * 3U)))
   9642  1.3  christos 		return (false);
   9643  1.1  christos 
   9644  1.1  christos 	oldsize = version->glue_table_size;
   9645  1.1  christos 	oldtable = version->glue_table;
   9646  1.1  christos 	do {
   9647  1.1  christos 		INSIST((version->glue_table_size * 2 + 1) >
   9648  1.1  christos 		       version->glue_table_size);
   9649  1.1  christos 		version->glue_table_size = version->glue_table_size * 2 + 1;
   9650  1.1  christos 	} while (version->glue_table_nodecount >=
   9651  1.1  christos 		 (version->glue_table_size * 3U));
   9652  1.1  christos 
   9653  1.1  christos 	version->glue_table = (rbtdb_glue_table_node_t **)
   9654  1.1  christos 		isc_mem_get(version->rbtdb->common.mctx,
   9655  1.1  christos 			    (version->glue_table_size *
   9656  1.1  christos 			     sizeof(*version->glue_table)));
   9657  1.1  christos 	if (ISC_UNLIKELY(version->glue_table == NULL)) {
   9658  1.1  christos 		version->glue_table = oldtable;
   9659  1.1  christos 		version->glue_table_size = oldsize;
   9660  1.3  christos 		return (false);
   9661  1.1  christos 	}
   9662  1.1  christos 
   9663  1.1  christos 	for (i = 0; i < version->glue_table_size; i++)
   9664  1.1  christos 		version->glue_table[i] = NULL;
   9665  1.1  christos 
   9666  1.1  christos 	for (i = 0; i < oldsize; i++) {
   9667  1.1  christos 		for (gluenode = oldtable[i];
   9668  1.1  christos 		     gluenode != NULL;
   9669  1.1  christos 		     gluenode = nextgluenode)
   9670  1.1  christos 		{
   9671  1.1  christos 			hash = isc_hash_function(&gluenode->node,
   9672  1.1  christos 						 sizeof(gluenode->node),
   9673  1.3  christos 						 true, NULL) %
   9674  1.1  christos 				version->glue_table_size;
   9675  1.1  christos 			nextgluenode = gluenode->next;
   9676  1.1  christos 			gluenode->next = version->glue_table[hash];
   9677  1.1  christos 			version->glue_table[hash] = gluenode;
   9678  1.1  christos 		}
   9679  1.1  christos 	}
   9680  1.1  christos 
   9681  1.1  christos 	isc_mem_put(version->rbtdb->common.mctx, oldtable,
   9682  1.1  christos 		    oldsize * sizeof(*version->glue_table));
   9683  1.1  christos 
   9684  1.1  christos 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
   9685  1.1  christos 		      DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
   9686  1.1  christos 		      "rehash_gluetable(): "
   9687  1.3  christos 		      "resized glue table from %" PRIu64 " to "
   9688  1.3  christos 		      "%" PRIu64,
   9689  1.3  christos 		      (uint64_t) oldsize,
   9690  1.3  christos 		      (uint64_t) version->glue_table_size);
   9691  1.1  christos 
   9692  1.3  christos 	return (true);
   9693  1.1  christos }
   9694  1.1  christos 
   9695  1.1  christos static isc_result_t
   9696  1.1  christos glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) {
   9697  1.1  christos 	rbtdb_glue_additionaldata_ctx_t *ctx;
   9698  1.1  christos 	isc_result_t result;
   9699  1.1  christos 	dns_fixedname_t fixedname_a;
   9700  1.1  christos 	dns_name_t *name_a = NULL;
   9701  1.1  christos 	dns_rdataset_t rdataset_a, sigrdataset_a;
   9702  1.1  christos 	dns_rbtnode_t *node_a = NULL;
   9703  1.1  christos 	dns_fixedname_t fixedname_aaaa;
   9704  1.1  christos 	dns_name_t *name_aaaa = NULL;
   9705  1.1  christos 	dns_rdataset_t rdataset_aaaa, sigrdataset_aaaa;
   9706  1.1  christos 	dns_rbtnode_t *node_aaaa = NULL;
   9707  1.1  christos 	rbtdb_glue_t *glue = NULL;
   9708  1.1  christos 	dns_name_t *gluename = NULL;
   9709  1.1  christos 
   9710  1.1  christos 	/*
   9711  1.1  christos 	 * NS records want addresses in additional records.
   9712  1.1  christos 	 */
   9713  1.1  christos 	INSIST(qtype == dns_rdatatype_a);
   9714  1.1  christos 
   9715  1.1  christos 	ctx = (rbtdb_glue_additionaldata_ctx_t *) arg;
   9716  1.1  christos 
   9717  1.1  christos 	name_a = dns_fixedname_initname(&fixedname_a);
   9718  1.1  christos 	dns_rdataset_init(&rdataset_a);
   9719  1.1  christos 	dns_rdataset_init(&sigrdataset_a);
   9720  1.1  christos 
   9721  1.1  christos 	name_aaaa = dns_fixedname_initname(&fixedname_aaaa);
   9722  1.1  christos 	dns_rdataset_init(&rdataset_aaaa);
   9723  1.1  christos 	dns_rdataset_init(&sigrdataset_aaaa);
   9724  1.1  christos 
   9725  1.1  christos 	result = zone_find((dns_db_t *) ctx->rbtdb, name, ctx->rbtversion,
   9726  1.1  christos 			   dns_rdatatype_a, DNS_DBFIND_GLUEOK, 0,
   9727  1.1  christos 			   (dns_dbnode_t **) &node_a, name_a,
   9728  1.1  christos 			   &rdataset_a, &sigrdataset_a);
   9729  1.1  christos 	if (result == DNS_R_GLUE) {
   9730  1.1  christos 		glue = isc_mem_get(ctx->rbtdb->common.mctx, sizeof(*glue));
   9731  1.1  christos 		if (glue == NULL) {
   9732  1.1  christos 			result = ISC_R_NOMEMORY;
   9733  1.1  christos 			goto out;
   9734  1.1  christos 		}
   9735  1.1  christos 
   9736  1.1  christos 		gluename = dns_fixedname_initname(&glue->fixedname);
   9737  1.1  christos 		dns_name_copy(name_a, gluename, NULL);
   9738  1.1  christos 
   9739  1.1  christos 		dns_rdataset_init(&glue->rdataset_a);
   9740  1.1  christos 		dns_rdataset_init(&glue->sigrdataset_a);
   9741  1.1  christos 		dns_rdataset_init(&glue->rdataset_aaaa);
   9742  1.1  christos 		dns_rdataset_init(&glue->sigrdataset_aaaa);
   9743  1.1  christos 
   9744  1.1  christos 		dns_rdataset_clone(&rdataset_a, &glue->rdataset_a);
   9745  1.1  christos 		if (dns_rdataset_isassociated(&sigrdataset_a)) {
   9746  1.1  christos 			dns_rdataset_clone(&sigrdataset_a,
   9747  1.1  christos 					   &glue->sigrdataset_a);
   9748  1.1  christos 		}
   9749  1.1  christos 	}
   9750  1.1  christos 
   9751  1.1  christos 	result = zone_find((dns_db_t *) ctx->rbtdb, name, ctx->rbtversion,
   9752  1.1  christos 			   dns_rdatatype_aaaa, DNS_DBFIND_GLUEOK, 0,
   9753  1.1  christos 			   (dns_dbnode_t **) &node_aaaa, name_aaaa,
   9754  1.1  christos 			   &rdataset_aaaa, &sigrdataset_aaaa);
   9755  1.1  christos 	if (result == DNS_R_GLUE) {
   9756  1.1  christos 		if (glue == NULL) {
   9757  1.1  christos 			glue = isc_mem_get(ctx->rbtdb->common.mctx,
   9758  1.1  christos 					   sizeof(*glue));
   9759  1.1  christos 			if (glue == NULL) {
   9760  1.1  christos 				result = ISC_R_NOMEMORY;
   9761  1.1  christos 				goto out;
   9762  1.1  christos 			}
   9763  1.1  christos 
   9764  1.1  christos 			gluename = dns_fixedname_initname(&glue->fixedname);
   9765  1.1  christos 			dns_name_copy(name_aaaa, gluename, NULL);
   9766  1.1  christos 
   9767  1.1  christos 			dns_rdataset_init(&glue->rdataset_a);
   9768  1.1  christos 			dns_rdataset_init(&glue->sigrdataset_a);
   9769  1.1  christos 			dns_rdataset_init(&glue->rdataset_aaaa);
   9770  1.1  christos 			dns_rdataset_init(&glue->sigrdataset_aaaa);
   9771  1.1  christos 		} else {
   9772  1.1  christos 			INSIST(node_a == node_aaaa);
   9773  1.1  christos 			INSIST(dns_name_equal(name_a, name_aaaa));
   9774  1.1  christos 		}
   9775  1.1  christos 
   9776  1.1  christos 		dns_rdataset_clone(&rdataset_aaaa, &glue->rdataset_aaaa);
   9777  1.1  christos 		if (dns_rdataset_isassociated(&sigrdataset_aaaa)) {
   9778  1.1  christos 			dns_rdataset_clone(&sigrdataset_aaaa,
   9779  1.1  christos 					   &glue->sigrdataset_aaaa);
   9780  1.1  christos 		}
   9781  1.1  christos 	}
   9782  1.1  christos 
   9783  1.1  christos 	if (glue != NULL) {
   9784  1.1  christos 		glue->next = ctx->glue_list;
   9785  1.1  christos 		ctx->glue_list = glue;
   9786  1.1  christos 	}
   9787  1.1  christos 
   9788  1.1  christos 	result = ISC_R_SUCCESS;
   9789  1.1  christos 
   9790  1.1  christos out:
   9791  1.1  christos 	if (dns_rdataset_isassociated(&rdataset_a))
   9792  1.1  christos 		rdataset_disassociate(&rdataset_a);
   9793  1.1  christos 	if (dns_rdataset_isassociated(&sigrdataset_a))
   9794  1.1  christos 		rdataset_disassociate(&sigrdataset_a);
   9795  1.1  christos 
   9796  1.1  christos 	if (dns_rdataset_isassociated(&rdataset_aaaa))
   9797  1.1  christos 		rdataset_disassociate(&rdataset_aaaa);
   9798  1.1  christos 	if (dns_rdataset_isassociated(&sigrdataset_aaaa))
   9799  1.1  christos 		rdataset_disassociate(&sigrdataset_aaaa);
   9800  1.1  christos 
   9801  1.1  christos 	if (node_a != NULL)
   9802  1.1  christos 		detachnode((dns_db_t *) ctx->rbtdb, (dns_dbnode_t *) &node_a);
   9803  1.1  christos 	if (node_aaaa != NULL)
   9804  1.1  christos 		detachnode((dns_db_t *) ctx->rbtdb,
   9805  1.1  christos 			   (dns_dbnode_t *) &node_aaaa);
   9806  1.1  christos 
   9807  1.1  christos 	return (result);
   9808  1.1  christos }
   9809  1.1  christos 
   9810  1.1  christos static isc_result_t
   9811  1.3  christos rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
   9812  1.1  christos 		 dns_message_t *msg)
   9813  1.1  christos {
   9814  1.1  christos 	dns_rbtdb_t *rbtdb = rdataset->private1;
   9815  1.1  christos 	dns_rbtnode_t *node = rdataset->private2;
   9816  1.1  christos 	rbtdb_version_t *rbtversion = version;
   9817  1.3  christos 	uint32_t idx;
   9818  1.1  christos 	rbtdb_glue_table_node_t *cur;
   9819  1.3  christos 	bool found = false;
   9820  1.3  christos 	bool restarted = false;
   9821  1.1  christos 	rbtdb_glue_t *ge;
   9822  1.1  christos 	rbtdb_glue_additionaldata_ctx_t ctx;
   9823  1.1  christos 	isc_result_t result;
   9824  1.1  christos 
   9825  1.1  christos 	REQUIRE(rdataset->type == dns_rdatatype_ns);
   9826  1.1  christos 	REQUIRE(rbtdb == rbtversion->rbtdb);
   9827  1.1  christos 	REQUIRE(!IS_CACHE(rbtdb) && !IS_STUB(rbtdb));
   9828  1.1  christos 
   9829  1.1  christos 	/*
   9830  1.1  christos 	 * The glue table cache that forms a part of the DB version
   9831  1.1  christos 	 * structure is not explicitly bounded and there's no cache
   9832  1.1  christos 	 * cleaning. The zone data size itself is an implicit bound.
   9833  1.1  christos 	 *
   9834  1.1  christos 	 * The key into the glue hashtable is the node pointer. This is
   9835  1.1  christos 	 * because the glue hashtable is a property of the DB version,
   9836  1.1  christos 	 * and the glue is keyed for the ownername/NS tuple. We don't
   9837  1.1  christos 	 * bother with using an expensive dns_name_t comparison here as
   9838  1.1  christos 	 * the node pointer is a fixed value that won't change for a DB
   9839  1.1  christos 	 * version and can be compared directly.
   9840  1.1  christos 	 */
   9841  1.3  christos 	idx = isc_hash_function(&node, sizeof(node), true, NULL) %
   9842  1.1  christos 		rbtversion->glue_table_size;
   9843  1.1  christos 
   9844  1.1  christos restart:
   9845  1.1  christos 	/*
   9846  1.1  christos 	 * First, check if we have the additional entries already cached
   9847  1.1  christos 	 * in the glue table.
   9848  1.1  christos 	 */
   9849  1.1  christos 	RWLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_read);
   9850  1.1  christos 
   9851  1.1  christos 	for (cur = rbtversion->glue_table[idx]; cur != NULL; cur = cur->next)
   9852  1.1  christos 		if (cur->node == node)
   9853  1.1  christos 			break;
   9854  1.1  christos 
   9855  1.1  christos 	if (cur == NULL) {
   9856  1.1  christos 		goto no_glue;
   9857  1.1  christos 	}
   9858  1.1  christos 	/*
   9859  1.1  christos 	 * We found a cached result. Add it to the message and
   9860  1.1  christos 	 * return.
   9861  1.1  christos 	 */
   9862  1.3  christos 	found = true;
   9863  1.1  christos 	ge = cur->glue_list;
   9864  1.1  christos 
   9865  1.1  christos 	/*
   9866  1.1  christos 	 * (void *) -1 is a special value that means no glue is
   9867  1.1  christos 	 * present in the zone.
   9868  1.1  christos 	 */
   9869  1.1  christos 	if (ge == (void *) -1) {
   9870  1.1  christos 		if (!restarted && (rbtdb->gluecachestats != NULL)) {
   9871  1.1  christos 			isc_stats_increment
   9872  1.1  christos 				(rbtdb->gluecachestats,
   9873  1.1  christos 				 dns_gluecachestatscounter_hits_absent);
   9874  1.1  christos 		}
   9875  1.1  christos 		goto no_glue;
   9876  1.1  christos 	} else {
   9877  1.1  christos 		if (!restarted && (rbtdb->gluecachestats != NULL)) {
   9878  1.1  christos 			isc_stats_increment
   9879  1.1  christos 				(rbtdb->gluecachestats,
   9880  1.1  christos 				 dns_gluecachestatscounter_hits_present);
   9881  1.1  christos 		}
   9882  1.1  christos 	}
   9883  1.1  christos 
   9884  1.1  christos 	for (; ge != NULL; ge = ge->next) {
   9885  1.1  christos 		isc_buffer_t *buffer = NULL;
   9886  1.1  christos 		dns_name_t *name = NULL;
   9887  1.1  christos 		dns_rdataset_t *rdataset_a = NULL;
   9888  1.1  christos 		dns_rdataset_t *sigrdataset_a = NULL;
   9889  1.1  christos 		dns_rdataset_t *rdataset_aaaa = NULL;
   9890  1.1  christos 		dns_rdataset_t *sigrdataset_aaaa = NULL;
   9891  1.1  christos 		dns_name_t *gluename = dns_fixedname_name(&ge->fixedname);
   9892  1.1  christos 
   9893  1.1  christos 		result = isc_buffer_allocate(msg->mctx, &buffer, 512);
   9894  1.1  christos 		if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
   9895  1.1  christos 			goto no_glue;
   9896  1.1  christos 		}
   9897  1.1  christos 
   9898  1.1  christos 		result = dns_message_gettempname(msg, &name);
   9899  1.1  christos 		if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
   9900  1.1  christos 			isc_buffer_free(&buffer);
   9901  1.1  christos 			goto no_glue;
   9902  1.1  christos 		}
   9903  1.1  christos 
   9904  1.1  christos 		dns_name_copy(gluename, name, buffer);
   9905  1.1  christos 		dns_message_takebuffer(msg, &buffer);
   9906  1.1  christos 
   9907  1.1  christos 		if (dns_rdataset_isassociated(&ge->rdataset_a)) {
   9908  1.1  christos 			result = dns_message_gettemprdataset(msg, &rdataset_a);
   9909  1.1  christos 			if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
   9910  1.1  christos 				dns_message_puttempname(msg, &name);
   9911  1.1  christos 				goto no_glue;
   9912  1.1  christos 			}
   9913  1.1  christos 		}
   9914  1.1  christos 
   9915  1.1  christos 		if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
   9916  1.1  christos 			result = dns_message_gettemprdataset(msg,
   9917  1.1  christos 							     &sigrdataset_a);
   9918  1.1  christos 			if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
   9919  1.1  christos 				if (rdataset_a != NULL) {
   9920  1.1  christos 					dns_message_puttemprdataset(msg,
   9921  1.1  christos 								  &rdataset_a);
   9922  1.1  christos 				}
   9923  1.1  christos 				dns_message_puttempname(msg, &name);
   9924  1.1  christos 				goto no_glue;
   9925  1.1  christos 			}
   9926  1.1  christos 		}
   9927  1.1  christos 
   9928  1.3  christos 		if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
   9929  1.3  christos 			result = dns_message_gettemprdataset(msg,
   9930  1.3  christos 						    &rdataset_aaaa);
   9931  1.3  christos 			if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
   9932  1.3  christos 				dns_message_puttempname(msg, &name);
   9933  1.3  christos 				if (rdataset_a != NULL) {
   9934  1.3  christos 					dns_message_puttemprdataset(msg,
   9935  1.3  christos 						    &rdataset_a);
   9936  1.3  christos 				}
   9937  1.3  christos 				if (sigrdataset_a != NULL) {
   9938  1.3  christos 					dns_message_puttemprdataset(msg,
   9939  1.3  christos 						    &sigrdataset_a);
   9940  1.1  christos 				}
   9941  1.3  christos 				goto no_glue;
   9942  1.1  christos 			}
   9943  1.3  christos 		}
   9944  1.1  christos 
   9945  1.3  christos 		if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
   9946  1.3  christos 			result = dns_message_gettemprdataset(msg,
   9947  1.3  christos 						    &sigrdataset_aaaa);
   9948  1.3  christos 			if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
   9949  1.3  christos 				dns_message_puttempname(msg, &name);
   9950  1.3  christos 				if (rdataset_a != NULL) {
   9951  1.3  christos 					dns_message_puttemprdataset(msg,
   9952  1.3  christos 						    &rdataset_a);
   9953  1.1  christos 				}
   9954  1.3  christos 				if (sigrdataset_a != NULL)
   9955  1.3  christos 					dns_message_puttemprdataset(msg,
   9956  1.3  christos 						    &sigrdataset_a);
   9957  1.3  christos 				if (rdataset_aaaa != NULL)
   9958  1.3  christos 					dns_message_puttemprdataset(msg,
   9959  1.3  christos 						    &rdataset_aaaa);
   9960  1.3  christos 				goto no_glue;
   9961  1.1  christos 			}
   9962  1.1  christos 		}
   9963  1.1  christos 
   9964  1.1  christos 		if (ISC_LIKELY(rdataset_a != NULL)) {
   9965  1.1  christos 			dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
   9966  1.1  christos 			ISC_LIST_APPEND(name->list, rdataset_a, link);
   9967  1.1  christos 		}
   9968  1.1  christos 
   9969  1.1  christos 		if (sigrdataset_a != NULL) {
   9970  1.1  christos 			dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a);
   9971  1.1  christos 			ISC_LIST_APPEND(name->list, sigrdataset_a, link);
   9972  1.1  christos 		}
   9973  1.1  christos 
   9974  1.3  christos 		if (rdataset_aaaa != NULL) {
   9975  1.3  christos 			dns_rdataset_clone(&ge->rdataset_aaaa,
   9976  1.3  christos 					   rdataset_aaaa);
   9977  1.3  christos 			ISC_LIST_APPEND(name->list, rdataset_aaaa,
   9978  1.3  christos 					link);
   9979  1.3  christos 		}
   9980  1.3  christos 		if (sigrdataset_aaaa != NULL) {
   9981  1.3  christos 			dns_rdataset_clone(&ge->sigrdataset_aaaa,
   9982  1.3  christos 					   sigrdataset_aaaa);
   9983  1.3  christos 			ISC_LIST_APPEND(name->list, sigrdataset_aaaa,
   9984  1.3  christos 					link);
   9985  1.1  christos 		}
   9986  1.1  christos 
   9987  1.1  christos 		dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
   9988  1.1  christos 	}
   9989  1.1  christos 
   9990  1.1  christos no_glue:
   9991  1.1  christos 	RWUNLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_read);
   9992  1.1  christos 
   9993  1.1  christos 	if (found) {
   9994  1.1  christos 		return (ISC_R_SUCCESS);
   9995  1.1  christos 	}
   9996  1.1  christos 
   9997  1.1  christos 	if (restarted) {
   9998  1.1  christos 		return (ISC_R_FAILURE);
   9999  1.1  christos 	}
   10000  1.1  christos 
   10001  1.1  christos 	/*
   10002  1.1  christos 	 * No cached glue was found in the table. Cache it and restart
   10003  1.1  christos 	 * this function.
   10004  1.1  christos 	 *
   10005  1.1  christos 	 * Due to the gap between the read lock and the write lock, it's
   10006  1.1  christos 	 * possible that we may cache a duplicate glue table entry, but
   10007  1.1  christos 	 * we don't care.
   10008  1.1  christos 	 */
   10009  1.1  christos 
   10010  1.1  christos 	ctx.glue_list = NULL;
   10011  1.1  christos 	ctx.rbtdb = rbtdb;
   10012  1.1  christos 	ctx.rbtversion = rbtversion;
   10013  1.1  christos 
   10014  1.1  christos 	RWLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_write);
   10015  1.1  christos 
   10016  1.1  christos 	if (ISC_UNLIKELY(rehash_gluetable(rbtversion))) {
   10017  1.1  christos 		idx = isc_hash_function(&node, sizeof(node),
   10018  1.3  christos 					true, NULL) %
   10019  1.1  christos 			rbtversion->glue_table_size;
   10020  1.1  christos 	}
   10021  1.1  christos 
   10022  1.1  christos 	(void)dns_rdataset_additionaldata(rdataset, glue_nsdname_cb, &ctx);
   10023  1.1  christos 
   10024  1.1  christos 	cur = isc_mem_get(rbtdb->common.mctx, sizeof(*cur));
   10025  1.1  christos 	if (cur == NULL) {
   10026  1.1  christos 		result = ISC_R_NOMEMORY;
   10027  1.1  christos 		goto out;
   10028  1.1  christos 	}
   10029  1.1  christos 
   10030  1.1  christos 	/*
   10031  1.1  christos 	 * XXXMUKS: it looks like the dns_dbversion is not destroyed
   10032  1.1  christos 	 * when named is terminated by a keyboard break. This doesn't
   10033  1.1  christos 	 * cleanup the node reference and keeps the process dangling.
   10034  1.1  christos 	 */
   10035  1.3  christos 	/* isc_refcount_increment0(&node->references); */
   10036  1.1  christos 	cur->node = node;
   10037  1.1  christos 
   10038  1.1  christos 	if (ctx.glue_list == NULL) {
   10039  1.1  christos 		/*
   10040  1.1  christos 		 * No glue was found. Cache it so.
   10041  1.1  christos 		 */
   10042  1.1  christos 		cur->glue_list = (void *) -1;
   10043  1.1  christos 		if (rbtdb->gluecachestats != NULL) {
   10044  1.1  christos 			isc_stats_increment
   10045  1.1  christos 				(rbtdb->gluecachestats,
   10046  1.1  christos 				 dns_gluecachestatscounter_inserts_absent);
   10047  1.1  christos 		}
   10048  1.1  christos 	} else {
   10049  1.1  christos 		cur->glue_list = ctx.glue_list;
   10050  1.1  christos 		if (rbtdb->gluecachestats != NULL) {
   10051  1.1  christos 			isc_stats_increment
   10052  1.1  christos 				(rbtdb->gluecachestats,
   10053  1.1  christos 				 dns_gluecachestatscounter_inserts_present);
   10054  1.1  christos 		}
   10055  1.1  christos 	}
   10056  1.1  christos 
   10057  1.1  christos 	cur->next = rbtversion->glue_table[idx];
   10058  1.1  christos 	rbtversion->glue_table[idx] = cur;
   10059  1.1  christos 	rbtversion->glue_table_nodecount++;
   10060  1.1  christos 
   10061  1.1  christos 	result = ISC_R_SUCCESS;
   10062  1.1  christos 
   10063  1.1  christos  out:
   10064  1.1  christos 	RWUNLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_write);
   10065  1.1  christos 
   10066  1.1  christos 	if (result == ISC_R_SUCCESS) {
   10067  1.3  christos 		restarted = true;
   10068  1.1  christos 		goto restart;
   10069  1.1  christos 	}
   10070  1.1  christos 
   10071  1.1  christos 	return (result);
   10072  1.1  christos }
   10073  1.1  christos 
   10074  1.1  christos /*%
   10075  1.1  christos  * Routines for LRU-based cache management.
   10076  1.1  christos  */
   10077  1.1  christos 
   10078  1.1  christos /*%
   10079  1.1  christos  * See if a given cache entry that is being reused needs to be updated
   10080  1.1  christos  * in the LRU-list.  From the LRU management point of view, this function is
   10081  1.1  christos  * expected to return true for almost all cases.  When used with threads,
   10082  1.1  christos  * however, this may cause a non-negligible performance penalty because a
   10083  1.1  christos  * writer lock will have to be acquired before updating the list.
   10084  1.1  christos  * If DNS_RBTDB_LIMITLRUUPDATE is defined to be non 0 at compilation time, this
   10085  1.1  christos  * function returns true if the entry has not been updated for some period of
   10086  1.1  christos  * time.  We differentiate the NS or glue address case and the others since
   10087  1.1  christos  * experiments have shown that the former tends to be accessed relatively
   10088  1.1  christos  * infrequently and the cost of cache miss is higher (e.g., a missing NS records
   10089  1.1  christos  * may cause external queries at a higher level zone, involving more
   10090  1.1  christos  * transactions).
   10091  1.1  christos  *
   10092  1.1  christos  * Caller must hold the node (read or write) lock.
   10093  1.1  christos  */
   10094  1.3  christos static inline bool
   10095  1.1  christos need_headerupdate(rdatasetheader_t *header, isc_stdtime_t now) {
   10096  1.1  christos 	if ((header->attributes &
   10097  1.1  christos 	     (RDATASET_ATTR_NONEXISTENT |
   10098  1.1  christos 	      RDATASET_ATTR_ANCIENT |
   10099  1.1  christos 	      RDATASET_ATTR_ZEROTTL)) != 0)
   10100  1.3  christos 		return (false);
   10101  1.1  christos 
   10102  1.1  christos #if DNS_RBTDB_LIMITLRUUPDATE
   10103  1.1  christos 	if (header->type == dns_rdatatype_ns ||
   10104  1.1  christos 	    (header->trust == dns_trust_glue &&
   10105  1.1  christos 	     (header->type == dns_rdatatype_a ||
   10106  1.1  christos 	      header->type == dns_rdatatype_aaaa))) {
   10107  1.1  christos 		/*
   10108  1.1  christos 		 * Glue records are updated if at least 60 seconds have passed
   10109  1.1  christos 		 * since the previous update time.
   10110  1.1  christos 		 */
   10111  1.1  christos 		return (header->last_used + 60 <= now);
   10112  1.1  christos 	}
   10113  1.1  christos 
   10114  1.1  christos 	/* Other records are updated if 5 minutes have passed. */
   10115  1.1  christos 	return (header->last_used + 300 <= now);
   10116  1.1  christos #else
   10117  1.1  christos 	UNUSED(now);
   10118  1.1  christos 
   10119  1.3  christos 	return (true);
   10120  1.1  christos #endif
   10121  1.1  christos }
   10122  1.1  christos 
   10123  1.1  christos /*%
   10124  1.1  christos  * Update the timestamp of a given cache entry and move it to the head
   10125  1.1  christos  * of the corresponding LRU list.
   10126  1.1  christos  *
   10127  1.1  christos  * Caller must hold the node (write) lock.
   10128  1.1  christos  *
   10129  1.1  christos  * Note that the we do NOT touch the heap here, as the TTL has not changed.
   10130  1.1  christos  */
   10131  1.1  christos static void
   10132  1.1  christos update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
   10133  1.1  christos 	      isc_stdtime_t now)
   10134  1.1  christos {
   10135  1.1  christos 	INSIST(IS_CACHE(rbtdb));
   10136  1.1  christos 
   10137  1.1  christos 	/* To be checked: can we really assume this? XXXMLG */
   10138  1.1  christos 	INSIST(ISC_LINK_LINKED(header, link));
   10139  1.1  christos 
   10140  1.1  christos 	ISC_LIST_UNLINK(rbtdb->rdatasets[header->node->locknum], header, link);
   10141  1.1  christos 	header->last_used = now;
   10142  1.1  christos 	ISC_LIST_PREPEND(rbtdb->rdatasets[header->node->locknum], header, link);
   10143  1.1  christos }
   10144  1.1  christos 
   10145  1.1  christos /*%
   10146  1.1  christos  * Purge some expired and/or stale (i.e. unused for some period) cache entries
   10147  1.1  christos  * under an overmem condition.  To recover from this condition quickly, up to
   10148  1.1  christos  * 2 entries will be purged.  This process is triggered while adding a new
   10149  1.1  christos  * entry, and we specifically avoid purging entries in the same LRU bucket as
   10150  1.1  christos  * the one to which the new entry will belong.  Otherwise, we might purge
   10151  1.1  christos  * entries of the same name of different RR types while adding RRsets from a
   10152  1.1  christos  * single response (consider the case where we're adding A and AAAA glue records
   10153  1.1  christos  * of the same NS name).
   10154  1.1  christos  */
   10155  1.1  christos static void
   10156  1.1  christos overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start,
   10157  1.3  christos 	      isc_stdtime_t now, bool tree_locked)
   10158  1.1  christos {
   10159  1.1  christos 	rdatasetheader_t *header, *header_prev;
   10160  1.1  christos 	unsigned int locknum;
   10161  1.1  christos 	int purgecount = 2;
   10162  1.1  christos 
   10163  1.1  christos 	for (locknum = (locknum_start + 1) % rbtdb->node_lock_count;
   10164  1.1  christos 	     locknum != locknum_start && purgecount > 0;
   10165  1.1  christos 	     locknum = (locknum + 1) % rbtdb->node_lock_count) {
   10166  1.1  christos 		NODE_LOCK(&rbtdb->node_locks[locknum].lock,
   10167  1.1  christos 			  isc_rwlocktype_write);
   10168  1.1  christos 
   10169  1.1  christos 		header = isc_heap_element(rbtdb->heaps[locknum], 1);
   10170  1.1  christos 		if (header && header->rdh_ttl < now - RBTDB_VIRTUAL) {
   10171  1.1  christos 			expire_header(rbtdb, header, tree_locked,
   10172  1.1  christos 				      expire_ttl);
   10173  1.1  christos 			purgecount--;
   10174  1.1  christos 		}
   10175  1.1  christos 
   10176  1.1  christos 		for (header = ISC_LIST_TAIL(rbtdb->rdatasets[locknum]);
   10177  1.1  christos 		     header != NULL && purgecount > 0;
   10178  1.1  christos 		     header = header_prev) {
   10179  1.1  christos 			header_prev = ISC_LIST_PREV(header, link);
   10180  1.1  christos 			/*
   10181  1.1  christos 			 * Unlink the entry at this point to avoid checking it
   10182  1.1  christos 			 * again even if it's currently used someone else and
   10183  1.1  christos 			 * cannot be purged at this moment.  This entry won't be
   10184  1.1  christos 			 * referenced any more (so unlinking is safe) since the
   10185  1.1  christos 			 * TTL was reset to 0.
   10186  1.1  christos 			 */
   10187  1.1  christos 			ISC_LIST_UNLINK(rbtdb->rdatasets[locknum], header,
   10188  1.1  christos 					link);
   10189  1.1  christos 			expire_header(rbtdb, header, tree_locked,
   10190  1.1  christos 				      expire_lru);
   10191  1.1  christos 			purgecount--;
   10192  1.1  christos 		}
   10193  1.1  christos 
   10194  1.1  christos 		NODE_UNLOCK(&rbtdb->node_locks[locknum].lock,
   10195  1.1  christos 				    isc_rwlocktype_write);
   10196  1.1  christos 	}
   10197  1.1  christos }
   10198  1.1  christos 
   10199  1.1  christos static void
   10200  1.1  christos expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
   10201  1.3  christos 	      bool tree_locked, expire_t reason)
   10202  1.1  christos {
   10203  1.1  christos 	set_ttl(rbtdb, header, 0);
   10204  1.1  christos 	mark_header_ancient(rbtdb, header);
   10205  1.1  christos 
   10206  1.1  christos 	/*
   10207  1.1  christos 	 * Caller must hold the node (write) lock.
   10208  1.1  christos 	 */
   10209  1.1  christos 
   10210  1.3  christos 	if (isc_refcount_current(&header->node->references) == 0) {
   10211  1.1  christos 		/*
   10212  1.1  christos 		 * If no one else is using the node, we can clean it up now.
   10213  1.1  christos 		 * We first need to gain a new reference to the node to meet a
   10214  1.1  christos 		 * requirement of decrement_reference().
   10215  1.1  christos 		 */
   10216  1.1  christos 		new_reference(rbtdb, header->node);
   10217  1.1  christos 		decrement_reference(rbtdb, header->node, 0,
   10218  1.1  christos 				    isc_rwlocktype_write,
   10219  1.1  christos 				    tree_locked ? isc_rwlocktype_write :
   10220  1.3  christos 				    isc_rwlocktype_none, false);
   10221  1.1  christos 
   10222  1.1  christos 		if (rbtdb->cachestats == NULL)
   10223  1.1  christos 			return;
   10224  1.1  christos 
   10225  1.1  christos 		switch (reason) {
   10226  1.1  christos 		case expire_ttl:
   10227  1.1  christos 			isc_stats_increment(rbtdb->cachestats,
   10228  1.1  christos 					    dns_cachestatscounter_deletettl);
   10229  1.1  christos 			break;
   10230  1.1  christos 		case expire_lru:
   10231  1.1  christos 			isc_stats_increment(rbtdb->cachestats,
   10232  1.1  christos 					    dns_cachestatscounter_deletelru);
   10233  1.1  christos 			break;
   10234  1.1  christos 		default:
   10235  1.1  christos 			break;
   10236  1.1  christos 		}
   10237  1.1  christos 
   10238  1.1  christos 	}
   10239  1.1  christos }
   10240