1 1.1 christos /* 2 1.1 christos * services/cache/rrset.c - Resource record set cache. 3 1.1 christos * 4 1.1 christos * Copyright (c) 2007, NLnet Labs. All rights reserved. 5 1.1 christos * 6 1.1 christos * This software is open source. 7 1.1 christos * 8 1.1 christos * Redistribution and use in source and binary forms, with or without 9 1.1 christos * modification, are permitted provided that the following conditions 10 1.1 christos * are met: 11 1.1 christos * 12 1.1 christos * Redistributions of source code must retain the above copyright notice, 13 1.1 christos * this list of conditions and the following disclaimer. 14 1.1 christos * 15 1.1 christos * Redistributions in binary form must reproduce the above copyright notice, 16 1.1 christos * this list of conditions and the following disclaimer in the documentation 17 1.1 christos * and/or other materials provided with the distribution. 18 1.1 christos * 19 1.1 christos * Neither the name of the NLNET LABS nor the names of its contributors may 20 1.1 christos * be used to endorse or promote products derived from this software without 21 1.1 christos * specific prior written permission. 22 1.1 christos * 23 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 1.1 christos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 1.1 christos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 1.1 christos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 1.1 christos * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 1.1 christos * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 1.1 christos * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 1.1 christos * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 1.1 christos * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 1.1 christos * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 1.1 christos * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 1.1 christos */ 35 1.1 christos 36 1.1 christos /** 37 1.1 christos * \file 38 1.1 christos * 39 1.1 christos * This file contains the rrset cache. 40 1.1 christos */ 41 1.1 christos #include "config.h" 42 1.1 christos #include "services/cache/rrset.h" 43 1.1 christos #include "sldns/rrdef.h" 44 1.1 christos #include "util/storage/slabhash.h" 45 1.1 christos #include "util/config_file.h" 46 1.1 christos #include "util/data/packed_rrset.h" 47 1.1 christos #include "util/data/msgreply.h" 48 1.1.1.5 christos #include "util/data/msgparse.h" 49 1.1.1.6 christos #include "util/data/dname.h" 50 1.1 christos #include "util/regional.h" 51 1.1 christos #include "util/alloc.h" 52 1.1.1.3 christos #include "util/net_help.h" 53 1.1 christos 54 1.1 christos void 55 1.1 christos rrset_markdel(void* key) 56 1.1 christos { 57 1.1 christos struct ub_packed_rrset_key* r = (struct ub_packed_rrset_key*)key; 58 1.1 christos r->id = 0; 59 1.1 christos } 60 1.1 christos 61 1.1 christos struct rrset_cache* rrset_cache_create(struct config_file* cfg, 62 1.1 christos struct alloc_cache* alloc) 63 1.1 christos { 64 1.1 christos size_t slabs = (cfg?cfg->rrset_cache_slabs:HASH_DEFAULT_SLABS); 65 1.1 christos size_t startarray = HASH_DEFAULT_STARTARRAY; 66 1.1 christos size_t maxmem = (cfg?cfg->rrset_cache_size:HASH_DEFAULT_MAXMEM); 67 1.1 christos 68 1.1 christos struct rrset_cache *r = (struct rrset_cache*)slabhash_create(slabs, 69 1.1 christos startarray, maxmem, ub_rrset_sizefunc, ub_rrset_compare, 70 1.1 christos ub_rrset_key_delete, rrset_data_delete, alloc); 71 1.1.1.7 christos if(!r) 72 1.1.1.7 christos return NULL; 73 1.1 christos slabhash_setmarkdel(&r->table, &rrset_markdel); 74 1.1 christos return r; 75 1.1 christos } 76 1.1 christos 77 1.1 christos void rrset_cache_delete(struct rrset_cache* r) 78 1.1 christos { 79 1.1 christos if(!r) 80 1.1 christos return; 81 1.1 christos slabhash_delete(&r->table); 82 1.1 christos /* slabhash delete also does free(r), since table is first in struct*/ 83 1.1 christos } 84 1.1 christos 85 1.1 christos struct rrset_cache* rrset_cache_adjust(struct rrset_cache *r, 86 1.1 christos struct config_file* cfg, struct alloc_cache* alloc) 87 1.1 christos { 88 1.1.1.4 christos if(!r || !cfg || !slabhash_is_size(&r->table, cfg->rrset_cache_size, 89 1.1.1.4 christos cfg->rrset_cache_slabs)) 90 1.1 christos { 91 1.1 christos rrset_cache_delete(r); 92 1.1 christos r = rrset_cache_create(cfg, alloc); 93 1.1 christos } 94 1.1 christos return r; 95 1.1 christos } 96 1.1 christos 97 1.1 christos void 98 1.1 christos rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key, 99 1.1.1.2 christos hashvalue_type hash, rrset_id_type id) 100 1.1 christos { 101 1.1 christos struct lruhash* table = slabhash_gettable(&r->table, hash); 102 1.1 christos /* 103 1.1 christos * This leads to locking problems, deadlocks, if the caller is 104 1.1 christos * holding any other rrset lock. 105 1.1 christos * Because a lookup through the hashtable does: 106 1.1 christos * tablelock -> entrylock (for that entry caller holds) 107 1.1 christos * And this would do 108 1.1 christos * entrylock(already held) -> tablelock 109 1.1 christos * And if two threads do this, it results in deadlock. 110 1.1 christos * So, the caller must not hold entrylock. 111 1.1 christos */ 112 1.1 christos lock_quick_lock(&table->lock); 113 1.1 christos /* we have locked the hash table, the item can still be deleted. 114 1.1 christos * because it could already have been reclaimed, but not yet set id=0. 115 1.1 christos * This is because some lruhash routines have lazy deletion. 116 1.1 christos * so, we must acquire a lock on the item to verify the id != 0. 117 1.1 christos * also, with hash not changed, we are using the right slab. 118 1.1 christos */ 119 1.1 christos lock_rw_rdlock(&key->entry.lock); 120 1.1 christos if(key->id == id && key->entry.hash == hash) { 121 1.1 christos lru_touch(table, &key->entry); 122 1.1 christos } 123 1.1 christos lock_rw_unlock(&key->entry.lock); 124 1.1 christos lock_quick_unlock(&table->lock); 125 1.1 christos } 126 1.1 christos 127 1.1 christos /** see if rrset needs to be updated in the cache */ 128 1.1 christos static int 129 1.1 christos need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns) 130 1.1 christos { 131 1.1 christos struct packed_rrset_data* newd = (struct packed_rrset_data*)nd; 132 1.1 christos struct packed_rrset_data* cached = (struct packed_rrset_data*)cd; 133 1.1.1.6 christos /* o if new data is expired, cached data is better */ 134 1.1.1.8 christos if( TTL_IS_EXPIRED(newd->ttl, timenow) && !TTL_IS_EXPIRED(cached->ttl, timenow)) 135 1.1.1.6 christos return 0; 136 1.1 christos /* o store if rrset has been validated 137 1.1 christos * everything better than bogus data 138 1.1 christos * secure is preferred */ 139 1.1 christos if( newd->security == sec_status_secure && 140 1.1 christos cached->security != sec_status_secure) 141 1.1 christos return 1; 142 1.1 christos if( cached->security == sec_status_bogus && 143 1.1 christos newd->security != sec_status_bogus && !equal) 144 1.1 christos return 1; 145 1.1.1.6 christos /* o if new RRset is more trustworthy - insert it */ 146 1.1 christos if( newd->trust > cached->trust ) { 147 1.1.1.6 christos /* if the cached rrset is bogus, and new is equal, 148 1.1 christos * do not update the TTL - let it expire. */ 149 1.1.1.8 christos if(equal && !TTL_IS_EXPIRED(cached->ttl, timenow) && 150 1.1 christos cached->security == sec_status_bogus) 151 1.1 christos return 0; 152 1.1.1.8 christos /* ghost-domain: never let an NS overwrite extend lifetime 153 1.1.1.8 christos * past the entry it replaces, regardless of trust. */ 154 1.1.1.8 christos if(ns && !TTL_IS_EXPIRED(cached->ttl, timenow) && 155 1.1.1.8 christos newd->ttl > cached->ttl) { 156 1.1.1.8 christos size_t i; 157 1.1.1.8 christos newd->ttl = cached->ttl; 158 1.1.1.8 christos for(i=0; i<(newd->count+newd->rrsig_count); i++) 159 1.1.1.8 christos if(newd->rr_ttl[i] > newd->ttl) 160 1.1.1.8 christos newd->rr_ttl[i] = newd->ttl; 161 1.1.1.8 christos } 162 1.1 christos return 1; 163 1.1 christos } 164 1.1 christos /* o item in cache has expired */ 165 1.1.1.8 christos if( TTL_IS_EXPIRED(cached->ttl, timenow) ) 166 1.1 christos return 1; 167 1.1 christos /* o same trust, but different in data - insert it */ 168 1.1 christos if( newd->trust == cached->trust && !equal ) { 169 1.1 christos /* if this is type NS, do not 'stick' to owner that changes 170 1.1.1.6 christos * the NS RRset, but use the cached TTL for the new data, and 171 1.1 christos * update to fetch the latest data. ttl is not expired, because 172 1.1 christos * that check was before this one. */ 173 1.1 christos if(ns) { 174 1.1 christos size_t i; 175 1.1 christos newd->ttl = cached->ttl; 176 1.1 christos for(i=0; i<(newd->count+newd->rrsig_count); i++) 177 1.1 christos if(newd->rr_ttl[i] > newd->ttl) 178 1.1 christos newd->rr_ttl[i] = newd->ttl; 179 1.1 christos } 180 1.1 christos return 1; 181 1.1 christos } 182 1.1 christos return 0; 183 1.1 christos } 184 1.1 christos 185 1.1 christos /** Update RRSet special key ID */ 186 1.1 christos static void 187 1.1 christos rrset_update_id(struct rrset_ref* ref, struct alloc_cache* alloc) 188 1.1 christos { 189 1.1 christos /* this may clear the cache and invalidate lock below */ 190 1.1 christos uint64_t newid = alloc_get_id(alloc); 191 1.1 christos /* obtain writelock */ 192 1.1 christos lock_rw_wrlock(&ref->key->entry.lock); 193 1.1 christos /* check if it was deleted in the meantime, if so, skip update */ 194 1.1 christos if(ref->key->id == ref->id) { 195 1.1 christos ref->key->id = newid; 196 1.1 christos ref->id = newid; 197 1.1 christos } 198 1.1 christos lock_rw_unlock(&ref->key->entry.lock); 199 1.1 christos } 200 1.1 christos 201 1.1 christos int 202 1.1 christos rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, 203 1.1 christos struct alloc_cache* alloc, time_t timenow) 204 1.1 christos { 205 1.1 christos struct lruhash_entry* e; 206 1.1 christos struct ub_packed_rrset_key* k = ref->key; 207 1.1.1.2 christos hashvalue_type h = k->entry.hash; 208 1.1 christos uint16_t rrset_type = ntohs(k->rk.type); 209 1.1 christos int equal = 0; 210 1.1 christos log_assert(ref->id != 0 && k->id != 0); 211 1.1 christos log_assert(k->rk.dname != NULL); 212 1.1 christos /* looks up item with a readlock - no editing! */ 213 1.1 christos if((e=slabhash_lookup(&r->table, h, k, 0)) != 0) { 214 1.1 christos /* return id and key as they will be used in the cache 215 1.1 christos * since the lruhash_insert, if item already exists, deallocs 216 1.1 christos * the passed key in favor of the already stored key. 217 1.1 christos * because of the small gap (see below) this key ptr and id 218 1.1 christos * may prove later to be already deleted, which is no problem 219 1.1 christos * as it only makes a cache miss. 220 1.1 christos */ 221 1.1 christos ref->key = (struct ub_packed_rrset_key*)e->key; 222 1.1 christos ref->id = ref->key->id; 223 1.1 christos equal = rrsetdata_equal((struct packed_rrset_data*)k->entry. 224 1.1 christos data, (struct packed_rrset_data*)e->data); 225 1.1 christos if(!need_to_update_rrset(k->entry.data, e->data, timenow, 226 1.1 christos equal, (rrset_type==LDNS_RR_TYPE_NS))) { 227 1.1 christos /* cache is superior, return that value */ 228 1.1 christos lock_rw_unlock(&e->lock); 229 1.1 christos ub_packed_rrset_parsedelete(k, alloc); 230 1.1 christos if(equal) return 2; 231 1.1 christos return 1; 232 1.1 christos } 233 1.1 christos lock_rw_unlock(&e->lock); 234 1.1 christos /* Go on and insert the passed item. 235 1.1 christos * small gap here, where entry is not locked. 236 1.1 christos * possibly entry is updated with something else. 237 1.1 christos * we then overwrite that with our data. 238 1.1 christos * this is just too bad, its cache anyway. */ 239 1.1 christos /* use insert to update entry to manage lruhash 240 1.1 christos * cache size values nicely. */ 241 1.1 christos } 242 1.1 christos log_assert(ref->key->id != 0); 243 1.1 christos slabhash_insert(&r->table, h, &k->entry, k->entry.data, alloc); 244 1.1 christos if(e) { 245 1.1 christos /* For NSEC, NSEC3, DNAME, when rdata is updated, update 246 1.1 christos * the ID number so that proofs in message cache are 247 1.1 christos * invalidated */ 248 1.1 christos if((rrset_type == LDNS_RR_TYPE_NSEC 249 1.1 christos || rrset_type == LDNS_RR_TYPE_NSEC3 250 1.1 christos || rrset_type == LDNS_RR_TYPE_DNAME) && !equal) { 251 1.1 christos rrset_update_id(ref, alloc); 252 1.1 christos } 253 1.1 christos return 1; 254 1.1 christos } 255 1.1 christos return 0; 256 1.1 christos } 257 1.1 christos 258 1.1.1.3 christos void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache, 259 1.1.1.3 christos struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len, 260 1.1.1.3 christos struct alloc_cache* alloc, time_t timenow) 261 1.1.1.3 christos { 262 1.1.1.3 christos struct rrset_ref ref; 263 1.1.1.3 christos uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3]; 264 1.1.1.3 christos rrset = packed_rrset_copy_alloc(rrset, alloc, timenow); 265 1.1.1.3 christos if(!rrset) { 266 1.1.1.3 christos log_err("malloc failure in rrset_cache_update_wildcard"); 267 1.1.1.3 christos return; 268 1.1.1.3 christos } 269 1.1.1.3 christos /* ce has at least one label less then qname, we can therefore safely 270 1.1.1.3 christos * add the wildcard label. */ 271 1.1.1.3 christos wc_dname[0] = 1; 272 1.1.1.3 christos wc_dname[1] = (uint8_t)'*'; 273 1.1.1.3 christos memmove(wc_dname+2, ce, ce_len); 274 1.1.1.3 christos 275 1.1.1.3 christos free(rrset->rk.dname); 276 1.1.1.3 christos rrset->rk.dname_len = ce_len + 2; 277 1.1.1.3 christos rrset->rk.dname = (uint8_t*)memdup(wc_dname, rrset->rk.dname_len); 278 1.1.1.3 christos if(!rrset->rk.dname) { 279 1.1.1.3 christos alloc_special_release(alloc, rrset); 280 1.1.1.3 christos log_err("memdup failure in rrset_cache_update_wildcard"); 281 1.1.1.3 christos return; 282 1.1.1.3 christos } 283 1.1.1.3 christos 284 1.1.1.3 christos rrset->entry.hash = rrset_key_hash(&rrset->rk); 285 1.1.1.3 christos ref.key = rrset; 286 1.1.1.3 christos ref.id = rrset->id; 287 1.1.1.3 christos /* ignore ret: if it was in the cache, ref updated */ 288 1.1.1.3 christos (void)rrset_cache_update(rrset_cache, &ref, alloc, timenow); 289 1.1.1.3 christos } 290 1.1.1.3 christos 291 1.1.1.8 christos /** Grace period in seconds for TTL=0 DNAME rrsets (RFC 2308: do not cache). 292 1.1.1.8 christos * Allows synthesis from cache within this window to reduce recursion load. */ 293 1.1.1.8 christos #define DNAME_TTL0_GRACE_SECONDS 1 294 1.1.1.8 christos 295 1.1 christos struct ub_packed_rrset_key* 296 1.1 christos rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen, 297 1.1 christos uint16_t qtype, uint16_t qclass, uint32_t flags, time_t timenow, 298 1.1 christos int wr) 299 1.1 christos { 300 1.1 christos struct lruhash_entry* e; 301 1.1 christos struct ub_packed_rrset_key key; 302 1.1 christos 303 1.1 christos key.entry.key = &key; 304 1.1 christos key.entry.data = NULL; 305 1.1 christos key.rk.dname = qname; 306 1.1 christos key.rk.dname_len = qnamelen; 307 1.1 christos key.rk.type = htons(qtype); 308 1.1 christos key.rk.rrset_class = htons(qclass); 309 1.1 christos key.rk.flags = flags; 310 1.1 christos 311 1.1 christos key.entry.hash = rrset_key_hash(&key.rk); 312 1.1 christos 313 1.1 christos if((e = slabhash_lookup(&r->table, key.entry.hash, &key, wr))) { 314 1.1 christos /* check TTL */ 315 1.1 christos struct packed_rrset_data* data = 316 1.1 christos (struct packed_rrset_data*)e->data; 317 1.1.1.8 christos struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key; 318 1.1.1.8 christos if(TTL_IS_EXPIRED(data->ttl, timenow)) { 319 1.1.1.8 christos /* Allow TTL=0 DNAME within grace period for synthesis */ 320 1.1.1.8 christos if(qtype == LDNS_RR_TYPE_DNAME && 321 1.1.1.8 christos (k->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) && 322 1.1.1.8 christos (timenow - data->ttl_add) <= DNAME_TTL0_GRACE_SECONDS) { 323 1.1.1.8 christos /* within grace: allow for synthesis */ 324 1.1.1.8 christos } else { 325 1.1.1.8 christos lock_rw_unlock(&e->lock); 326 1.1.1.8 christos return NULL; 327 1.1.1.8 christos } 328 1.1 christos } 329 1.1 christos /* we're done */ 330 1.1.1.8 christos return k; 331 1.1 christos } 332 1.1 christos return NULL; 333 1.1 christos } 334 1.1 christos 335 1.1.1.8 christos int 336 1.1 christos rrset_array_lock(struct rrset_ref* ref, size_t count, time_t timenow) 337 1.1 christos { 338 1.1 christos size_t i; 339 1.1.1.8 christos struct packed_rrset_data* d; 340 1.1 christos for(i=0; i<count; i++) { 341 1.1 christos if(i>0 && ref[i].key == ref[i-1].key) 342 1.1 christos continue; /* only lock items once */ 343 1.1 christos lock_rw_rdlock(&ref[i].key->entry.lock); 344 1.1.1.8 christos d = ref[i].key->entry.data; 345 1.1.1.8 christos if(ref[i].id != ref[i].key->id || 346 1.1.1.8 christos TTL_IS_EXPIRED(d->ttl, timenow)) { 347 1.1 christos /* failure! rollback our readlocks */ 348 1.1 christos rrset_array_unlock(ref, i+1); 349 1.1 christos return 0; 350 1.1 christos } 351 1.1 christos } 352 1.1 christos return 1; 353 1.1 christos } 354 1.1 christos 355 1.1 christos void 356 1.1 christos rrset_array_unlock(struct rrset_ref* ref, size_t count) 357 1.1 christos { 358 1.1 christos size_t i; 359 1.1 christos for(i=0; i<count; i++) { 360 1.1 christos if(i>0 && ref[i].key == ref[i-1].key) 361 1.1 christos continue; /* only unlock items once */ 362 1.1 christos lock_rw_unlock(&ref[i].key->entry.lock); 363 1.1 christos } 364 1.1 christos } 365 1.1 christos 366 1.1 christos void 367 1.1 christos rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch, 368 1.1 christos struct rrset_ref* ref, size_t count) 369 1.1 christos { 370 1.1.1.2 christos hashvalue_type* h; 371 1.1 christos size_t i; 372 1.1.1.2 christos if(count > RR_COUNT_MAX || !(h = (hashvalue_type*)regional_alloc( 373 1.1.1.2 christos scratch, sizeof(hashvalue_type)*count))) { 374 1.1 christos log_warn("rrset LRU: memory allocation failed"); 375 1.1 christos h = NULL; 376 1.1 christos } else /* store hash values */ 377 1.1 christos for(i=0; i<count; i++) 378 1.1 christos h[i] = ref[i].key->entry.hash; 379 1.1 christos /* unlock */ 380 1.1 christos for(i=0; i<count; i++) { 381 1.1 christos if(i>0 && ref[i].key == ref[i-1].key) 382 1.1 christos continue; /* only unlock items once */ 383 1.1 christos lock_rw_unlock(&ref[i].key->entry.lock); 384 1.1 christos } 385 1.1 christos if(h) { 386 1.1 christos /* LRU touch, with no rrset locks held */ 387 1.1 christos for(i=0; i<count; i++) { 388 1.1 christos if(i>0 && ref[i].key == ref[i-1].key) 389 1.1 christos continue; /* only touch items once */ 390 1.1 christos rrset_cache_touch(r, ref[i].key, h[i], ref[i].id); 391 1.1 christos } 392 1.1 christos } 393 1.1 christos } 394 1.1 christos 395 1.1 christos void 396 1.1 christos rrset_update_sec_status(struct rrset_cache* r, 397 1.1 christos struct ub_packed_rrset_key* rrset, time_t now) 398 1.1 christos { 399 1.1 christos struct packed_rrset_data* updata = 400 1.1 christos (struct packed_rrset_data*)rrset->entry.data; 401 1.1 christos struct lruhash_entry* e; 402 1.1 christos struct packed_rrset_data* cachedata; 403 1.1 christos 404 1.1 christos /* hash it again to make sure it has a hash */ 405 1.1 christos rrset->entry.hash = rrset_key_hash(&rrset->rk); 406 1.1 christos 407 1.1 christos e = slabhash_lookup(&r->table, rrset->entry.hash, rrset, 1); 408 1.1 christos if(!e) 409 1.1 christos return; /* not in the cache anymore */ 410 1.1 christos cachedata = (struct packed_rrset_data*)e->data; 411 1.1 christos if(!rrsetdata_equal(updata, cachedata)) { 412 1.1 christos lock_rw_unlock(&e->lock); 413 1.1 christos return; /* rrset has changed in the meantime */ 414 1.1 christos } 415 1.1 christos /* update the cached rrset */ 416 1.1 christos if(updata->security > cachedata->security) { 417 1.1 christos size_t i; 418 1.1 christos if(updata->trust > cachedata->trust) 419 1.1 christos cachedata->trust = updata->trust; 420 1.1 christos cachedata->security = updata->security; 421 1.1 christos /* for NS records only shorter TTLs, other types: update it */ 422 1.1 christos if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_NS || 423 1.1 christos updata->ttl+now < cachedata->ttl || 424 1.1 christos cachedata->ttl < now || 425 1.1 christos updata->security == sec_status_bogus) { 426 1.1 christos cachedata->ttl = updata->ttl + now; 427 1.1 christos for(i=0; i<cachedata->count+cachedata->rrsig_count; i++) 428 1.1 christos cachedata->rr_ttl[i] = updata->rr_ttl[i]+now; 429 1.1.1.5 christos cachedata->ttl_add = now; 430 1.1 christos } 431 1.1 christos } 432 1.1 christos lock_rw_unlock(&e->lock); 433 1.1 christos } 434 1.1 christos 435 1.1 christos void 436 1.1 christos rrset_check_sec_status(struct rrset_cache* r, 437 1.1 christos struct ub_packed_rrset_key* rrset, time_t now) 438 1.1 christos { 439 1.1 christos struct packed_rrset_data* updata = 440 1.1 christos (struct packed_rrset_data*)rrset->entry.data; 441 1.1 christos struct lruhash_entry* e; 442 1.1 christos struct packed_rrset_data* cachedata; 443 1.1 christos 444 1.1 christos /* hash it again to make sure it has a hash */ 445 1.1 christos rrset->entry.hash = rrset_key_hash(&rrset->rk); 446 1.1 christos 447 1.1 christos e = slabhash_lookup(&r->table, rrset->entry.hash, rrset, 0); 448 1.1 christos if(!e) 449 1.1 christos return; /* not in the cache anymore */ 450 1.1 christos cachedata = (struct packed_rrset_data*)e->data; 451 1.1 christos if(now > cachedata->ttl || !rrsetdata_equal(updata, cachedata)) { 452 1.1 christos lock_rw_unlock(&e->lock); 453 1.1 christos return; /* expired, or rrset has changed in the meantime */ 454 1.1 christos } 455 1.1 christos if(cachedata->security > updata->security) { 456 1.1 christos updata->security = cachedata->security; 457 1.1 christos if(cachedata->security == sec_status_bogus) { 458 1.1 christos size_t i; 459 1.1 christos updata->ttl = cachedata->ttl - now; 460 1.1 christos for(i=0; i<cachedata->count+cachedata->rrsig_count; i++) 461 1.1 christos if(cachedata->rr_ttl[i] < now) 462 1.1 christos updata->rr_ttl[i] = 0; 463 1.1 christos else updata->rr_ttl[i] = 464 1.1 christos cachedata->rr_ttl[i]-now; 465 1.1 christos } 466 1.1 christos if(cachedata->trust > updata->trust) 467 1.1 christos updata->trust = cachedata->trust; 468 1.1 christos } 469 1.1 christos lock_rw_unlock(&e->lock); 470 1.1 christos } 471 1.1 christos 472 1.1.1.6 christos void 473 1.1.1.6 christos rrset_cache_remove_above(struct rrset_cache* r, uint8_t** qname, size_t* 474 1.1.1.6 christos qnamelen, uint16_t searchtype, uint16_t qclass, time_t now, uint8_t* 475 1.1.1.6 christos qnametop, size_t qnametoplen) 476 1.1.1.6 christos { 477 1.1.1.6 christos struct ub_packed_rrset_key *rrset; 478 1.1.1.6 christos uint8_t lablen; 479 1.1.1.6 christos 480 1.1.1.6 christos while(*qnamelen > 0) { 481 1.1.1.6 christos /* look one label higher */ 482 1.1.1.6 christos lablen = **qname; 483 1.1.1.6 christos *qname += lablen + 1; 484 1.1.1.6 christos *qnamelen -= lablen + 1; 485 1.1.1.6 christos if(*qnamelen <= 0) 486 1.1.1.6 christos return; 487 1.1.1.6 christos 488 1.1.1.6 christos /* stop at qnametop */ 489 1.1.1.6 christos if(qnametop && *qnamelen == qnametoplen && 490 1.1.1.6 christos query_dname_compare(*qname, qnametop)==0) 491 1.1.1.6 christos return; 492 1.1.1.6 christos 493 1.1.1.6 christos if(verbosity >= VERB_ALGO) { 494 1.1.1.6 christos /* looks up with a time of 0, to see expired entries */ 495 1.1.1.6 christos if((rrset = rrset_cache_lookup(r, *qname, 496 1.1.1.6 christos *qnamelen, searchtype, qclass, 0, 0, 0))) { 497 1.1.1.6 christos struct packed_rrset_data* data = 498 1.1.1.6 christos (struct packed_rrset_data*)rrset->entry.data; 499 1.1.1.6 christos int expired = (now > data->ttl); 500 1.1.1.6 christos lock_rw_unlock(&rrset->entry.lock); 501 1.1.1.6 christos if(expired) 502 1.1.1.6 christos log_nametypeclass(verbosity, "this " 503 1.1.1.6 christos "(grand)parent rrset will be " 504 1.1.1.6 christos "removed (expired)", 505 1.1.1.6 christos *qname, searchtype, qclass); 506 1.1.1.6 christos else log_nametypeclass(verbosity, "this " 507 1.1.1.6 christos "(grand)parent rrset will be " 508 1.1.1.6 christos "removed", 509 1.1.1.6 christos *qname, searchtype, qclass); 510 1.1.1.6 christos } 511 1.1.1.6 christos } 512 1.1.1.6 christos rrset_cache_remove(r, *qname, *qnamelen, searchtype, qclass, 0); 513 1.1.1.6 christos } 514 1.1.1.6 christos } 515 1.1.1.6 christos 516 1.1.1.6 christos int 517 1.1.1.6 christos rrset_cache_expired_above(struct rrset_cache* r, uint8_t** qname, size_t* 518 1.1.1.6 christos qnamelen, uint16_t searchtype, uint16_t qclass, time_t now, uint8_t* 519 1.1.1.6 christos qnametop, size_t qnametoplen) 520 1.1.1.6 christos { 521 1.1.1.6 christos struct ub_packed_rrset_key *rrset; 522 1.1.1.6 christos uint8_t lablen; 523 1.1.1.6 christos 524 1.1.1.6 christos while(*qnamelen > 0) { 525 1.1.1.6 christos /* look one label higher */ 526 1.1.1.6 christos lablen = **qname; 527 1.1.1.6 christos *qname += lablen + 1; 528 1.1.1.6 christos *qnamelen -= lablen + 1; 529 1.1.1.6 christos if(*qnamelen <= 0) 530 1.1.1.6 christos break; 531 1.1.1.6 christos 532 1.1.1.6 christos /* looks up with a time of 0, to see expired entries */ 533 1.1.1.6 christos if((rrset = rrset_cache_lookup(r, *qname, 534 1.1.1.6 christos *qnamelen, searchtype, qclass, 0, 0, 0))) { 535 1.1.1.6 christos struct packed_rrset_data* data = 536 1.1.1.6 christos (struct packed_rrset_data*)rrset->entry.data; 537 1.1.1.8 christos if(TTL_IS_EXPIRED(data->ttl, now)) { 538 1.1.1.6 christos /* it is expired, this is not wanted */ 539 1.1.1.6 christos lock_rw_unlock(&rrset->entry.lock); 540 1.1.1.6 christos log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass); 541 1.1.1.6 christos return 1; 542 1.1.1.6 christos } 543 1.1.1.6 christos /* it is not expired, continue looking */ 544 1.1.1.6 christos lock_rw_unlock(&rrset->entry.lock); 545 1.1.1.6 christos } 546 1.1.1.6 christos 547 1.1.1.6 christos /* do not look above the qnametop. */ 548 1.1.1.6 christos if(qnametop && *qnamelen == qnametoplen && 549 1.1.1.6 christos query_dname_compare(*qname, qnametop)==0) 550 1.1.1.6 christos break; 551 1.1.1.6 christos } 552 1.1.1.6 christos return 0; 553 1.1.1.6 christos } 554 1.1.1.6 christos 555 1.1 christos void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen, 556 1.1 christos uint16_t type, uint16_t dclass, uint32_t flags) 557 1.1 christos { 558 1.1 christos struct ub_packed_rrset_key key; 559 1.1 christos key.entry.key = &key; 560 1.1 christos key.rk.dname = nm; 561 1.1 christos key.rk.dname_len = nmlen; 562 1.1 christos key.rk.rrset_class = htons(dclass); 563 1.1 christos key.rk.type = htons(type); 564 1.1 christos key.rk.flags = flags; 565 1.1 christos key.entry.hash = rrset_key_hash(&key.rk); 566 1.1 christos slabhash_remove(&r->table, key.entry.hash, &key); 567 1.1 christos } 568