1238106Sdes/* 2238106Sdes * services/cache/infra.c - infrastructure cache, server rtt and capabilities 3238106Sdes * 4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24238106Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25238106Sdes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26238106Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27238106Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28238106Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29238106Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30238106Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31238106Sdes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32238106Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33238106Sdes * POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains the infrastructure cache. 40238106Sdes */ 41238106Sdes#include "config.h" 42238106Sdes#include <ldns/rr.h> 43238106Sdes#include "services/cache/infra.h" 44238106Sdes#include "util/storage/slabhash.h" 45238106Sdes#include "util/storage/lookup3.h" 46238106Sdes#include "util/data/dname.h" 47238106Sdes#include "util/log.h" 48238106Sdes#include "util/net_help.h" 49238106Sdes#include "util/config_file.h" 50238106Sdes#include "iterator/iterator.h" 51238106Sdes 52238106Sdes/** Timeout when only a single probe query per IP is allowed. */ 53238106Sdes#define PROBE_MAXRTO 12000 /* in msec */ 54238106Sdes 55238106Sdes/** number of timeouts for a type when the domain can be blocked ; 56238106Sdes * even if another type has completely rtt maxed it, the different type 57238106Sdes * can do this number of packets (until those all timeout too) */ 58238106Sdes#define TIMEOUT_COUNT_MAX 3 59238106Sdes 60238106Sdessize_t 61238106Sdesinfra_sizefunc(void* k, void* ATTR_UNUSED(d)) 62238106Sdes{ 63238106Sdes struct infra_key* key = (struct infra_key*)k; 64238106Sdes return sizeof(*key) + sizeof(struct infra_data) + key->namelen 65238106Sdes + lock_get_mem(&key->entry.lock); 66238106Sdes} 67238106Sdes 68238106Sdesint 69238106Sdesinfra_compfunc(void* key1, void* key2) 70238106Sdes{ 71238106Sdes struct infra_key* k1 = (struct infra_key*)key1; 72238106Sdes struct infra_key* k2 = (struct infra_key*)key2; 73238106Sdes int r = sockaddr_cmp(&k1->addr, k1->addrlen, &k2->addr, k2->addrlen); 74238106Sdes if(r != 0) 75238106Sdes return r; 76238106Sdes if(k1->namelen != k2->namelen) { 77238106Sdes if(k1->namelen < k2->namelen) 78238106Sdes return -1; 79238106Sdes return 1; 80238106Sdes } 81238106Sdes return query_dname_compare(k1->zonename, k2->zonename); 82238106Sdes} 83238106Sdes 84238106Sdesvoid 85238106Sdesinfra_delkeyfunc(void* k, void* ATTR_UNUSED(arg)) 86238106Sdes{ 87238106Sdes struct infra_key* key = (struct infra_key*)k; 88238106Sdes if(!key) 89238106Sdes return; 90238106Sdes lock_rw_destroy(&key->entry.lock); 91238106Sdes free(key->zonename); 92238106Sdes free(key); 93238106Sdes} 94238106Sdes 95238106Sdesvoid 96238106Sdesinfra_deldatafunc(void* d, void* ATTR_UNUSED(arg)) 97238106Sdes{ 98238106Sdes struct infra_data* data = (struct infra_data*)d; 99238106Sdes free(data); 100238106Sdes} 101238106Sdes 102238106Sdesstruct infra_cache* 103238106Sdesinfra_create(struct config_file* cfg) 104238106Sdes{ 105238106Sdes struct infra_cache* infra = (struct infra_cache*)calloc(1, 106238106Sdes sizeof(struct infra_cache)); 107238106Sdes size_t maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+ 108238106Sdes sizeof(struct infra_data)+INFRA_BYTES_NAME); 109238106Sdes infra->hosts = slabhash_create(cfg->infra_cache_slabs, 110238106Sdes INFRA_HOST_STARTSIZE, maxmem, &infra_sizefunc, &infra_compfunc, 111238106Sdes &infra_delkeyfunc, &infra_deldatafunc, NULL); 112238106Sdes if(!infra->hosts) { 113238106Sdes free(infra); 114238106Sdes return NULL; 115238106Sdes } 116238106Sdes infra->host_ttl = cfg->host_ttl; 117238106Sdes return infra; 118238106Sdes} 119238106Sdes 120238106Sdesvoid 121238106Sdesinfra_delete(struct infra_cache* infra) 122238106Sdes{ 123238106Sdes if(!infra) 124238106Sdes return; 125238106Sdes slabhash_delete(infra->hosts); 126238106Sdes free(infra); 127238106Sdes} 128238106Sdes 129238106Sdesstruct infra_cache* 130238106Sdesinfra_adjust(struct infra_cache* infra, struct config_file* cfg) 131238106Sdes{ 132238106Sdes size_t maxmem; 133238106Sdes if(!infra) 134238106Sdes return infra_create(cfg); 135238106Sdes infra->host_ttl = cfg->host_ttl; 136238106Sdes maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+ 137238106Sdes sizeof(struct infra_data)+INFRA_BYTES_NAME); 138238106Sdes if(maxmem != slabhash_get_size(infra->hosts) || 139238106Sdes cfg->infra_cache_slabs != infra->hosts->size) { 140238106Sdes infra_delete(infra); 141238106Sdes infra = infra_create(cfg); 142238106Sdes } 143238106Sdes return infra; 144238106Sdes} 145238106Sdes 146238106Sdes/** calculate the hash value for a host key */ 147238106Sdesstatic hashvalue_t 148238106Sdeshash_addr(struct sockaddr_storage* addr, socklen_t addrlen) 149238106Sdes{ 150238106Sdes hashvalue_t h = 0xab; 151238106Sdes /* select the pieces to hash, some OS have changing data inside */ 152238106Sdes if(addr_is_ip6(addr, addrlen)) { 153238106Sdes struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr; 154238106Sdes h = hashlittle(&in6->sin6_family, sizeof(in6->sin6_family), h); 155238106Sdes h = hashlittle(&in6->sin6_port, sizeof(in6->sin6_port), h); 156238106Sdes h = hashlittle(&in6->sin6_addr, INET6_SIZE, h); 157238106Sdes } else { 158238106Sdes struct sockaddr_in* in = (struct sockaddr_in*)addr; 159238106Sdes h = hashlittle(&in->sin_family, sizeof(in->sin_family), h); 160238106Sdes h = hashlittle(&in->sin_port, sizeof(in->sin_port), h); 161238106Sdes h = hashlittle(&in->sin_addr, INET_SIZE, h); 162238106Sdes } 163238106Sdes return h; 164238106Sdes} 165238106Sdes 166238106Sdes/** calculate infra hash for a key */ 167238106Sdesstatic hashvalue_t 168238106Sdeshash_infra(struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name) 169238106Sdes{ 170238106Sdes return dname_query_hash(name, hash_addr(addr, addrlen)); 171238106Sdes} 172238106Sdes 173238106Sdes/** lookup version that does not check host ttl (you check it) */ 174238106Sdesstruct lruhash_entry* 175238106Sdesinfra_lookup_nottl(struct infra_cache* infra, struct sockaddr_storage* addr, 176238106Sdes socklen_t addrlen, uint8_t* name, size_t namelen, int wr) 177238106Sdes{ 178238106Sdes struct infra_key k; 179238106Sdes k.addrlen = addrlen; 180238106Sdes memcpy(&k.addr, addr, addrlen); 181238106Sdes k.namelen = namelen; 182238106Sdes k.zonename = name; 183238106Sdes k.entry.hash = hash_infra(addr, addrlen, name); 184238106Sdes k.entry.key = (void*)&k; 185238106Sdes k.entry.data = NULL; 186238106Sdes return slabhash_lookup(infra->hosts, k.entry.hash, &k, wr); 187238106Sdes} 188238106Sdes 189238106Sdes/** init the data elements */ 190238106Sdesstatic void 191238106Sdesdata_entry_init(struct infra_cache* infra, struct lruhash_entry* e, 192238106Sdes uint32_t timenow) 193238106Sdes{ 194238106Sdes struct infra_data* data = (struct infra_data*)e->data; 195238106Sdes data->ttl = timenow + infra->host_ttl; 196238106Sdes rtt_init(&data->rtt); 197238106Sdes data->edns_version = 0; 198238106Sdes data->edns_lame_known = 0; 199238106Sdes data->probedelay = 0; 200238106Sdes data->isdnsseclame = 0; 201238106Sdes data->rec_lame = 0; 202238106Sdes data->lame_type_A = 0; 203238106Sdes data->lame_other = 0; 204238106Sdes data->timeout_A = 0; 205238106Sdes data->timeout_AAAA = 0; 206238106Sdes data->timeout_other = 0; 207238106Sdes} 208238106Sdes 209238106Sdes/** 210238106Sdes * Create and init a new entry for a host 211238106Sdes * @param infra: infra structure with config parameters. 212238106Sdes * @param addr: host address. 213238106Sdes * @param addrlen: length of addr. 214238106Sdes * @param name: name of zone 215238106Sdes * @param namelen: length of name. 216238106Sdes * @param tm: time now. 217238106Sdes * @return: the new entry or NULL on malloc failure. 218238106Sdes */ 219238106Sdesstatic struct lruhash_entry* 220238106Sdesnew_entry(struct infra_cache* infra, struct sockaddr_storage* addr, 221238106Sdes socklen_t addrlen, uint8_t* name, size_t namelen, uint32_t tm) 222238106Sdes{ 223238106Sdes struct infra_data* data; 224238106Sdes struct infra_key* key = (struct infra_key*)malloc(sizeof(*key)); 225238106Sdes if(!key) 226238106Sdes return NULL; 227238106Sdes data = (struct infra_data*)malloc(sizeof(struct infra_data)); 228238106Sdes if(!data) { 229238106Sdes free(key); 230238106Sdes return NULL; 231238106Sdes } 232238106Sdes key->zonename = memdup(name, namelen); 233238106Sdes if(!key->zonename) { 234238106Sdes free(key); 235238106Sdes free(data); 236238106Sdes return NULL; 237238106Sdes } 238238106Sdes key->namelen = namelen; 239238106Sdes lock_rw_init(&key->entry.lock); 240238106Sdes key->entry.hash = hash_infra(addr, addrlen, name); 241238106Sdes key->entry.key = (void*)key; 242238106Sdes key->entry.data = (void*)data; 243238106Sdes key->addrlen = addrlen; 244238106Sdes memcpy(&key->addr, addr, addrlen); 245238106Sdes data_entry_init(infra, &key->entry, tm); 246238106Sdes return &key->entry; 247238106Sdes} 248238106Sdes 249238106Sdesint 250238106Sdesinfra_host(struct infra_cache* infra, struct sockaddr_storage* addr, 251238106Sdes socklen_t addrlen, uint8_t* nm, size_t nmlen, uint32_t timenow, 252238106Sdes int* edns_vs, uint8_t* edns_lame_known, int* to) 253238106Sdes{ 254238106Sdes struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 255238106Sdes nm, nmlen, 0); 256238106Sdes struct infra_data* data; 257238106Sdes int wr = 0; 258238106Sdes if(e && ((struct infra_data*)e->data)->ttl < timenow) { 259238106Sdes /* it expired, try to reuse existing entry */ 260238106Sdes int old = ((struct infra_data*)e->data)->rtt.rto; 261238106Sdes uint8_t tA = ((struct infra_data*)e->data)->timeout_A; 262238106Sdes uint8_t tAAAA = ((struct infra_data*)e->data)->timeout_AAAA; 263238106Sdes uint8_t tother = ((struct infra_data*)e->data)->timeout_other; 264238106Sdes lock_rw_unlock(&e->lock); 265238106Sdes e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); 266238106Sdes if(e) { 267238106Sdes /* if its still there we have a writelock, init */ 268238106Sdes /* re-initialise */ 269238106Sdes /* do not touch lameness, it may be valid still */ 270238106Sdes data_entry_init(infra, e, timenow); 271238106Sdes wr = 1; 272238106Sdes /* TOP_TIMEOUT remains on reuse */ 273238106Sdes if(old >= USEFUL_SERVER_TOP_TIMEOUT) { 274238106Sdes ((struct infra_data*)e->data)->rtt.rto 275238106Sdes = USEFUL_SERVER_TOP_TIMEOUT; 276238106Sdes ((struct infra_data*)e->data)->timeout_A = tA; 277238106Sdes ((struct infra_data*)e->data)->timeout_AAAA = tAAAA; 278238106Sdes ((struct infra_data*)e->data)->timeout_other = tother; 279238106Sdes } 280238106Sdes } 281238106Sdes } 282238106Sdes if(!e) { 283238106Sdes /* insert new entry */ 284238106Sdes if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) 285238106Sdes return 0; 286238106Sdes data = (struct infra_data*)e->data; 287238106Sdes *edns_vs = data->edns_version; 288238106Sdes *edns_lame_known = data->edns_lame_known; 289238106Sdes *to = rtt_timeout(&data->rtt); 290238106Sdes slabhash_insert(infra->hosts, e->hash, e, data, NULL); 291238106Sdes return 1; 292238106Sdes } 293238106Sdes /* use existing entry */ 294238106Sdes data = (struct infra_data*)e->data; 295238106Sdes *edns_vs = data->edns_version; 296238106Sdes *edns_lame_known = data->edns_lame_known; 297238106Sdes *to = rtt_timeout(&data->rtt); 298238106Sdes if(*to >= PROBE_MAXRTO && rtt_notimeout(&data->rtt)*4 <= *to) { 299238106Sdes /* delay other queries, this is the probe query */ 300238106Sdes if(!wr) { 301238106Sdes lock_rw_unlock(&e->lock); 302238106Sdes e = infra_lookup_nottl(infra, addr,addrlen,nm,nmlen, 1); 303238106Sdes if(!e) { /* flushed from cache real fast, no use to 304238106Sdes allocate just for the probedelay */ 305238106Sdes return 1; 306238106Sdes } 307238106Sdes data = (struct infra_data*)e->data; 308238106Sdes } 309238106Sdes /* add 999 to round up the timeout value from msec to sec, 310238106Sdes * then add a whole second so it is certain that this probe 311238106Sdes * has timed out before the next is allowed */ 312238106Sdes data->probedelay = timenow + ((*to)+1999)/1000; 313238106Sdes } 314238106Sdes lock_rw_unlock(&e->lock); 315238106Sdes return 1; 316238106Sdes} 317238106Sdes 318238106Sdesint 319238106Sdesinfra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr, 320238106Sdes socklen_t addrlen, uint8_t* nm, size_t nmlen, uint32_t timenow, 321238106Sdes int dnsseclame, int reclame, uint16_t qtype) 322238106Sdes{ 323238106Sdes struct infra_data* data; 324238106Sdes struct lruhash_entry* e; 325238106Sdes int needtoinsert = 0; 326238106Sdes e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); 327238106Sdes if(!e) { 328238106Sdes /* insert it */ 329238106Sdes if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) { 330238106Sdes log_err("set_lame: malloc failure"); 331238106Sdes return 0; 332238106Sdes } 333238106Sdes needtoinsert = 1; 334238106Sdes } else if( ((struct infra_data*)e->data)->ttl < timenow) { 335238106Sdes /* expired, reuse existing entry */ 336238106Sdes data_entry_init(infra, e, timenow); 337238106Sdes } 338238106Sdes /* got an entry, now set the zone lame */ 339238106Sdes data = (struct infra_data*)e->data; 340238106Sdes /* merge data (if any) */ 341238106Sdes if(dnsseclame) 342238106Sdes data->isdnsseclame = 1; 343238106Sdes if(reclame) 344238106Sdes data->rec_lame = 1; 345238106Sdes if(!dnsseclame && !reclame && qtype == LDNS_RR_TYPE_A) 346238106Sdes data->lame_type_A = 1; 347238106Sdes if(!dnsseclame && !reclame && qtype != LDNS_RR_TYPE_A) 348238106Sdes data->lame_other = 1; 349238106Sdes /* done */ 350238106Sdes if(needtoinsert) 351238106Sdes slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); 352238106Sdes else { lock_rw_unlock(&e->lock); } 353238106Sdes return 1; 354238106Sdes} 355238106Sdes 356238106Sdesvoid 357238106Sdesinfra_update_tcp_works(struct infra_cache* infra, 358238106Sdes struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, 359238106Sdes size_t nmlen) 360238106Sdes{ 361238106Sdes struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 362238106Sdes nm, nmlen, 1); 363238106Sdes struct infra_data* data; 364238106Sdes if(!e) 365238106Sdes return; /* doesn't exist */ 366238106Sdes data = (struct infra_data*)e->data; 367238106Sdes if(data->rtt.rto >= RTT_MAX_TIMEOUT) 368238106Sdes /* do not disqualify this server altogether, it is better 369238106Sdes * than nothing */ 370238106Sdes data->rtt.rto = RTT_MAX_TIMEOUT-1000; 371238106Sdes lock_rw_unlock(&e->lock); 372238106Sdes} 373238106Sdes 374238106Sdesint 375238106Sdesinfra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, 376238106Sdes socklen_t addrlen, uint8_t* nm, size_t nmlen, int qtype, 377238106Sdes int roundtrip, int orig_rtt, uint32_t timenow) 378238106Sdes{ 379238106Sdes struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 380238106Sdes nm, nmlen, 1); 381238106Sdes struct infra_data* data; 382238106Sdes int needtoinsert = 0; 383238106Sdes int rto = 1; 384238106Sdes if(!e) { 385238106Sdes if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) 386238106Sdes return 0; 387238106Sdes needtoinsert = 1; 388238106Sdes } else if(((struct infra_data*)e->data)->ttl < timenow) { 389238106Sdes data_entry_init(infra, e, timenow); 390238106Sdes } 391238106Sdes /* have an entry, update the rtt */ 392238106Sdes data = (struct infra_data*)e->data; 393238106Sdes if(roundtrip == -1) { 394238106Sdes rtt_lost(&data->rtt, orig_rtt); 395238106Sdes if(qtype == LDNS_RR_TYPE_A) { 396238106Sdes if(data->timeout_A < TIMEOUT_COUNT_MAX) 397238106Sdes data->timeout_A++; 398238106Sdes } else if(qtype == LDNS_RR_TYPE_AAAA) { 399238106Sdes if(data->timeout_AAAA < TIMEOUT_COUNT_MAX) 400238106Sdes data->timeout_AAAA++; 401238106Sdes } else { 402238106Sdes if(data->timeout_other < TIMEOUT_COUNT_MAX) 403238106Sdes data->timeout_other++; 404238106Sdes } 405238106Sdes } else { 406249141Sdes /* if we got a reply, but the old timeout was above server 407249141Sdes * selection height, delete the timeout so the server is 408249141Sdes * fully available again */ 409249141Sdes if(rtt_unclamped(&data->rtt) >= USEFUL_SERVER_TOP_TIMEOUT) 410249141Sdes rtt_init(&data->rtt); 411238106Sdes rtt_update(&data->rtt, roundtrip); 412238106Sdes data->probedelay = 0; 413238106Sdes if(qtype == LDNS_RR_TYPE_A) 414238106Sdes data->timeout_A = 0; 415238106Sdes else if(qtype == LDNS_RR_TYPE_AAAA) 416238106Sdes data->timeout_AAAA = 0; 417238106Sdes else data->timeout_other = 0; 418238106Sdes } 419238106Sdes if(data->rtt.rto > 0) 420238106Sdes rto = data->rtt.rto; 421238106Sdes 422238106Sdes if(needtoinsert) 423238106Sdes slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); 424238106Sdes else { lock_rw_unlock(&e->lock); } 425238106Sdes return rto; 426238106Sdes} 427238106Sdes 428238106Sdesint infra_get_host_rto(struct infra_cache* infra, 429238106Sdes struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, 430238106Sdes size_t nmlen, struct rtt_info* rtt, int* delay, uint32_t timenow, 431238106Sdes int* tA, int* tAAAA, int* tother) 432238106Sdes{ 433238106Sdes struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 434238106Sdes nm, nmlen, 0); 435238106Sdes struct infra_data* data; 436238106Sdes int ttl = -2; 437238106Sdes if(!e) return -1; 438238106Sdes data = (struct infra_data*)e->data; 439238106Sdes if(data->ttl >= timenow) { 440238106Sdes ttl = (int)(data->ttl - timenow); 441238106Sdes memmove(rtt, &data->rtt, sizeof(*rtt)); 442238106Sdes if(timenow < data->probedelay) 443238106Sdes *delay = (int)(data->probedelay - timenow); 444238106Sdes else *delay = 0; 445238106Sdes } 446238106Sdes *tA = (int)data->timeout_A; 447238106Sdes *tAAAA = (int)data->timeout_AAAA; 448238106Sdes *tother = (int)data->timeout_other; 449238106Sdes lock_rw_unlock(&e->lock); 450238106Sdes return ttl; 451238106Sdes} 452238106Sdes 453238106Sdesint 454238106Sdesinfra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr, 455238106Sdes socklen_t addrlen, uint8_t* nm, size_t nmlen, int edns_version, 456238106Sdes uint32_t timenow) 457238106Sdes{ 458238106Sdes struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 459238106Sdes nm, nmlen, 1); 460238106Sdes struct infra_data* data; 461238106Sdes int needtoinsert = 0; 462238106Sdes if(!e) { 463238106Sdes if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) 464238106Sdes return 0; 465238106Sdes needtoinsert = 1; 466238106Sdes } else if(((struct infra_data*)e->data)->ttl < timenow) { 467238106Sdes data_entry_init(infra, e, timenow); 468238106Sdes } 469238106Sdes /* have an entry, update the rtt, and the ttl */ 470238106Sdes data = (struct infra_data*)e->data; 471238106Sdes /* do not update if noEDNS and stored is yesEDNS */ 472238106Sdes if(!(edns_version == -1 && (data->edns_version != -1 && 473238106Sdes data->edns_lame_known))) { 474238106Sdes data->edns_version = edns_version; 475238106Sdes data->edns_lame_known = 1; 476238106Sdes } 477238106Sdes 478238106Sdes if(needtoinsert) 479238106Sdes slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); 480238106Sdes else { lock_rw_unlock(&e->lock); } 481238106Sdes return 1; 482238106Sdes} 483238106Sdes 484238106Sdesint 485238106Sdesinfra_get_lame_rtt(struct infra_cache* infra, 486238106Sdes struct sockaddr_storage* addr, socklen_t addrlen, 487238106Sdes uint8_t* name, size_t namelen, uint16_t qtype, 488238106Sdes int* lame, int* dnsseclame, int* reclame, int* rtt, uint32_t timenow) 489238106Sdes{ 490238106Sdes struct infra_data* host; 491238106Sdes struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 492238106Sdes name, namelen, 0); 493238106Sdes if(!e) 494238106Sdes return 0; 495238106Sdes host = (struct infra_data*)e->data; 496238106Sdes *rtt = rtt_unclamped(&host->rtt); 497238106Sdes if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay 498238106Sdes && rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) { 499238106Sdes /* single probe for this domain, and we are not probing */ 500238106Sdes /* unless the query type allows a probe to happen */ 501238106Sdes if(qtype == LDNS_RR_TYPE_A) { 502238106Sdes if(host->timeout_A >= TIMEOUT_COUNT_MAX) 503238106Sdes *rtt = USEFUL_SERVER_TOP_TIMEOUT; 504238106Sdes else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; 505238106Sdes } else if(qtype == LDNS_RR_TYPE_AAAA) { 506238106Sdes if(host->timeout_AAAA >= TIMEOUT_COUNT_MAX) 507238106Sdes *rtt = USEFUL_SERVER_TOP_TIMEOUT; 508238106Sdes else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; 509238106Sdes } else { 510238106Sdes if(host->timeout_other >= TIMEOUT_COUNT_MAX) 511238106Sdes *rtt = USEFUL_SERVER_TOP_TIMEOUT; 512238106Sdes else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; 513238106Sdes } 514238106Sdes } 515238106Sdes if(timenow > host->ttl) { 516238106Sdes /* expired entry */ 517238106Sdes /* see if this can be a re-probe of an unresponsive server */ 518238106Sdes /* minus 1000 because that is outside of the RTTBAND, so 519238106Sdes * blacklisted servers stay blacklisted if this is chosen */ 520238106Sdes if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) { 521238106Sdes lock_rw_unlock(&e->lock); 522238106Sdes *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; 523238106Sdes *lame = 0; 524238106Sdes *dnsseclame = 0; 525238106Sdes *reclame = 0; 526238106Sdes return 1; 527238106Sdes } 528238106Sdes lock_rw_unlock(&e->lock); 529238106Sdes return 0; 530238106Sdes } 531238106Sdes /* check lameness first */ 532238106Sdes if(host->lame_type_A && qtype == LDNS_RR_TYPE_A) { 533238106Sdes lock_rw_unlock(&e->lock); 534238106Sdes *lame = 1; 535238106Sdes *dnsseclame = 0; 536238106Sdes *reclame = 0; 537238106Sdes return 1; 538238106Sdes } else if(host->lame_other && qtype != LDNS_RR_TYPE_A) { 539238106Sdes lock_rw_unlock(&e->lock); 540238106Sdes *lame = 1; 541238106Sdes *dnsseclame = 0; 542238106Sdes *reclame = 0; 543238106Sdes return 1; 544238106Sdes } else if(host->isdnsseclame) { 545238106Sdes lock_rw_unlock(&e->lock); 546238106Sdes *lame = 0; 547238106Sdes *dnsseclame = 1; 548238106Sdes *reclame = 0; 549238106Sdes return 1; 550238106Sdes } else if(host->rec_lame) { 551238106Sdes lock_rw_unlock(&e->lock); 552238106Sdes *lame = 0; 553238106Sdes *dnsseclame = 0; 554238106Sdes *reclame = 1; 555238106Sdes return 1; 556238106Sdes } 557238106Sdes /* no lameness for this type of query */ 558238106Sdes lock_rw_unlock(&e->lock); 559238106Sdes *lame = 0; 560238106Sdes *dnsseclame = 0; 561238106Sdes *reclame = 0; 562238106Sdes return 1; 563238106Sdes} 564238106Sdes 565238106Sdessize_t 566238106Sdesinfra_get_mem(struct infra_cache* infra) 567238106Sdes{ 568238106Sdes return sizeof(*infra) + slabhash_get_mem(infra->hosts); 569238106Sdes} 570