1*b7579f77SDag-Erling Smørgrav /* 2*b7579f77SDag-Erling Smørgrav * services/cache/infra.c - infrastructure cache, server rtt and capabilities 3*b7579f77SDag-Erling Smørgrav * 4*b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, NLnet Labs. All rights reserved. 5*b7579f77SDag-Erling Smørgrav * 6*b7579f77SDag-Erling Smørgrav * This software is open source. 7*b7579f77SDag-Erling Smørgrav * 8*b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9*b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10*b7579f77SDag-Erling Smørgrav * are met: 11*b7579f77SDag-Erling Smørgrav * 12*b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13*b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14*b7579f77SDag-Erling Smørgrav * 15*b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16*b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17*b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18*b7579f77SDag-Erling Smørgrav * 19*b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20*b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21*b7579f77SDag-Erling Smørgrav * specific prior written permission. 22*b7579f77SDag-Erling Smørgrav * 23*b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24*b7579f77SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25*b7579f77SDag-Erling Smørgrav * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26*b7579f77SDag-Erling Smørgrav * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27*b7579f77SDag-Erling Smørgrav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28*b7579f77SDag-Erling Smørgrav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29*b7579f77SDag-Erling Smørgrav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30*b7579f77SDag-Erling Smørgrav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31*b7579f77SDag-Erling Smørgrav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32*b7579f77SDag-Erling Smørgrav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33*b7579f77SDag-Erling Smørgrav * POSSIBILITY OF SUCH DAMAGE. 34*b7579f77SDag-Erling Smørgrav */ 35*b7579f77SDag-Erling Smørgrav 36*b7579f77SDag-Erling Smørgrav /** 37*b7579f77SDag-Erling Smørgrav * \file 38*b7579f77SDag-Erling Smørgrav * 39*b7579f77SDag-Erling Smørgrav * This file contains the infrastructure cache. 40*b7579f77SDag-Erling Smørgrav */ 41*b7579f77SDag-Erling Smørgrav #include "config.h" 42*b7579f77SDag-Erling Smørgrav #include <ldns/rr.h> 43*b7579f77SDag-Erling Smørgrav #include "services/cache/infra.h" 44*b7579f77SDag-Erling Smørgrav #include "util/storage/slabhash.h" 45*b7579f77SDag-Erling Smørgrav #include "util/storage/lookup3.h" 46*b7579f77SDag-Erling Smørgrav #include "util/data/dname.h" 47*b7579f77SDag-Erling Smørgrav #include "util/log.h" 48*b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 49*b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 50*b7579f77SDag-Erling Smørgrav #include "iterator/iterator.h" 51*b7579f77SDag-Erling Smørgrav 52*b7579f77SDag-Erling Smørgrav /** Timeout when only a single probe query per IP is allowed. */ 53*b7579f77SDag-Erling Smørgrav #define PROBE_MAXRTO 12000 /* in msec */ 54*b7579f77SDag-Erling Smørgrav 55*b7579f77SDag-Erling Smørgrav /** number of timeouts for a type when the domain can be blocked ; 56*b7579f77SDag-Erling Smørgrav * even if another type has completely rtt maxed it, the different type 57*b7579f77SDag-Erling Smørgrav * can do this number of packets (until those all timeout too) */ 58*b7579f77SDag-Erling Smørgrav #define TIMEOUT_COUNT_MAX 3 59*b7579f77SDag-Erling Smørgrav 60*b7579f77SDag-Erling Smørgrav size_t 61*b7579f77SDag-Erling Smørgrav infra_sizefunc(void* k, void* ATTR_UNUSED(d)) 62*b7579f77SDag-Erling Smørgrav { 63*b7579f77SDag-Erling Smørgrav struct infra_key* key = (struct infra_key*)k; 64*b7579f77SDag-Erling Smørgrav return sizeof(*key) + sizeof(struct infra_data) + key->namelen 65*b7579f77SDag-Erling Smørgrav + lock_get_mem(&key->entry.lock); 66*b7579f77SDag-Erling Smørgrav } 67*b7579f77SDag-Erling Smørgrav 68*b7579f77SDag-Erling Smørgrav int 69*b7579f77SDag-Erling Smørgrav infra_compfunc(void* key1, void* key2) 70*b7579f77SDag-Erling Smørgrav { 71*b7579f77SDag-Erling Smørgrav struct infra_key* k1 = (struct infra_key*)key1; 72*b7579f77SDag-Erling Smørgrav struct infra_key* k2 = (struct infra_key*)key2; 73*b7579f77SDag-Erling Smørgrav int r = sockaddr_cmp(&k1->addr, k1->addrlen, &k2->addr, k2->addrlen); 74*b7579f77SDag-Erling Smørgrav if(r != 0) 75*b7579f77SDag-Erling Smørgrav return r; 76*b7579f77SDag-Erling Smørgrav if(k1->namelen != k2->namelen) { 77*b7579f77SDag-Erling Smørgrav if(k1->namelen < k2->namelen) 78*b7579f77SDag-Erling Smørgrav return -1; 79*b7579f77SDag-Erling Smørgrav return 1; 80*b7579f77SDag-Erling Smørgrav } 81*b7579f77SDag-Erling Smørgrav return query_dname_compare(k1->zonename, k2->zonename); 82*b7579f77SDag-Erling Smørgrav } 83*b7579f77SDag-Erling Smørgrav 84*b7579f77SDag-Erling Smørgrav void 85*b7579f77SDag-Erling Smørgrav infra_delkeyfunc(void* k, void* ATTR_UNUSED(arg)) 86*b7579f77SDag-Erling Smørgrav { 87*b7579f77SDag-Erling Smørgrav struct infra_key* key = (struct infra_key*)k; 88*b7579f77SDag-Erling Smørgrav if(!key) 89*b7579f77SDag-Erling Smørgrav return; 90*b7579f77SDag-Erling Smørgrav lock_rw_destroy(&key->entry.lock); 91*b7579f77SDag-Erling Smørgrav free(key->zonename); 92*b7579f77SDag-Erling Smørgrav free(key); 93*b7579f77SDag-Erling Smørgrav } 94*b7579f77SDag-Erling Smørgrav 95*b7579f77SDag-Erling Smørgrav void 96*b7579f77SDag-Erling Smørgrav infra_deldatafunc(void* d, void* ATTR_UNUSED(arg)) 97*b7579f77SDag-Erling Smørgrav { 98*b7579f77SDag-Erling Smørgrav struct infra_data* data = (struct infra_data*)d; 99*b7579f77SDag-Erling Smørgrav free(data); 100*b7579f77SDag-Erling Smørgrav } 101*b7579f77SDag-Erling Smørgrav 102*b7579f77SDag-Erling Smørgrav struct infra_cache* 103*b7579f77SDag-Erling Smørgrav infra_create(struct config_file* cfg) 104*b7579f77SDag-Erling Smørgrav { 105*b7579f77SDag-Erling Smørgrav struct infra_cache* infra = (struct infra_cache*)calloc(1, 106*b7579f77SDag-Erling Smørgrav sizeof(struct infra_cache)); 107*b7579f77SDag-Erling Smørgrav size_t maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+ 108*b7579f77SDag-Erling Smørgrav sizeof(struct infra_data)+INFRA_BYTES_NAME); 109*b7579f77SDag-Erling Smørgrav infra->hosts = slabhash_create(cfg->infra_cache_slabs, 110*b7579f77SDag-Erling Smørgrav INFRA_HOST_STARTSIZE, maxmem, &infra_sizefunc, &infra_compfunc, 111*b7579f77SDag-Erling Smørgrav &infra_delkeyfunc, &infra_deldatafunc, NULL); 112*b7579f77SDag-Erling Smørgrav if(!infra->hosts) { 113*b7579f77SDag-Erling Smørgrav free(infra); 114*b7579f77SDag-Erling Smørgrav return NULL; 115*b7579f77SDag-Erling Smørgrav } 116*b7579f77SDag-Erling Smørgrav infra->host_ttl = cfg->host_ttl; 117*b7579f77SDag-Erling Smørgrav return infra; 118*b7579f77SDag-Erling Smørgrav } 119*b7579f77SDag-Erling Smørgrav 120*b7579f77SDag-Erling Smørgrav void 121*b7579f77SDag-Erling Smørgrav infra_delete(struct infra_cache* infra) 122*b7579f77SDag-Erling Smørgrav { 123*b7579f77SDag-Erling Smørgrav if(!infra) 124*b7579f77SDag-Erling Smørgrav return; 125*b7579f77SDag-Erling Smørgrav slabhash_delete(infra->hosts); 126*b7579f77SDag-Erling Smørgrav free(infra); 127*b7579f77SDag-Erling Smørgrav } 128*b7579f77SDag-Erling Smørgrav 129*b7579f77SDag-Erling Smørgrav struct infra_cache* 130*b7579f77SDag-Erling Smørgrav infra_adjust(struct infra_cache* infra, struct config_file* cfg) 131*b7579f77SDag-Erling Smørgrav { 132*b7579f77SDag-Erling Smørgrav size_t maxmem; 133*b7579f77SDag-Erling Smørgrav if(!infra) 134*b7579f77SDag-Erling Smørgrav return infra_create(cfg); 135*b7579f77SDag-Erling Smørgrav infra->host_ttl = cfg->host_ttl; 136*b7579f77SDag-Erling Smørgrav maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+ 137*b7579f77SDag-Erling Smørgrav sizeof(struct infra_data)+INFRA_BYTES_NAME); 138*b7579f77SDag-Erling Smørgrav if(maxmem != slabhash_get_size(infra->hosts) || 139*b7579f77SDag-Erling Smørgrav cfg->infra_cache_slabs != infra->hosts->size) { 140*b7579f77SDag-Erling Smørgrav infra_delete(infra); 141*b7579f77SDag-Erling Smørgrav infra = infra_create(cfg); 142*b7579f77SDag-Erling Smørgrav } 143*b7579f77SDag-Erling Smørgrav return infra; 144*b7579f77SDag-Erling Smørgrav } 145*b7579f77SDag-Erling Smørgrav 146*b7579f77SDag-Erling Smørgrav /** calculate the hash value for a host key */ 147*b7579f77SDag-Erling Smørgrav static hashvalue_t 148*b7579f77SDag-Erling Smørgrav hash_addr(struct sockaddr_storage* addr, socklen_t addrlen) 149*b7579f77SDag-Erling Smørgrav { 150*b7579f77SDag-Erling Smørgrav hashvalue_t h = 0xab; 151*b7579f77SDag-Erling Smørgrav /* select the pieces to hash, some OS have changing data inside */ 152*b7579f77SDag-Erling Smørgrav if(addr_is_ip6(addr, addrlen)) { 153*b7579f77SDag-Erling Smørgrav struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr; 154*b7579f77SDag-Erling Smørgrav h = hashlittle(&in6->sin6_family, sizeof(in6->sin6_family), h); 155*b7579f77SDag-Erling Smørgrav h = hashlittle(&in6->sin6_port, sizeof(in6->sin6_port), h); 156*b7579f77SDag-Erling Smørgrav h = hashlittle(&in6->sin6_addr, INET6_SIZE, h); 157*b7579f77SDag-Erling Smørgrav } else { 158*b7579f77SDag-Erling Smørgrav struct sockaddr_in* in = (struct sockaddr_in*)addr; 159*b7579f77SDag-Erling Smørgrav h = hashlittle(&in->sin_family, sizeof(in->sin_family), h); 160*b7579f77SDag-Erling Smørgrav h = hashlittle(&in->sin_port, sizeof(in->sin_port), h); 161*b7579f77SDag-Erling Smørgrav h = hashlittle(&in->sin_addr, INET_SIZE, h); 162*b7579f77SDag-Erling Smørgrav } 163*b7579f77SDag-Erling Smørgrav return h; 164*b7579f77SDag-Erling Smørgrav } 165*b7579f77SDag-Erling Smørgrav 166*b7579f77SDag-Erling Smørgrav /** calculate infra hash for a key */ 167*b7579f77SDag-Erling Smørgrav static hashvalue_t 168*b7579f77SDag-Erling Smørgrav hash_infra(struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name) 169*b7579f77SDag-Erling Smørgrav { 170*b7579f77SDag-Erling Smørgrav return dname_query_hash(name, hash_addr(addr, addrlen)); 171*b7579f77SDag-Erling Smørgrav } 172*b7579f77SDag-Erling Smørgrav 173*b7579f77SDag-Erling Smørgrav /** lookup version that does not check host ttl (you check it) */ 174*b7579f77SDag-Erling Smørgrav struct lruhash_entry* 175*b7579f77SDag-Erling Smørgrav infra_lookup_nottl(struct infra_cache* infra, struct sockaddr_storage* addr, 176*b7579f77SDag-Erling Smørgrav socklen_t addrlen, uint8_t* name, size_t namelen, int wr) 177*b7579f77SDag-Erling Smørgrav { 178*b7579f77SDag-Erling Smørgrav struct infra_key k; 179*b7579f77SDag-Erling Smørgrav k.addrlen = addrlen; 180*b7579f77SDag-Erling Smørgrav memcpy(&k.addr, addr, addrlen); 181*b7579f77SDag-Erling Smørgrav k.namelen = namelen; 182*b7579f77SDag-Erling Smørgrav k.zonename = name; 183*b7579f77SDag-Erling Smørgrav k.entry.hash = hash_infra(addr, addrlen, name); 184*b7579f77SDag-Erling Smørgrav k.entry.key = (void*)&k; 185*b7579f77SDag-Erling Smørgrav k.entry.data = NULL; 186*b7579f77SDag-Erling Smørgrav return slabhash_lookup(infra->hosts, k.entry.hash, &k, wr); 187*b7579f77SDag-Erling Smørgrav } 188*b7579f77SDag-Erling Smørgrav 189*b7579f77SDag-Erling Smørgrav /** init the data elements */ 190*b7579f77SDag-Erling Smørgrav static void 191*b7579f77SDag-Erling Smørgrav data_entry_init(struct infra_cache* infra, struct lruhash_entry* e, 192*b7579f77SDag-Erling Smørgrav uint32_t timenow) 193*b7579f77SDag-Erling Smørgrav { 194*b7579f77SDag-Erling Smørgrav struct infra_data* data = (struct infra_data*)e->data; 195*b7579f77SDag-Erling Smørgrav data->ttl = timenow + infra->host_ttl; 196*b7579f77SDag-Erling Smørgrav rtt_init(&data->rtt); 197*b7579f77SDag-Erling Smørgrav data->edns_version = 0; 198*b7579f77SDag-Erling Smørgrav data->edns_lame_known = 0; 199*b7579f77SDag-Erling Smørgrav data->probedelay = 0; 200*b7579f77SDag-Erling Smørgrav data->isdnsseclame = 0; 201*b7579f77SDag-Erling Smørgrav data->rec_lame = 0; 202*b7579f77SDag-Erling Smørgrav data->lame_type_A = 0; 203*b7579f77SDag-Erling Smørgrav data->lame_other = 0; 204*b7579f77SDag-Erling Smørgrav data->timeout_A = 0; 205*b7579f77SDag-Erling Smørgrav data->timeout_AAAA = 0; 206*b7579f77SDag-Erling Smørgrav data->timeout_other = 0; 207*b7579f77SDag-Erling Smørgrav } 208*b7579f77SDag-Erling Smørgrav 209*b7579f77SDag-Erling Smørgrav /** 210*b7579f77SDag-Erling Smørgrav * Create and init a new entry for a host 211*b7579f77SDag-Erling Smørgrav * @param infra: infra structure with config parameters. 212*b7579f77SDag-Erling Smørgrav * @param addr: host address. 213*b7579f77SDag-Erling Smørgrav * @param addrlen: length of addr. 214*b7579f77SDag-Erling Smørgrav * @param name: name of zone 215*b7579f77SDag-Erling Smørgrav * @param namelen: length of name. 216*b7579f77SDag-Erling Smørgrav * @param tm: time now. 217*b7579f77SDag-Erling Smørgrav * @return: the new entry or NULL on malloc failure. 218*b7579f77SDag-Erling Smørgrav */ 219*b7579f77SDag-Erling Smørgrav static struct lruhash_entry* 220*b7579f77SDag-Erling Smørgrav new_entry(struct infra_cache* infra, struct sockaddr_storage* addr, 221*b7579f77SDag-Erling Smørgrav socklen_t addrlen, uint8_t* name, size_t namelen, uint32_t tm) 222*b7579f77SDag-Erling Smørgrav { 223*b7579f77SDag-Erling Smørgrav struct infra_data* data; 224*b7579f77SDag-Erling Smørgrav struct infra_key* key = (struct infra_key*)malloc(sizeof(*key)); 225*b7579f77SDag-Erling Smørgrav if(!key) 226*b7579f77SDag-Erling Smørgrav return NULL; 227*b7579f77SDag-Erling Smørgrav data = (struct infra_data*)malloc(sizeof(struct infra_data)); 228*b7579f77SDag-Erling Smørgrav if(!data) { 229*b7579f77SDag-Erling Smørgrav free(key); 230*b7579f77SDag-Erling Smørgrav return NULL; 231*b7579f77SDag-Erling Smørgrav } 232*b7579f77SDag-Erling Smørgrav key->zonename = memdup(name, namelen); 233*b7579f77SDag-Erling Smørgrav if(!key->zonename) { 234*b7579f77SDag-Erling Smørgrav free(key); 235*b7579f77SDag-Erling Smørgrav free(data); 236*b7579f77SDag-Erling Smørgrav return NULL; 237*b7579f77SDag-Erling Smørgrav } 238*b7579f77SDag-Erling Smørgrav key->namelen = namelen; 239*b7579f77SDag-Erling Smørgrav lock_rw_init(&key->entry.lock); 240*b7579f77SDag-Erling Smørgrav key->entry.hash = hash_infra(addr, addrlen, name); 241*b7579f77SDag-Erling Smørgrav key->entry.key = (void*)key; 242*b7579f77SDag-Erling Smørgrav key->entry.data = (void*)data; 243*b7579f77SDag-Erling Smørgrav key->addrlen = addrlen; 244*b7579f77SDag-Erling Smørgrav memcpy(&key->addr, addr, addrlen); 245*b7579f77SDag-Erling Smørgrav data_entry_init(infra, &key->entry, tm); 246*b7579f77SDag-Erling Smørgrav return &key->entry; 247*b7579f77SDag-Erling Smørgrav } 248*b7579f77SDag-Erling Smørgrav 249*b7579f77SDag-Erling Smørgrav int 250*b7579f77SDag-Erling Smørgrav infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, 251*b7579f77SDag-Erling Smørgrav socklen_t addrlen, uint8_t* nm, size_t nmlen, uint32_t timenow, 252*b7579f77SDag-Erling Smørgrav int* edns_vs, uint8_t* edns_lame_known, int* to) 253*b7579f77SDag-Erling Smørgrav { 254*b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 255*b7579f77SDag-Erling Smørgrav nm, nmlen, 0); 256*b7579f77SDag-Erling Smørgrav struct infra_data* data; 257*b7579f77SDag-Erling Smørgrav int wr = 0; 258*b7579f77SDag-Erling Smørgrav if(e && ((struct infra_data*)e->data)->ttl < timenow) { 259*b7579f77SDag-Erling Smørgrav /* it expired, try to reuse existing entry */ 260*b7579f77SDag-Erling Smørgrav int old = ((struct infra_data*)e->data)->rtt.rto; 261*b7579f77SDag-Erling Smørgrav uint8_t tA = ((struct infra_data*)e->data)->timeout_A; 262*b7579f77SDag-Erling Smørgrav uint8_t tAAAA = ((struct infra_data*)e->data)->timeout_AAAA; 263*b7579f77SDag-Erling Smørgrav uint8_t tother = ((struct infra_data*)e->data)->timeout_other; 264*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 265*b7579f77SDag-Erling Smørgrav e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); 266*b7579f77SDag-Erling Smørgrav if(e) { 267*b7579f77SDag-Erling Smørgrav /* if its still there we have a writelock, init */ 268*b7579f77SDag-Erling Smørgrav /* re-initialise */ 269*b7579f77SDag-Erling Smørgrav /* do not touch lameness, it may be valid still */ 270*b7579f77SDag-Erling Smørgrav data_entry_init(infra, e, timenow); 271*b7579f77SDag-Erling Smørgrav wr = 1; 272*b7579f77SDag-Erling Smørgrav /* TOP_TIMEOUT remains on reuse */ 273*b7579f77SDag-Erling Smørgrav if(old >= USEFUL_SERVER_TOP_TIMEOUT) { 274*b7579f77SDag-Erling Smørgrav ((struct infra_data*)e->data)->rtt.rto 275*b7579f77SDag-Erling Smørgrav = USEFUL_SERVER_TOP_TIMEOUT; 276*b7579f77SDag-Erling Smørgrav ((struct infra_data*)e->data)->timeout_A = tA; 277*b7579f77SDag-Erling Smørgrav ((struct infra_data*)e->data)->timeout_AAAA = tAAAA; 278*b7579f77SDag-Erling Smørgrav ((struct infra_data*)e->data)->timeout_other = tother; 279*b7579f77SDag-Erling Smørgrav } 280*b7579f77SDag-Erling Smørgrav } 281*b7579f77SDag-Erling Smørgrav } 282*b7579f77SDag-Erling Smørgrav if(!e) { 283*b7579f77SDag-Erling Smørgrav /* insert new entry */ 284*b7579f77SDag-Erling Smørgrav if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) 285*b7579f77SDag-Erling Smørgrav return 0; 286*b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 287*b7579f77SDag-Erling Smørgrav *edns_vs = data->edns_version; 288*b7579f77SDag-Erling Smørgrav *edns_lame_known = data->edns_lame_known; 289*b7579f77SDag-Erling Smørgrav *to = rtt_timeout(&data->rtt); 290*b7579f77SDag-Erling Smørgrav slabhash_insert(infra->hosts, e->hash, e, data, NULL); 291*b7579f77SDag-Erling Smørgrav return 1; 292*b7579f77SDag-Erling Smørgrav } 293*b7579f77SDag-Erling Smørgrav /* use existing entry */ 294*b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 295*b7579f77SDag-Erling Smørgrav *edns_vs = data->edns_version; 296*b7579f77SDag-Erling Smørgrav *edns_lame_known = data->edns_lame_known; 297*b7579f77SDag-Erling Smørgrav *to = rtt_timeout(&data->rtt); 298*b7579f77SDag-Erling Smørgrav if(*to >= PROBE_MAXRTO && rtt_notimeout(&data->rtt)*4 <= *to) { 299*b7579f77SDag-Erling Smørgrav /* delay other queries, this is the probe query */ 300*b7579f77SDag-Erling Smørgrav if(!wr) { 301*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 302*b7579f77SDag-Erling Smørgrav e = infra_lookup_nottl(infra, addr,addrlen,nm,nmlen, 1); 303*b7579f77SDag-Erling Smørgrav if(!e) { /* flushed from cache real fast, no use to 304*b7579f77SDag-Erling Smørgrav allocate just for the probedelay */ 305*b7579f77SDag-Erling Smørgrav return 1; 306*b7579f77SDag-Erling Smørgrav } 307*b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 308*b7579f77SDag-Erling Smørgrav } 309*b7579f77SDag-Erling Smørgrav /* add 999 to round up the timeout value from msec to sec, 310*b7579f77SDag-Erling Smørgrav * then add a whole second so it is certain that this probe 311*b7579f77SDag-Erling Smørgrav * has timed out before the next is allowed */ 312*b7579f77SDag-Erling Smørgrav data->probedelay = timenow + ((*to)+1999)/1000; 313*b7579f77SDag-Erling Smørgrav } 314*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 315*b7579f77SDag-Erling Smørgrav return 1; 316*b7579f77SDag-Erling Smørgrav } 317*b7579f77SDag-Erling Smørgrav 318*b7579f77SDag-Erling Smørgrav int 319*b7579f77SDag-Erling Smørgrav infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr, 320*b7579f77SDag-Erling Smørgrav socklen_t addrlen, uint8_t* nm, size_t nmlen, uint32_t timenow, 321*b7579f77SDag-Erling Smørgrav int dnsseclame, int reclame, uint16_t qtype) 322*b7579f77SDag-Erling Smørgrav { 323*b7579f77SDag-Erling Smørgrav struct infra_data* data; 324*b7579f77SDag-Erling Smørgrav struct lruhash_entry* e; 325*b7579f77SDag-Erling Smørgrav int needtoinsert = 0; 326*b7579f77SDag-Erling Smørgrav e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); 327*b7579f77SDag-Erling Smørgrav if(!e) { 328*b7579f77SDag-Erling Smørgrav /* insert it */ 329*b7579f77SDag-Erling Smørgrav if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) { 330*b7579f77SDag-Erling Smørgrav log_err("set_lame: malloc failure"); 331*b7579f77SDag-Erling Smørgrav return 0; 332*b7579f77SDag-Erling Smørgrav } 333*b7579f77SDag-Erling Smørgrav needtoinsert = 1; 334*b7579f77SDag-Erling Smørgrav } else if( ((struct infra_data*)e->data)->ttl < timenow) { 335*b7579f77SDag-Erling Smørgrav /* expired, reuse existing entry */ 336*b7579f77SDag-Erling Smørgrav data_entry_init(infra, e, timenow); 337*b7579f77SDag-Erling Smørgrav } 338*b7579f77SDag-Erling Smørgrav /* got an entry, now set the zone lame */ 339*b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 340*b7579f77SDag-Erling Smørgrav /* merge data (if any) */ 341*b7579f77SDag-Erling Smørgrav if(dnsseclame) 342*b7579f77SDag-Erling Smørgrav data->isdnsseclame = 1; 343*b7579f77SDag-Erling Smørgrav if(reclame) 344*b7579f77SDag-Erling Smørgrav data->rec_lame = 1; 345*b7579f77SDag-Erling Smørgrav if(!dnsseclame && !reclame && qtype == LDNS_RR_TYPE_A) 346*b7579f77SDag-Erling Smørgrav data->lame_type_A = 1; 347*b7579f77SDag-Erling Smørgrav if(!dnsseclame && !reclame && qtype != LDNS_RR_TYPE_A) 348*b7579f77SDag-Erling Smørgrav data->lame_other = 1; 349*b7579f77SDag-Erling Smørgrav /* done */ 350*b7579f77SDag-Erling Smørgrav if(needtoinsert) 351*b7579f77SDag-Erling Smørgrav slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); 352*b7579f77SDag-Erling Smørgrav else { lock_rw_unlock(&e->lock); } 353*b7579f77SDag-Erling Smørgrav return 1; 354*b7579f77SDag-Erling Smørgrav } 355*b7579f77SDag-Erling Smørgrav 356*b7579f77SDag-Erling Smørgrav void 357*b7579f77SDag-Erling Smørgrav infra_update_tcp_works(struct infra_cache* infra, 358*b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, 359*b7579f77SDag-Erling Smørgrav size_t nmlen) 360*b7579f77SDag-Erling Smørgrav { 361*b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 362*b7579f77SDag-Erling Smørgrav nm, nmlen, 1); 363*b7579f77SDag-Erling Smørgrav struct infra_data* data; 364*b7579f77SDag-Erling Smørgrav if(!e) 365*b7579f77SDag-Erling Smørgrav return; /* doesn't exist */ 366*b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 367*b7579f77SDag-Erling Smørgrav if(data->rtt.rto >= RTT_MAX_TIMEOUT) 368*b7579f77SDag-Erling Smørgrav /* do not disqualify this server altogether, it is better 369*b7579f77SDag-Erling Smørgrav * than nothing */ 370*b7579f77SDag-Erling Smørgrav data->rtt.rto = RTT_MAX_TIMEOUT-1000; 371*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 372*b7579f77SDag-Erling Smørgrav } 373*b7579f77SDag-Erling Smørgrav 374*b7579f77SDag-Erling Smørgrav int 375*b7579f77SDag-Erling Smørgrav infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, 376*b7579f77SDag-Erling Smørgrav socklen_t addrlen, uint8_t* nm, size_t nmlen, int qtype, 377*b7579f77SDag-Erling Smørgrav int roundtrip, int orig_rtt, uint32_t timenow) 378*b7579f77SDag-Erling Smørgrav { 379*b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 380*b7579f77SDag-Erling Smørgrav nm, nmlen, 1); 381*b7579f77SDag-Erling Smørgrav struct infra_data* data; 382*b7579f77SDag-Erling Smørgrav int needtoinsert = 0; 383*b7579f77SDag-Erling Smørgrav int rto = 1; 384*b7579f77SDag-Erling Smørgrav if(!e) { 385*b7579f77SDag-Erling Smørgrav if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) 386*b7579f77SDag-Erling Smørgrav return 0; 387*b7579f77SDag-Erling Smørgrav needtoinsert = 1; 388*b7579f77SDag-Erling Smørgrav } else if(((struct infra_data*)e->data)->ttl < timenow) { 389*b7579f77SDag-Erling Smørgrav data_entry_init(infra, e, timenow); 390*b7579f77SDag-Erling Smørgrav } 391*b7579f77SDag-Erling Smørgrav /* have an entry, update the rtt */ 392*b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 393*b7579f77SDag-Erling Smørgrav if(roundtrip == -1) { 394*b7579f77SDag-Erling Smørgrav rtt_lost(&data->rtt, orig_rtt); 395*b7579f77SDag-Erling Smørgrav if(qtype == LDNS_RR_TYPE_A) { 396*b7579f77SDag-Erling Smørgrav if(data->timeout_A < TIMEOUT_COUNT_MAX) 397*b7579f77SDag-Erling Smørgrav data->timeout_A++; 398*b7579f77SDag-Erling Smørgrav } else if(qtype == LDNS_RR_TYPE_AAAA) { 399*b7579f77SDag-Erling Smørgrav if(data->timeout_AAAA < TIMEOUT_COUNT_MAX) 400*b7579f77SDag-Erling Smørgrav data->timeout_AAAA++; 401*b7579f77SDag-Erling Smørgrav } else { 402*b7579f77SDag-Erling Smørgrav if(data->timeout_other < TIMEOUT_COUNT_MAX) 403*b7579f77SDag-Erling Smørgrav data->timeout_other++; 404*b7579f77SDag-Erling Smørgrav } 405*b7579f77SDag-Erling Smørgrav } else { 406*b7579f77SDag-Erling Smørgrav rtt_update(&data->rtt, roundtrip); 407*b7579f77SDag-Erling Smørgrav data->probedelay = 0; 408*b7579f77SDag-Erling Smørgrav if(qtype == LDNS_RR_TYPE_A) 409*b7579f77SDag-Erling Smørgrav data->timeout_A = 0; 410*b7579f77SDag-Erling Smørgrav else if(qtype == LDNS_RR_TYPE_AAAA) 411*b7579f77SDag-Erling Smørgrav data->timeout_AAAA = 0; 412*b7579f77SDag-Erling Smørgrav else data->timeout_other = 0; 413*b7579f77SDag-Erling Smørgrav } 414*b7579f77SDag-Erling Smørgrav if(data->rtt.rto > 0) 415*b7579f77SDag-Erling Smørgrav rto = data->rtt.rto; 416*b7579f77SDag-Erling Smørgrav 417*b7579f77SDag-Erling Smørgrav if(needtoinsert) 418*b7579f77SDag-Erling Smørgrav slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); 419*b7579f77SDag-Erling Smørgrav else { lock_rw_unlock(&e->lock); } 420*b7579f77SDag-Erling Smørgrav return rto; 421*b7579f77SDag-Erling Smørgrav } 422*b7579f77SDag-Erling Smørgrav 423*b7579f77SDag-Erling Smørgrav int infra_get_host_rto(struct infra_cache* infra, 424*b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, 425*b7579f77SDag-Erling Smørgrav size_t nmlen, struct rtt_info* rtt, int* delay, uint32_t timenow, 426*b7579f77SDag-Erling Smørgrav int* tA, int* tAAAA, int* tother) 427*b7579f77SDag-Erling Smørgrav { 428*b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 429*b7579f77SDag-Erling Smørgrav nm, nmlen, 0); 430*b7579f77SDag-Erling Smørgrav struct infra_data* data; 431*b7579f77SDag-Erling Smørgrav int ttl = -2; 432*b7579f77SDag-Erling Smørgrav if(!e) return -1; 433*b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 434*b7579f77SDag-Erling Smørgrav if(data->ttl >= timenow) { 435*b7579f77SDag-Erling Smørgrav ttl = (int)(data->ttl - timenow); 436*b7579f77SDag-Erling Smørgrav memmove(rtt, &data->rtt, sizeof(*rtt)); 437*b7579f77SDag-Erling Smørgrav if(timenow < data->probedelay) 438*b7579f77SDag-Erling Smørgrav *delay = (int)(data->probedelay - timenow); 439*b7579f77SDag-Erling Smørgrav else *delay = 0; 440*b7579f77SDag-Erling Smørgrav } 441*b7579f77SDag-Erling Smørgrav *tA = (int)data->timeout_A; 442*b7579f77SDag-Erling Smørgrav *tAAAA = (int)data->timeout_AAAA; 443*b7579f77SDag-Erling Smørgrav *tother = (int)data->timeout_other; 444*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 445*b7579f77SDag-Erling Smørgrav return ttl; 446*b7579f77SDag-Erling Smørgrav } 447*b7579f77SDag-Erling Smørgrav 448*b7579f77SDag-Erling Smørgrav int 449*b7579f77SDag-Erling Smørgrav infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr, 450*b7579f77SDag-Erling Smørgrav socklen_t addrlen, uint8_t* nm, size_t nmlen, int edns_version, 451*b7579f77SDag-Erling Smørgrav uint32_t timenow) 452*b7579f77SDag-Erling Smørgrav { 453*b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 454*b7579f77SDag-Erling Smørgrav nm, nmlen, 1); 455*b7579f77SDag-Erling Smørgrav struct infra_data* data; 456*b7579f77SDag-Erling Smørgrav int needtoinsert = 0; 457*b7579f77SDag-Erling Smørgrav if(!e) { 458*b7579f77SDag-Erling Smørgrav if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) 459*b7579f77SDag-Erling Smørgrav return 0; 460*b7579f77SDag-Erling Smørgrav needtoinsert = 1; 461*b7579f77SDag-Erling Smørgrav } else if(((struct infra_data*)e->data)->ttl < timenow) { 462*b7579f77SDag-Erling Smørgrav data_entry_init(infra, e, timenow); 463*b7579f77SDag-Erling Smørgrav } 464*b7579f77SDag-Erling Smørgrav /* have an entry, update the rtt, and the ttl */ 465*b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 466*b7579f77SDag-Erling Smørgrav /* do not update if noEDNS and stored is yesEDNS */ 467*b7579f77SDag-Erling Smørgrav if(!(edns_version == -1 && (data->edns_version != -1 && 468*b7579f77SDag-Erling Smørgrav data->edns_lame_known))) { 469*b7579f77SDag-Erling Smørgrav data->edns_version = edns_version; 470*b7579f77SDag-Erling Smørgrav data->edns_lame_known = 1; 471*b7579f77SDag-Erling Smørgrav } 472*b7579f77SDag-Erling Smørgrav 473*b7579f77SDag-Erling Smørgrav if(needtoinsert) 474*b7579f77SDag-Erling Smørgrav slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); 475*b7579f77SDag-Erling Smørgrav else { lock_rw_unlock(&e->lock); } 476*b7579f77SDag-Erling Smørgrav return 1; 477*b7579f77SDag-Erling Smørgrav } 478*b7579f77SDag-Erling Smørgrav 479*b7579f77SDag-Erling Smørgrav int 480*b7579f77SDag-Erling Smørgrav infra_get_lame_rtt(struct infra_cache* infra, 481*b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t addrlen, 482*b7579f77SDag-Erling Smørgrav uint8_t* name, size_t namelen, uint16_t qtype, 483*b7579f77SDag-Erling Smørgrav int* lame, int* dnsseclame, int* reclame, int* rtt, uint32_t timenow) 484*b7579f77SDag-Erling Smørgrav { 485*b7579f77SDag-Erling Smørgrav struct infra_data* host; 486*b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 487*b7579f77SDag-Erling Smørgrav name, namelen, 0); 488*b7579f77SDag-Erling Smørgrav if(!e) 489*b7579f77SDag-Erling Smørgrav return 0; 490*b7579f77SDag-Erling Smørgrav host = (struct infra_data*)e->data; 491*b7579f77SDag-Erling Smørgrav *rtt = rtt_unclamped(&host->rtt); 492*b7579f77SDag-Erling Smørgrav if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay 493*b7579f77SDag-Erling Smørgrav && rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) { 494*b7579f77SDag-Erling Smørgrav /* single probe for this domain, and we are not probing */ 495*b7579f77SDag-Erling Smørgrav /* unless the query type allows a probe to happen */ 496*b7579f77SDag-Erling Smørgrav if(qtype == LDNS_RR_TYPE_A) { 497*b7579f77SDag-Erling Smørgrav if(host->timeout_A >= TIMEOUT_COUNT_MAX) 498*b7579f77SDag-Erling Smørgrav *rtt = USEFUL_SERVER_TOP_TIMEOUT; 499*b7579f77SDag-Erling Smørgrav else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; 500*b7579f77SDag-Erling Smørgrav } else if(qtype == LDNS_RR_TYPE_AAAA) { 501*b7579f77SDag-Erling Smørgrav if(host->timeout_AAAA >= TIMEOUT_COUNT_MAX) 502*b7579f77SDag-Erling Smørgrav *rtt = USEFUL_SERVER_TOP_TIMEOUT; 503*b7579f77SDag-Erling Smørgrav else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; 504*b7579f77SDag-Erling Smørgrav } else { 505*b7579f77SDag-Erling Smørgrav if(host->timeout_other >= TIMEOUT_COUNT_MAX) 506*b7579f77SDag-Erling Smørgrav *rtt = USEFUL_SERVER_TOP_TIMEOUT; 507*b7579f77SDag-Erling Smørgrav else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; 508*b7579f77SDag-Erling Smørgrav } 509*b7579f77SDag-Erling Smørgrav } 510*b7579f77SDag-Erling Smørgrav if(timenow > host->ttl) { 511*b7579f77SDag-Erling Smørgrav /* expired entry */ 512*b7579f77SDag-Erling Smørgrav /* see if this can be a re-probe of an unresponsive server */ 513*b7579f77SDag-Erling Smørgrav /* minus 1000 because that is outside of the RTTBAND, so 514*b7579f77SDag-Erling Smørgrav * blacklisted servers stay blacklisted if this is chosen */ 515*b7579f77SDag-Erling Smørgrav if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) { 516*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 517*b7579f77SDag-Erling Smørgrav *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; 518*b7579f77SDag-Erling Smørgrav *lame = 0; 519*b7579f77SDag-Erling Smørgrav *dnsseclame = 0; 520*b7579f77SDag-Erling Smørgrav *reclame = 0; 521*b7579f77SDag-Erling Smørgrav return 1; 522*b7579f77SDag-Erling Smørgrav } 523*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 524*b7579f77SDag-Erling Smørgrav return 0; 525*b7579f77SDag-Erling Smørgrav } 526*b7579f77SDag-Erling Smørgrav /* check lameness first */ 527*b7579f77SDag-Erling Smørgrav if(host->lame_type_A && qtype == LDNS_RR_TYPE_A) { 528*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 529*b7579f77SDag-Erling Smørgrav *lame = 1; 530*b7579f77SDag-Erling Smørgrav *dnsseclame = 0; 531*b7579f77SDag-Erling Smørgrav *reclame = 0; 532*b7579f77SDag-Erling Smørgrav return 1; 533*b7579f77SDag-Erling Smørgrav } else if(host->lame_other && qtype != LDNS_RR_TYPE_A) { 534*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 535*b7579f77SDag-Erling Smørgrav *lame = 1; 536*b7579f77SDag-Erling Smørgrav *dnsseclame = 0; 537*b7579f77SDag-Erling Smørgrav *reclame = 0; 538*b7579f77SDag-Erling Smørgrav return 1; 539*b7579f77SDag-Erling Smørgrav } else if(host->isdnsseclame) { 540*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 541*b7579f77SDag-Erling Smørgrav *lame = 0; 542*b7579f77SDag-Erling Smørgrav *dnsseclame = 1; 543*b7579f77SDag-Erling Smørgrav *reclame = 0; 544*b7579f77SDag-Erling Smørgrav return 1; 545*b7579f77SDag-Erling Smørgrav } else if(host->rec_lame) { 546*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 547*b7579f77SDag-Erling Smørgrav *lame = 0; 548*b7579f77SDag-Erling Smørgrav *dnsseclame = 0; 549*b7579f77SDag-Erling Smørgrav *reclame = 1; 550*b7579f77SDag-Erling Smørgrav return 1; 551*b7579f77SDag-Erling Smørgrav } 552*b7579f77SDag-Erling Smørgrav /* no lameness for this type of query */ 553*b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 554*b7579f77SDag-Erling Smørgrav *lame = 0; 555*b7579f77SDag-Erling Smørgrav *dnsseclame = 0; 556*b7579f77SDag-Erling Smørgrav *reclame = 0; 557*b7579f77SDag-Erling Smørgrav return 1; 558*b7579f77SDag-Erling Smørgrav } 559*b7579f77SDag-Erling Smørgrav 560*b7579f77SDag-Erling Smørgrav size_t 561*b7579f77SDag-Erling Smørgrav infra_get_mem(struct infra_cache* infra) 562*b7579f77SDag-Erling Smørgrav { 563*b7579f77SDag-Erling Smørgrav return sizeof(*infra) + slabhash_get_mem(infra->hosts); 564*b7579f77SDag-Erling Smørgrav } 565