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