1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * services/cache/infra.c - infrastructure cache, server rtt and capabilities 3b7579f77SDag-Erling Smørgrav * 4b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, NLnet Labs. All rights reserved. 5b7579f77SDag-Erling Smørgrav * 6b7579f77SDag-Erling Smørgrav * This software is open source. 7b7579f77SDag-Erling Smørgrav * 8b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10b7579f77SDag-Erling Smørgrav * are met: 11b7579f77SDag-Erling Smørgrav * 12b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14b7579f77SDag-Erling Smørgrav * 15b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18b7579f77SDag-Erling Smørgrav * 19b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21b7579f77SDag-Erling Smørgrav * specific prior written permission. 22b7579f77SDag-Erling Smørgrav * 23b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2417d15b25SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2517d15b25SDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2617d15b25SDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2717d15b25SDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2817d15b25SDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2917d15b25SDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 3017d15b25SDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3117d15b25SDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3217d15b25SDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3317d15b25SDag-Erling Smørgrav * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34b7579f77SDag-Erling Smørgrav */ 35b7579f77SDag-Erling Smørgrav 36b7579f77SDag-Erling Smørgrav /** 37b7579f77SDag-Erling Smørgrav * \file 38b7579f77SDag-Erling Smørgrav * 39b7579f77SDag-Erling Smørgrav * This file contains the infrastructure cache. 40b7579f77SDag-Erling Smørgrav */ 41b7579f77SDag-Erling Smørgrav #include "config.h" 4209a3aaf3SDag-Erling Smørgrav #include "sldns/rrdef.h" 4309a3aaf3SDag-Erling Smørgrav #include "sldns/str2wire.h" 44e86b9096SDag-Erling Smørgrav #include "sldns/sbuffer.h" 45e86b9096SDag-Erling Smørgrav #include "sldns/wire2str.h" 46b7579f77SDag-Erling Smørgrav #include "services/cache/infra.h" 47b7579f77SDag-Erling Smørgrav #include "util/storage/slabhash.h" 48b7579f77SDag-Erling Smørgrav #include "util/storage/lookup3.h" 49b7579f77SDag-Erling Smørgrav #include "util/data/dname.h" 50b7579f77SDag-Erling Smørgrav #include "util/log.h" 51b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 52b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 53b7579f77SDag-Erling Smørgrav #include "iterator/iterator.h" 54b7579f77SDag-Erling Smørgrav 5509a3aaf3SDag-Erling Smørgrav /** ratelimit value for delegation point */ 5609a3aaf3SDag-Erling Smørgrav int infra_dp_ratelimit = 0; 5709a3aaf3SDag-Erling Smørgrav 583005e0a3SDag-Erling Smørgrav /** ratelimit value for client ip addresses, 593005e0a3SDag-Erling Smørgrav * in queries per second. */ 603005e0a3SDag-Erling Smørgrav int infra_ip_ratelimit = 0; 613005e0a3SDag-Erling Smørgrav 628f76bb7dSCy Schubert /** ratelimit value for client ip addresses, 638f76bb7dSCy Schubert * in queries per second. 648f76bb7dSCy Schubert * For clients with a valid DNS Cookie. */ 658f76bb7dSCy Schubert int infra_ip_ratelimit_cookie = 0; 668f76bb7dSCy Schubert 67*be771a7bSCy Schubert /** Minus 1000 because that is outside of the RTTBAND, so 68*be771a7bSCy Schubert * blacklisted servers stay blacklisted if this is chosen. 69*be771a7bSCy Schubert * If USEFUL_SERVER_TOP_TIMEOUT is below 1000 (configured via RTT_MAX_TIMEOUT, 70*be771a7bSCy Schubert * infra-cache-max-rtt) change it to just above the RTT_BAND. */ 71*be771a7bSCy Schubert int 72*be771a7bSCy Schubert still_useful_timeout() 73*be771a7bSCy Schubert { 74*be771a7bSCy Schubert return 75*be771a7bSCy Schubert USEFUL_SERVER_TOP_TIMEOUT < 1000 || 76*be771a7bSCy Schubert USEFUL_SERVER_TOP_TIMEOUT - 1000 <= RTT_BAND 77*be771a7bSCy Schubert ?RTT_BAND + 1 78*be771a7bSCy Schubert :USEFUL_SERVER_TOP_TIMEOUT - 1000; 79*be771a7bSCy Schubert } 80*be771a7bSCy Schubert 81b7579f77SDag-Erling Smørgrav size_t 82b7579f77SDag-Erling Smørgrav infra_sizefunc(void* k, void* ATTR_UNUSED(d)) 83b7579f77SDag-Erling Smørgrav { 84b7579f77SDag-Erling Smørgrav struct infra_key* key = (struct infra_key*)k; 85b7579f77SDag-Erling Smørgrav return sizeof(*key) + sizeof(struct infra_data) + key->namelen 86b7579f77SDag-Erling Smørgrav + lock_get_mem(&key->entry.lock); 87b7579f77SDag-Erling Smørgrav } 88b7579f77SDag-Erling Smørgrav 89b7579f77SDag-Erling Smørgrav int 90b7579f77SDag-Erling Smørgrav infra_compfunc(void* key1, void* key2) 91b7579f77SDag-Erling Smørgrav { 92b7579f77SDag-Erling Smørgrav struct infra_key* k1 = (struct infra_key*)key1; 93b7579f77SDag-Erling Smørgrav struct infra_key* k2 = (struct infra_key*)key2; 94b7579f77SDag-Erling Smørgrav int r = sockaddr_cmp(&k1->addr, k1->addrlen, &k2->addr, k2->addrlen); 95b7579f77SDag-Erling Smørgrav if(r != 0) 96b7579f77SDag-Erling Smørgrav return r; 97b7579f77SDag-Erling Smørgrav if(k1->namelen != k2->namelen) { 98b7579f77SDag-Erling Smørgrav if(k1->namelen < k2->namelen) 99b7579f77SDag-Erling Smørgrav return -1; 100b7579f77SDag-Erling Smørgrav return 1; 101b7579f77SDag-Erling Smørgrav } 102b7579f77SDag-Erling Smørgrav return query_dname_compare(k1->zonename, k2->zonename); 103b7579f77SDag-Erling Smørgrav } 104b7579f77SDag-Erling Smørgrav 105b7579f77SDag-Erling Smørgrav void 106b7579f77SDag-Erling Smørgrav infra_delkeyfunc(void* k, void* ATTR_UNUSED(arg)) 107b7579f77SDag-Erling Smørgrav { 108b7579f77SDag-Erling Smørgrav struct infra_key* key = (struct infra_key*)k; 109b7579f77SDag-Erling Smørgrav if(!key) 110b7579f77SDag-Erling Smørgrav return; 111b7579f77SDag-Erling Smørgrav lock_rw_destroy(&key->entry.lock); 112b7579f77SDag-Erling Smørgrav free(key->zonename); 113b7579f77SDag-Erling Smørgrav free(key); 114b7579f77SDag-Erling Smørgrav } 115b7579f77SDag-Erling Smørgrav 116b7579f77SDag-Erling Smørgrav void 117b7579f77SDag-Erling Smørgrav infra_deldatafunc(void* d, void* ATTR_UNUSED(arg)) 118b7579f77SDag-Erling Smørgrav { 119b7579f77SDag-Erling Smørgrav struct infra_data* data = (struct infra_data*)d; 120b7579f77SDag-Erling Smørgrav free(data); 121b7579f77SDag-Erling Smørgrav } 122b7579f77SDag-Erling Smørgrav 12309a3aaf3SDag-Erling Smørgrav size_t 12409a3aaf3SDag-Erling Smørgrav rate_sizefunc(void* k, void* ATTR_UNUSED(d)) 12509a3aaf3SDag-Erling Smørgrav { 12609a3aaf3SDag-Erling Smørgrav struct rate_key* key = (struct rate_key*)k; 12709a3aaf3SDag-Erling Smørgrav return sizeof(*key) + sizeof(struct rate_data) + key->namelen 12809a3aaf3SDag-Erling Smørgrav + lock_get_mem(&key->entry.lock); 12909a3aaf3SDag-Erling Smørgrav } 13009a3aaf3SDag-Erling Smørgrav 13109a3aaf3SDag-Erling Smørgrav int 13209a3aaf3SDag-Erling Smørgrav rate_compfunc(void* key1, void* key2) 13309a3aaf3SDag-Erling Smørgrav { 13409a3aaf3SDag-Erling Smørgrav struct rate_key* k1 = (struct rate_key*)key1; 13509a3aaf3SDag-Erling Smørgrav struct rate_key* k2 = (struct rate_key*)key2; 13609a3aaf3SDag-Erling Smørgrav if(k1->namelen != k2->namelen) { 13709a3aaf3SDag-Erling Smørgrav if(k1->namelen < k2->namelen) 13809a3aaf3SDag-Erling Smørgrav return -1; 13909a3aaf3SDag-Erling Smørgrav return 1; 14009a3aaf3SDag-Erling Smørgrav } 14109a3aaf3SDag-Erling Smørgrav return query_dname_compare(k1->name, k2->name); 14209a3aaf3SDag-Erling Smørgrav } 14309a3aaf3SDag-Erling Smørgrav 14409a3aaf3SDag-Erling Smørgrav void 14509a3aaf3SDag-Erling Smørgrav rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg)) 14609a3aaf3SDag-Erling Smørgrav { 14709a3aaf3SDag-Erling Smørgrav struct rate_key* key = (struct rate_key*)k; 14809a3aaf3SDag-Erling Smørgrav if(!key) 14909a3aaf3SDag-Erling Smørgrav return; 15009a3aaf3SDag-Erling Smørgrav lock_rw_destroy(&key->entry.lock); 15109a3aaf3SDag-Erling Smørgrav free(key->name); 15209a3aaf3SDag-Erling Smørgrav free(key); 15309a3aaf3SDag-Erling Smørgrav } 15409a3aaf3SDag-Erling Smørgrav 15509a3aaf3SDag-Erling Smørgrav void 15609a3aaf3SDag-Erling Smørgrav rate_deldatafunc(void* d, void* ATTR_UNUSED(arg)) 15709a3aaf3SDag-Erling Smørgrav { 15809a3aaf3SDag-Erling Smørgrav struct rate_data* data = (struct rate_data*)d; 15909a3aaf3SDag-Erling Smørgrav free(data); 16009a3aaf3SDag-Erling Smørgrav } 16109a3aaf3SDag-Erling Smørgrav 16209a3aaf3SDag-Erling Smørgrav /** find or create element in domainlimit tree */ 16309a3aaf3SDag-Erling Smørgrav static struct domain_limit_data* domain_limit_findcreate( 164*be771a7bSCy Schubert struct rbtree_type* domain_limits, char* name) 16509a3aaf3SDag-Erling Smørgrav { 16609a3aaf3SDag-Erling Smørgrav uint8_t* nm; 16709a3aaf3SDag-Erling Smørgrav int labs; 16809a3aaf3SDag-Erling Smørgrav size_t nmlen; 16909a3aaf3SDag-Erling Smørgrav struct domain_limit_data* d; 17009a3aaf3SDag-Erling Smørgrav 17109a3aaf3SDag-Erling Smørgrav /* parse name */ 17209a3aaf3SDag-Erling Smørgrav nm = sldns_str2wire_dname(name, &nmlen); 17309a3aaf3SDag-Erling Smørgrav if(!nm) { 17409a3aaf3SDag-Erling Smørgrav log_err("could not parse %s", name); 17509a3aaf3SDag-Erling Smørgrav return NULL; 17609a3aaf3SDag-Erling Smørgrav } 17709a3aaf3SDag-Erling Smørgrav labs = dname_count_labels(nm); 17809a3aaf3SDag-Erling Smørgrav 17909a3aaf3SDag-Erling Smørgrav /* can we find it? */ 180*be771a7bSCy Schubert d = (struct domain_limit_data*)name_tree_find(domain_limits, nm, 181*be771a7bSCy Schubert nmlen, labs, LDNS_RR_CLASS_IN); 18209a3aaf3SDag-Erling Smørgrav if(d) { 18309a3aaf3SDag-Erling Smørgrav free(nm); 18409a3aaf3SDag-Erling Smørgrav return d; 18509a3aaf3SDag-Erling Smørgrav } 18609a3aaf3SDag-Erling Smørgrav 18709a3aaf3SDag-Erling Smørgrav /* create it */ 18809a3aaf3SDag-Erling Smørgrav d = (struct domain_limit_data*)calloc(1, sizeof(*d)); 18909a3aaf3SDag-Erling Smørgrav if(!d) { 19009a3aaf3SDag-Erling Smørgrav free(nm); 19109a3aaf3SDag-Erling Smørgrav return NULL; 19209a3aaf3SDag-Erling Smørgrav } 19309a3aaf3SDag-Erling Smørgrav d->node.node.key = &d->node; 19409a3aaf3SDag-Erling Smørgrav d->node.name = nm; 19509a3aaf3SDag-Erling Smørgrav d->node.len = nmlen; 19609a3aaf3SDag-Erling Smørgrav d->node.labs = labs; 19709a3aaf3SDag-Erling Smørgrav d->node.dclass = LDNS_RR_CLASS_IN; 19809a3aaf3SDag-Erling Smørgrav d->lim = -1; 19909a3aaf3SDag-Erling Smørgrav d->below = -1; 200*be771a7bSCy Schubert if(!name_tree_insert(domain_limits, &d->node, nm, nmlen, labs, 201*be771a7bSCy Schubert LDNS_RR_CLASS_IN)) { 20209a3aaf3SDag-Erling Smørgrav log_err("duplicate element in domainlimit tree"); 20309a3aaf3SDag-Erling Smørgrav free(nm); 20409a3aaf3SDag-Erling Smørgrav free(d); 20509a3aaf3SDag-Erling Smørgrav return NULL; 20609a3aaf3SDag-Erling Smørgrav } 20709a3aaf3SDag-Erling Smørgrav return d; 20809a3aaf3SDag-Erling Smørgrav } 20909a3aaf3SDag-Erling Smørgrav 21009a3aaf3SDag-Erling Smørgrav /** insert rate limit configuration into lookup tree */ 211*be771a7bSCy Schubert static int infra_ratelimit_cfg_insert(struct rbtree_type* domain_limits, 21209a3aaf3SDag-Erling Smørgrav struct config_file* cfg) 21309a3aaf3SDag-Erling Smørgrav { 21409a3aaf3SDag-Erling Smørgrav struct config_str2list* p; 21509a3aaf3SDag-Erling Smørgrav struct domain_limit_data* d; 21609a3aaf3SDag-Erling Smørgrav for(p = cfg->ratelimit_for_domain; p; p = p->next) { 217*be771a7bSCy Schubert d = domain_limit_findcreate(domain_limits, p->str); 21809a3aaf3SDag-Erling Smørgrav if(!d) 21909a3aaf3SDag-Erling Smørgrav return 0; 22009a3aaf3SDag-Erling Smørgrav d->lim = atoi(p->str2); 22109a3aaf3SDag-Erling Smørgrav } 22209a3aaf3SDag-Erling Smørgrav for(p = cfg->ratelimit_below_domain; p; p = p->next) { 223*be771a7bSCy Schubert d = domain_limit_findcreate(domain_limits, p->str); 22409a3aaf3SDag-Erling Smørgrav if(!d) 22509a3aaf3SDag-Erling Smørgrav return 0; 22609a3aaf3SDag-Erling Smørgrav d->below = atoi(p->str2); 22709a3aaf3SDag-Erling Smørgrav } 22809a3aaf3SDag-Erling Smørgrav return 1; 22909a3aaf3SDag-Erling Smørgrav } 23009a3aaf3SDag-Erling Smørgrav 231*be771a7bSCy Schubert int 232*be771a7bSCy Schubert setup_domain_limits(struct rbtree_type* domain_limits, struct config_file* cfg) 2334c75e3aaSDag-Erling Smørgrav { 234*be771a7bSCy Schubert name_tree_init(domain_limits); 235*be771a7bSCy Schubert if(!infra_ratelimit_cfg_insert(domain_limits, cfg)) { 2364c75e3aaSDag-Erling Smørgrav return 0; 2374c75e3aaSDag-Erling Smørgrav } 238*be771a7bSCy Schubert name_tree_init_parents(domain_limits); 2394c75e3aaSDag-Erling Smørgrav return 1; 2404c75e3aaSDag-Erling Smørgrav } 2414c75e3aaSDag-Erling Smørgrav 242335c7cdaSCy Schubert /** find or create element in wait limit netblock tree */ 243335c7cdaSCy Schubert static struct wait_limit_netblock_info* 244*be771a7bSCy Schubert wait_limit_netblock_findcreate(struct rbtree_type* tree, char* str) 245335c7cdaSCy Schubert { 246335c7cdaSCy Schubert struct sockaddr_storage addr; 247335c7cdaSCy Schubert int net; 248335c7cdaSCy Schubert socklen_t addrlen; 249335c7cdaSCy Schubert struct wait_limit_netblock_info* d; 250335c7cdaSCy Schubert 251335c7cdaSCy Schubert if(!netblockstrtoaddr(str, 0, &addr, &addrlen, &net)) { 252335c7cdaSCy Schubert log_err("cannot parse wait limit netblock '%s'", str); 253335c7cdaSCy Schubert return 0; 254335c7cdaSCy Schubert } 255335c7cdaSCy Schubert 256335c7cdaSCy Schubert /* can we find it? */ 257335c7cdaSCy Schubert d = (struct wait_limit_netblock_info*)addr_tree_find(tree, &addr, 258335c7cdaSCy Schubert addrlen, net); 259335c7cdaSCy Schubert if(d) 260335c7cdaSCy Schubert return d; 261335c7cdaSCy Schubert 262335c7cdaSCy Schubert /* create it */ 263335c7cdaSCy Schubert d = (struct wait_limit_netblock_info*)calloc(1, sizeof(*d)); 264335c7cdaSCy Schubert if(!d) 265335c7cdaSCy Schubert return NULL; 266335c7cdaSCy Schubert d->limit = -1; 267335c7cdaSCy Schubert if(!addr_tree_insert(tree, &d->node, &addr, addrlen, net)) { 268335c7cdaSCy Schubert log_err("duplicate element in domainlimit tree"); 269335c7cdaSCy Schubert free(d); 270335c7cdaSCy Schubert return NULL; 271335c7cdaSCy Schubert } 272335c7cdaSCy Schubert return d; 273335c7cdaSCy Schubert } 274335c7cdaSCy Schubert 275335c7cdaSCy Schubert 276335c7cdaSCy Schubert /** insert wait limit information into lookup tree */ 277335c7cdaSCy Schubert static int 278*be771a7bSCy Schubert infra_wait_limit_netblock_insert(rbtree_type* wait_limits_netblock, 279*be771a7bSCy Schubert rbtree_type* wait_limits_cookie_netblock, struct config_file* cfg) 280335c7cdaSCy Schubert { 281335c7cdaSCy Schubert struct config_str2list* p; 282335c7cdaSCy Schubert struct wait_limit_netblock_info* d; 283335c7cdaSCy Schubert for(p = cfg->wait_limit_netblock; p; p = p->next) { 284*be771a7bSCy Schubert d = wait_limit_netblock_findcreate(wait_limits_netblock, 285*be771a7bSCy Schubert p->str); 286335c7cdaSCy Schubert if(!d) 287335c7cdaSCy Schubert return 0; 288335c7cdaSCy Schubert d->limit = atoi(p->str2); 289335c7cdaSCy Schubert } 290335c7cdaSCy Schubert for(p = cfg->wait_limit_cookie_netblock; p; p = p->next) { 291*be771a7bSCy Schubert d = wait_limit_netblock_findcreate(wait_limits_cookie_netblock, 292*be771a7bSCy Schubert p->str); 293335c7cdaSCy Schubert if(!d) 294335c7cdaSCy Schubert return 0; 295335c7cdaSCy Schubert d->limit = atoi(p->str2); 296335c7cdaSCy Schubert } 297335c7cdaSCy Schubert return 1; 298335c7cdaSCy Schubert } 299335c7cdaSCy Schubert 300*be771a7bSCy Schubert /** Add a default wait limit netblock */ 301335c7cdaSCy Schubert static int 302*be771a7bSCy Schubert wait_limit_netblock_default(struct rbtree_type* tree, char* str, int limit) 303335c7cdaSCy Schubert { 304*be771a7bSCy Schubert struct wait_limit_netblock_info* d; 305*be771a7bSCy Schubert d = wait_limit_netblock_findcreate(tree, str); 306*be771a7bSCy Schubert if(!d) 307335c7cdaSCy Schubert return 0; 308*be771a7bSCy Schubert d->limit = limit; 309*be771a7bSCy Schubert return 1; 310*be771a7bSCy Schubert } 311*be771a7bSCy Schubert 312*be771a7bSCy Schubert int 313*be771a7bSCy Schubert setup_wait_limits(rbtree_type* wait_limits_netblock, 314*be771a7bSCy Schubert rbtree_type* wait_limits_cookie_netblock, struct config_file* cfg) 315*be771a7bSCy Schubert { 316*be771a7bSCy Schubert addr_tree_init(wait_limits_netblock); 317*be771a7bSCy Schubert addr_tree_init(wait_limits_cookie_netblock); 318*be771a7bSCy Schubert 319*be771a7bSCy Schubert /* Insert defaults */ 320*be771a7bSCy Schubert /* The loopback address is separated from the rest of the network. */ 321*be771a7bSCy Schubert /* wait-limit-netblock: 127.0.0.0/8 -1 */ 322*be771a7bSCy Schubert if(!wait_limit_netblock_default(wait_limits_netblock, "127.0.0.0/8", 323*be771a7bSCy Schubert -1)) 324*be771a7bSCy Schubert return 0; 325*be771a7bSCy Schubert /* wait-limit-netblock: ::1/128 -1 */ 326*be771a7bSCy Schubert if(!wait_limit_netblock_default(wait_limits_netblock, "::1/128", -1)) 327*be771a7bSCy Schubert return 0; 328*be771a7bSCy Schubert /* wait-limit-cookie-netblock: 127.0.0.0/8 -1 */ 329*be771a7bSCy Schubert if(!wait_limit_netblock_default(wait_limits_cookie_netblock, 330*be771a7bSCy Schubert "127.0.0.0/8", -1)) 331*be771a7bSCy Schubert return 0; 332*be771a7bSCy Schubert /* wait-limit-cookie-netblock: ::1/128 -1 */ 333*be771a7bSCy Schubert if(!wait_limit_netblock_default(wait_limits_cookie_netblock, 334*be771a7bSCy Schubert "::1/128", -1)) 335*be771a7bSCy Schubert return 0; 336*be771a7bSCy Schubert 337*be771a7bSCy Schubert if(!infra_wait_limit_netblock_insert(wait_limits_netblock, 338*be771a7bSCy Schubert wait_limits_cookie_netblock, cfg)) 339*be771a7bSCy Schubert return 0; 340*be771a7bSCy Schubert addr_tree_init_parents(wait_limits_netblock); 341*be771a7bSCy Schubert addr_tree_init_parents(wait_limits_cookie_netblock); 342335c7cdaSCy Schubert return 1; 343335c7cdaSCy Schubert } 344335c7cdaSCy Schubert 345b7579f77SDag-Erling Smørgrav struct infra_cache* 346b7579f77SDag-Erling Smørgrav infra_create(struct config_file* cfg) 347b7579f77SDag-Erling Smørgrav { 348b7579f77SDag-Erling Smørgrav struct infra_cache* infra = (struct infra_cache*)calloc(1, 349b7579f77SDag-Erling Smørgrav sizeof(struct infra_cache)); 350b7579f77SDag-Erling Smørgrav size_t maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+ 351b7579f77SDag-Erling Smørgrav sizeof(struct infra_data)+INFRA_BYTES_NAME); 3525469a995SCy Schubert if(!infra) { 3535469a995SCy Schubert return NULL; 3545469a995SCy Schubert } 355b7579f77SDag-Erling Smørgrav infra->hosts = slabhash_create(cfg->infra_cache_slabs, 356b7579f77SDag-Erling Smørgrav INFRA_HOST_STARTSIZE, maxmem, &infra_sizefunc, &infra_compfunc, 357b7579f77SDag-Erling Smørgrav &infra_delkeyfunc, &infra_deldatafunc, NULL); 358b7579f77SDag-Erling Smørgrav if(!infra->hosts) { 359b7579f77SDag-Erling Smørgrav free(infra); 360b7579f77SDag-Erling Smørgrav return NULL; 361b7579f77SDag-Erling Smørgrav } 362b7579f77SDag-Erling Smørgrav infra->host_ttl = cfg->host_ttl; 363369c6923SCy Schubert infra->infra_keep_probing = cfg->infra_keep_probing; 36409a3aaf3SDag-Erling Smørgrav infra_dp_ratelimit = cfg->ratelimit; 36509a3aaf3SDag-Erling Smørgrav infra->domain_rates = slabhash_create(cfg->ratelimit_slabs, 36609a3aaf3SDag-Erling Smørgrav INFRA_HOST_STARTSIZE, cfg->ratelimit_size, 36709a3aaf3SDag-Erling Smørgrav &rate_sizefunc, &rate_compfunc, &rate_delkeyfunc, 36809a3aaf3SDag-Erling Smørgrav &rate_deldatafunc, NULL); 36909a3aaf3SDag-Erling Smørgrav if(!infra->domain_rates) { 37009a3aaf3SDag-Erling Smørgrav infra_delete(infra); 37109a3aaf3SDag-Erling Smørgrav return NULL; 37209a3aaf3SDag-Erling Smørgrav } 37309a3aaf3SDag-Erling Smørgrav /* insert config data into ratelimits */ 374*be771a7bSCy Schubert if(!setup_domain_limits(&infra->domain_limits, cfg)) { 37509a3aaf3SDag-Erling Smørgrav infra_delete(infra); 37609a3aaf3SDag-Erling Smørgrav return NULL; 37709a3aaf3SDag-Erling Smørgrav } 378*be771a7bSCy Schubert if(!setup_wait_limits(&infra->wait_limits_netblock, 379*be771a7bSCy Schubert &infra->wait_limits_cookie_netblock, cfg)) { 380335c7cdaSCy Schubert infra_delete(infra); 381335c7cdaSCy Schubert return NULL; 382335c7cdaSCy Schubert } 3833005e0a3SDag-Erling Smørgrav infra_ip_ratelimit = cfg->ip_ratelimit; 38456850988SCy Schubert infra_ip_ratelimit_cookie = cfg->ip_ratelimit_cookie; 385971980c3SDag-Erling Smørgrav infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs, 3863005e0a3SDag-Erling Smørgrav INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc, 3873005e0a3SDag-Erling Smørgrav &ip_rate_compfunc, &ip_rate_delkeyfunc, &ip_rate_deldatafunc, NULL); 3883005e0a3SDag-Erling Smørgrav if(!infra->client_ip_rates) { 3893005e0a3SDag-Erling Smørgrav infra_delete(infra); 3903005e0a3SDag-Erling Smørgrav return NULL; 3913005e0a3SDag-Erling Smørgrav } 392b7579f77SDag-Erling Smørgrav return infra; 393b7579f77SDag-Erling Smørgrav } 394b7579f77SDag-Erling Smørgrav 39509a3aaf3SDag-Erling Smørgrav /** delete domain_limit entries */ 3963005e0a3SDag-Erling Smørgrav static void domain_limit_free(rbnode_type* n, void* ATTR_UNUSED(arg)) 39709a3aaf3SDag-Erling Smørgrav { 39809a3aaf3SDag-Erling Smørgrav if(n) { 39909a3aaf3SDag-Erling Smørgrav free(((struct domain_limit_data*)n)->node.name); 40009a3aaf3SDag-Erling Smørgrav free(n); 40109a3aaf3SDag-Erling Smørgrav } 40209a3aaf3SDag-Erling Smørgrav } 40309a3aaf3SDag-Erling Smørgrav 404*be771a7bSCy Schubert void 405*be771a7bSCy Schubert domain_limits_free(struct rbtree_type* domain_limits) 406*be771a7bSCy Schubert { 407*be771a7bSCy Schubert if(!domain_limits) 408*be771a7bSCy Schubert return; 409*be771a7bSCy Schubert traverse_postorder(domain_limits, domain_limit_free, NULL); 410*be771a7bSCy Schubert } 411*be771a7bSCy Schubert 412335c7cdaSCy Schubert /** delete wait_limit_netblock_info entries */ 413335c7cdaSCy Schubert static void wait_limit_netblock_del(rbnode_type* n, void* ATTR_UNUSED(arg)) 414335c7cdaSCy Schubert { 415335c7cdaSCy Schubert free(n); 416335c7cdaSCy Schubert } 417335c7cdaSCy Schubert 418b7579f77SDag-Erling Smørgrav void 419*be771a7bSCy Schubert wait_limits_free(struct rbtree_type* wait_limits_tree) 420*be771a7bSCy Schubert { 421*be771a7bSCy Schubert if(!wait_limits_tree) 422*be771a7bSCy Schubert return; 423*be771a7bSCy Schubert traverse_postorder(wait_limits_tree, wait_limit_netblock_del, 424*be771a7bSCy Schubert NULL); 425*be771a7bSCy Schubert } 426*be771a7bSCy Schubert 427*be771a7bSCy Schubert void 428b7579f77SDag-Erling Smørgrav infra_delete(struct infra_cache* infra) 429b7579f77SDag-Erling Smørgrav { 430b7579f77SDag-Erling Smørgrav if(!infra) 431b7579f77SDag-Erling Smørgrav return; 432b7579f77SDag-Erling Smørgrav slabhash_delete(infra->hosts); 43309a3aaf3SDag-Erling Smørgrav slabhash_delete(infra->domain_rates); 434*be771a7bSCy Schubert domain_limits_free(&infra->domain_limits); 4353005e0a3SDag-Erling Smørgrav slabhash_delete(infra->client_ip_rates); 436*be771a7bSCy Schubert wait_limits_free(&infra->wait_limits_netblock); 437*be771a7bSCy Schubert wait_limits_free(&infra->wait_limits_cookie_netblock); 438b7579f77SDag-Erling Smørgrav free(infra); 439b7579f77SDag-Erling Smørgrav } 440b7579f77SDag-Erling Smørgrav 441b7579f77SDag-Erling Smørgrav struct infra_cache* 442b7579f77SDag-Erling Smørgrav infra_adjust(struct infra_cache* infra, struct config_file* cfg) 443b7579f77SDag-Erling Smørgrav { 444b7579f77SDag-Erling Smørgrav size_t maxmem; 445b7579f77SDag-Erling Smørgrav if(!infra) 446b7579f77SDag-Erling Smørgrav return infra_create(cfg); 447b7579f77SDag-Erling Smørgrav infra->host_ttl = cfg->host_ttl; 448369c6923SCy Schubert infra->infra_keep_probing = cfg->infra_keep_probing; 4494c75e3aaSDag-Erling Smørgrav infra_dp_ratelimit = cfg->ratelimit; 4504c75e3aaSDag-Erling Smørgrav infra_ip_ratelimit = cfg->ip_ratelimit; 45156850988SCy Schubert infra_ip_ratelimit_cookie = cfg->ip_ratelimit_cookie; 452b7579f77SDag-Erling Smørgrav maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+ 453b7579f77SDag-Erling Smørgrav sizeof(struct infra_data)+INFRA_BYTES_NAME); 4544c75e3aaSDag-Erling Smørgrav /* divide cachesize by slabs and multiply by slabs, because if the 4554c75e3aaSDag-Erling Smørgrav * cachesize is not an even multiple of slabs, that is the resulting 4564c75e3aaSDag-Erling Smørgrav * size of the slabhash */ 4574c75e3aaSDag-Erling Smørgrav if(!slabhash_is_size(infra->hosts, maxmem, cfg->infra_cache_slabs) || 4584c75e3aaSDag-Erling Smørgrav !slabhash_is_size(infra->domain_rates, cfg->ratelimit_size, 4594c75e3aaSDag-Erling Smørgrav cfg->ratelimit_slabs) || 4604c75e3aaSDag-Erling Smørgrav !slabhash_is_size(infra->client_ip_rates, cfg->ip_ratelimit_size, 4614c75e3aaSDag-Erling Smørgrav cfg->ip_ratelimit_slabs)) { 462b7579f77SDag-Erling Smørgrav infra_delete(infra); 463b7579f77SDag-Erling Smørgrav infra = infra_create(cfg); 4644c75e3aaSDag-Erling Smørgrav } else { 4654c75e3aaSDag-Erling Smørgrav /* reapply domain limits */ 4664c75e3aaSDag-Erling Smørgrav traverse_postorder(&infra->domain_limits, domain_limit_free, 4674c75e3aaSDag-Erling Smørgrav NULL); 468*be771a7bSCy Schubert if(!setup_domain_limits(&infra->domain_limits, cfg)) { 4694c75e3aaSDag-Erling Smørgrav infra_delete(infra); 4704c75e3aaSDag-Erling Smørgrav return NULL; 4714c75e3aaSDag-Erling Smørgrav } 472b7579f77SDag-Erling Smørgrav } 473b7579f77SDag-Erling Smørgrav return infra; 474b7579f77SDag-Erling Smørgrav } 475b7579f77SDag-Erling Smørgrav 4763005e0a3SDag-Erling Smørgrav /** calculate the hash value for a host key 4773005e0a3SDag-Erling Smørgrav * set use_port to a non-0 number to use the port in 4783005e0a3SDag-Erling Smørgrav * the hash calculation; 0 to ignore the port.*/ 4793005e0a3SDag-Erling Smørgrav static hashvalue_type 4803005e0a3SDag-Erling Smørgrav hash_addr(struct sockaddr_storage* addr, socklen_t addrlen, 4813005e0a3SDag-Erling Smørgrav int use_port) 482b7579f77SDag-Erling Smørgrav { 4833005e0a3SDag-Erling Smørgrav hashvalue_type h = 0xab; 484b7579f77SDag-Erling Smørgrav /* select the pieces to hash, some OS have changing data inside */ 485b7579f77SDag-Erling Smørgrav if(addr_is_ip6(addr, addrlen)) { 486b7579f77SDag-Erling Smørgrav struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr; 487b7579f77SDag-Erling Smørgrav h = hashlittle(&in6->sin6_family, sizeof(in6->sin6_family), h); 4883005e0a3SDag-Erling Smørgrav if(use_port){ 489b7579f77SDag-Erling Smørgrav h = hashlittle(&in6->sin6_port, sizeof(in6->sin6_port), h); 4903005e0a3SDag-Erling Smørgrav } 491b7579f77SDag-Erling Smørgrav h = hashlittle(&in6->sin6_addr, INET6_SIZE, h); 492b7579f77SDag-Erling Smørgrav } else { 493b7579f77SDag-Erling Smørgrav struct sockaddr_in* in = (struct sockaddr_in*)addr; 494b7579f77SDag-Erling Smørgrav h = hashlittle(&in->sin_family, sizeof(in->sin_family), h); 4953005e0a3SDag-Erling Smørgrav if(use_port){ 496b7579f77SDag-Erling Smørgrav h = hashlittle(&in->sin_port, sizeof(in->sin_port), h); 4973005e0a3SDag-Erling Smørgrav } 498b7579f77SDag-Erling Smørgrav h = hashlittle(&in->sin_addr, INET_SIZE, h); 499b7579f77SDag-Erling Smørgrav } 500b7579f77SDag-Erling Smørgrav return h; 501b7579f77SDag-Erling Smørgrav } 502b7579f77SDag-Erling Smørgrav 503b7579f77SDag-Erling Smørgrav /** calculate infra hash for a key */ 5043005e0a3SDag-Erling Smørgrav static hashvalue_type 505b7579f77SDag-Erling Smørgrav hash_infra(struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name) 506b7579f77SDag-Erling Smørgrav { 5073005e0a3SDag-Erling Smørgrav return dname_query_hash(name, hash_addr(addr, addrlen, 1)); 508b7579f77SDag-Erling Smørgrav } 509b7579f77SDag-Erling Smørgrav 510b7579f77SDag-Erling Smørgrav /** lookup version that does not check host ttl (you check it) */ 511b7579f77SDag-Erling Smørgrav struct lruhash_entry* 512b7579f77SDag-Erling Smørgrav infra_lookup_nottl(struct infra_cache* infra, struct sockaddr_storage* addr, 513b7579f77SDag-Erling Smørgrav socklen_t addrlen, uint8_t* name, size_t namelen, int wr) 514b7579f77SDag-Erling Smørgrav { 515b7579f77SDag-Erling Smørgrav struct infra_key k; 516b7579f77SDag-Erling Smørgrav k.addrlen = addrlen; 517b7579f77SDag-Erling Smørgrav memcpy(&k.addr, addr, addrlen); 518b7579f77SDag-Erling Smørgrav k.namelen = namelen; 519b7579f77SDag-Erling Smørgrav k.zonename = name; 520b7579f77SDag-Erling Smørgrav k.entry.hash = hash_infra(addr, addrlen, name); 521b7579f77SDag-Erling Smørgrav k.entry.key = (void*)&k; 522b7579f77SDag-Erling Smørgrav k.entry.data = NULL; 523b7579f77SDag-Erling Smørgrav return slabhash_lookup(infra->hosts, k.entry.hash, &k, wr); 524b7579f77SDag-Erling Smørgrav } 525b7579f77SDag-Erling Smørgrav 526b7579f77SDag-Erling Smørgrav /** init the data elements */ 527b7579f77SDag-Erling Smørgrav static void 528b7579f77SDag-Erling Smørgrav data_entry_init(struct infra_cache* infra, struct lruhash_entry* e, 52917d15b25SDag-Erling Smørgrav time_t timenow) 530b7579f77SDag-Erling Smørgrav { 531b7579f77SDag-Erling Smørgrav struct infra_data* data = (struct infra_data*)e->data; 532b7579f77SDag-Erling Smørgrav data->ttl = timenow + infra->host_ttl; 533b7579f77SDag-Erling Smørgrav rtt_init(&data->rtt); 534b7579f77SDag-Erling Smørgrav data->edns_version = 0; 535b7579f77SDag-Erling Smørgrav data->edns_lame_known = 0; 536b7579f77SDag-Erling Smørgrav data->probedelay = 0; 537b7579f77SDag-Erling Smørgrav data->isdnsseclame = 0; 538b7579f77SDag-Erling Smørgrav data->rec_lame = 0; 539b7579f77SDag-Erling Smørgrav data->lame_type_A = 0; 540b7579f77SDag-Erling Smørgrav data->lame_other = 0; 541b7579f77SDag-Erling Smørgrav data->timeout_A = 0; 542b7579f77SDag-Erling Smørgrav data->timeout_AAAA = 0; 543b7579f77SDag-Erling Smørgrav data->timeout_other = 0; 544b7579f77SDag-Erling Smørgrav } 545b7579f77SDag-Erling Smørgrav 546b7579f77SDag-Erling Smørgrav /** 547b7579f77SDag-Erling Smørgrav * Create and init a new entry for a host 548b7579f77SDag-Erling Smørgrav * @param infra: infra structure with config parameters. 549b7579f77SDag-Erling Smørgrav * @param addr: host address. 550b7579f77SDag-Erling Smørgrav * @param addrlen: length of addr. 551b7579f77SDag-Erling Smørgrav * @param name: name of zone 552b7579f77SDag-Erling Smørgrav * @param namelen: length of name. 553b7579f77SDag-Erling Smørgrav * @param tm: time now. 554b7579f77SDag-Erling Smørgrav * @return: the new entry or NULL on malloc failure. 555b7579f77SDag-Erling Smørgrav */ 556b7579f77SDag-Erling Smørgrav static struct lruhash_entry* 557b7579f77SDag-Erling Smørgrav new_entry(struct infra_cache* infra, struct sockaddr_storage* addr, 55817d15b25SDag-Erling Smørgrav socklen_t addrlen, uint8_t* name, size_t namelen, time_t tm) 559b7579f77SDag-Erling Smørgrav { 560b7579f77SDag-Erling Smørgrav struct infra_data* data; 561b7579f77SDag-Erling Smørgrav struct infra_key* key = (struct infra_key*)malloc(sizeof(*key)); 562b7579f77SDag-Erling Smørgrav if(!key) 563b7579f77SDag-Erling Smørgrav return NULL; 564b7579f77SDag-Erling Smørgrav data = (struct infra_data*)malloc(sizeof(struct infra_data)); 565b7579f77SDag-Erling Smørgrav if(!data) { 566b7579f77SDag-Erling Smørgrav free(key); 567b7579f77SDag-Erling Smørgrav return NULL; 568b7579f77SDag-Erling Smørgrav } 569b7579f77SDag-Erling Smørgrav key->zonename = memdup(name, namelen); 570b7579f77SDag-Erling Smørgrav if(!key->zonename) { 571b7579f77SDag-Erling Smørgrav free(key); 572b7579f77SDag-Erling Smørgrav free(data); 573b7579f77SDag-Erling Smørgrav return NULL; 574b7579f77SDag-Erling Smørgrav } 575b7579f77SDag-Erling Smørgrav key->namelen = namelen; 576b7579f77SDag-Erling Smørgrav lock_rw_init(&key->entry.lock); 577b7579f77SDag-Erling Smørgrav key->entry.hash = hash_infra(addr, addrlen, name); 578b7579f77SDag-Erling Smørgrav key->entry.key = (void*)key; 579b7579f77SDag-Erling Smørgrav key->entry.data = (void*)data; 580b7579f77SDag-Erling Smørgrav key->addrlen = addrlen; 581b7579f77SDag-Erling Smørgrav memcpy(&key->addr, addr, addrlen); 582b7579f77SDag-Erling Smørgrav data_entry_init(infra, &key->entry, tm); 583b7579f77SDag-Erling Smørgrav return &key->entry; 584b7579f77SDag-Erling Smørgrav } 585b7579f77SDag-Erling Smørgrav 586b7579f77SDag-Erling Smørgrav int 587b7579f77SDag-Erling Smørgrav infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, 58817d15b25SDag-Erling Smørgrav socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow, 589b7579f77SDag-Erling Smørgrav int* edns_vs, uint8_t* edns_lame_known, int* to) 590b7579f77SDag-Erling Smørgrav { 591b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 592b7579f77SDag-Erling Smørgrav nm, nmlen, 0); 593b7579f77SDag-Erling Smørgrav struct infra_data* data; 594b7579f77SDag-Erling Smørgrav int wr = 0; 595b7579f77SDag-Erling Smørgrav if(e && ((struct infra_data*)e->data)->ttl < timenow) { 596b7579f77SDag-Erling Smørgrav /* it expired, try to reuse existing entry */ 597b7579f77SDag-Erling Smørgrav int old = ((struct infra_data*)e->data)->rtt.rto; 598369c6923SCy Schubert time_t tprobe = ((struct infra_data*)e->data)->probedelay; 599b7579f77SDag-Erling Smørgrav uint8_t tA = ((struct infra_data*)e->data)->timeout_A; 600b7579f77SDag-Erling Smørgrav uint8_t tAAAA = ((struct infra_data*)e->data)->timeout_AAAA; 601b7579f77SDag-Erling Smørgrav uint8_t tother = ((struct infra_data*)e->data)->timeout_other; 602b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 603b7579f77SDag-Erling Smørgrav e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); 604b7579f77SDag-Erling Smørgrav if(e) { 605b7579f77SDag-Erling Smørgrav /* if its still there we have a writelock, init */ 606b7579f77SDag-Erling Smørgrav /* re-initialise */ 607b7579f77SDag-Erling Smørgrav /* do not touch lameness, it may be valid still */ 608b7579f77SDag-Erling Smørgrav data_entry_init(infra, e, timenow); 609b7579f77SDag-Erling Smørgrav wr = 1; 610b7579f77SDag-Erling Smørgrav /* TOP_TIMEOUT remains on reuse */ 611b7579f77SDag-Erling Smørgrav if(old >= USEFUL_SERVER_TOP_TIMEOUT) { 612b7579f77SDag-Erling Smørgrav ((struct infra_data*)e->data)->rtt.rto 613b7579f77SDag-Erling Smørgrav = USEFUL_SERVER_TOP_TIMEOUT; 614369c6923SCy Schubert ((struct infra_data*)e->data)->probedelay = tprobe; 615b7579f77SDag-Erling Smørgrav ((struct infra_data*)e->data)->timeout_A = tA; 616b7579f77SDag-Erling Smørgrav ((struct infra_data*)e->data)->timeout_AAAA = tAAAA; 617b7579f77SDag-Erling Smørgrav ((struct infra_data*)e->data)->timeout_other = tother; 618b7579f77SDag-Erling Smørgrav } 619b7579f77SDag-Erling Smørgrav } 620b7579f77SDag-Erling Smørgrav } 621b7579f77SDag-Erling Smørgrav if(!e) { 622b7579f77SDag-Erling Smørgrav /* insert new entry */ 623b7579f77SDag-Erling Smørgrav if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) 624b7579f77SDag-Erling Smørgrav return 0; 625b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 626b7579f77SDag-Erling Smørgrav *edns_vs = data->edns_version; 627b7579f77SDag-Erling Smørgrav *edns_lame_known = data->edns_lame_known; 628b7579f77SDag-Erling Smørgrav *to = rtt_timeout(&data->rtt); 629b7579f77SDag-Erling Smørgrav slabhash_insert(infra->hosts, e->hash, e, data, NULL); 630b7579f77SDag-Erling Smørgrav return 1; 631b7579f77SDag-Erling Smørgrav } 632b7579f77SDag-Erling Smørgrav /* use existing entry */ 633b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 634b7579f77SDag-Erling Smørgrav *edns_vs = data->edns_version; 635b7579f77SDag-Erling Smørgrav *edns_lame_known = data->edns_lame_known; 636b7579f77SDag-Erling Smørgrav *to = rtt_timeout(&data->rtt); 637369c6923SCy Schubert if(*to >= PROBE_MAXRTO && (infra->infra_keep_probing || 638369c6923SCy Schubert rtt_notimeout(&data->rtt)*4 <= *to)) { 639b7579f77SDag-Erling Smørgrav /* delay other queries, this is the probe query */ 640b7579f77SDag-Erling Smørgrav if(!wr) { 641b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 642b7579f77SDag-Erling Smørgrav e = infra_lookup_nottl(infra, addr,addrlen,nm,nmlen, 1); 643b7579f77SDag-Erling Smørgrav if(!e) { /* flushed from cache real fast, no use to 644b7579f77SDag-Erling Smørgrav allocate just for the probedelay */ 645b7579f77SDag-Erling Smørgrav return 1; 646b7579f77SDag-Erling Smørgrav } 647b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 648b7579f77SDag-Erling Smørgrav } 649b7579f77SDag-Erling Smørgrav /* add 999 to round up the timeout value from msec to sec, 650b7579f77SDag-Erling Smørgrav * then add a whole second so it is certain that this probe 651b7579f77SDag-Erling Smørgrav * has timed out before the next is allowed */ 652b7579f77SDag-Erling Smørgrav data->probedelay = timenow + ((*to)+1999)/1000; 653b7579f77SDag-Erling Smørgrav } 654b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 655b7579f77SDag-Erling Smørgrav return 1; 656b7579f77SDag-Erling Smørgrav } 657b7579f77SDag-Erling Smørgrav 658b7579f77SDag-Erling Smørgrav int 659b7579f77SDag-Erling Smørgrav infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr, 66017d15b25SDag-Erling Smørgrav socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow, 661b7579f77SDag-Erling Smørgrav int dnsseclame, int reclame, uint16_t qtype) 662b7579f77SDag-Erling Smørgrav { 663b7579f77SDag-Erling Smørgrav struct infra_data* data; 664b7579f77SDag-Erling Smørgrav struct lruhash_entry* e; 665b7579f77SDag-Erling Smørgrav int needtoinsert = 0; 666b7579f77SDag-Erling Smørgrav e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); 667b7579f77SDag-Erling Smørgrav if(!e) { 668b7579f77SDag-Erling Smørgrav /* insert it */ 669b7579f77SDag-Erling Smørgrav if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) { 670b7579f77SDag-Erling Smørgrav log_err("set_lame: malloc failure"); 671b7579f77SDag-Erling Smørgrav return 0; 672b7579f77SDag-Erling Smørgrav } 673b7579f77SDag-Erling Smørgrav needtoinsert = 1; 674b7579f77SDag-Erling Smørgrav } else if( ((struct infra_data*)e->data)->ttl < timenow) { 675b7579f77SDag-Erling Smørgrav /* expired, reuse existing entry */ 676b7579f77SDag-Erling Smørgrav data_entry_init(infra, e, timenow); 677b7579f77SDag-Erling Smørgrav } 678b7579f77SDag-Erling Smørgrav /* got an entry, now set the zone lame */ 679b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 680b7579f77SDag-Erling Smørgrav /* merge data (if any) */ 681b7579f77SDag-Erling Smørgrav if(dnsseclame) 682b7579f77SDag-Erling Smørgrav data->isdnsseclame = 1; 683b7579f77SDag-Erling Smørgrav if(reclame) 684b7579f77SDag-Erling Smørgrav data->rec_lame = 1; 685b7579f77SDag-Erling Smørgrav if(!dnsseclame && !reclame && qtype == LDNS_RR_TYPE_A) 686b7579f77SDag-Erling Smørgrav data->lame_type_A = 1; 687b7579f77SDag-Erling Smørgrav if(!dnsseclame && !reclame && qtype != LDNS_RR_TYPE_A) 688b7579f77SDag-Erling Smørgrav data->lame_other = 1; 689b7579f77SDag-Erling Smørgrav /* done */ 690b7579f77SDag-Erling Smørgrav if(needtoinsert) 691b7579f77SDag-Erling Smørgrav slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); 692b7579f77SDag-Erling Smørgrav else { lock_rw_unlock(&e->lock); } 693b7579f77SDag-Erling Smørgrav return 1; 694b7579f77SDag-Erling Smørgrav } 695b7579f77SDag-Erling Smørgrav 696b7579f77SDag-Erling Smørgrav void 697b7579f77SDag-Erling Smørgrav infra_update_tcp_works(struct infra_cache* infra, 698b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, 699b7579f77SDag-Erling Smørgrav size_t nmlen) 700b7579f77SDag-Erling Smørgrav { 701b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 702b7579f77SDag-Erling Smørgrav nm, nmlen, 1); 703b7579f77SDag-Erling Smørgrav struct infra_data* data; 704b7579f77SDag-Erling Smørgrav if(!e) 705b7579f77SDag-Erling Smørgrav return; /* doesn't exist */ 706b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 707b7579f77SDag-Erling Smørgrav if(data->rtt.rto >= RTT_MAX_TIMEOUT) 708b7579f77SDag-Erling Smørgrav /* do not disqualify this server altogether, it is better 709b7579f77SDag-Erling Smørgrav * than nothing */ 710*be771a7bSCy Schubert data->rtt.rto = still_useful_timeout(); 711b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 712b7579f77SDag-Erling Smørgrav } 713b7579f77SDag-Erling Smørgrav 714b7579f77SDag-Erling Smørgrav int 715b7579f77SDag-Erling Smørgrav infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, 716b7579f77SDag-Erling Smørgrav socklen_t addrlen, uint8_t* nm, size_t nmlen, int qtype, 71717d15b25SDag-Erling Smørgrav int roundtrip, int orig_rtt, time_t timenow) 718b7579f77SDag-Erling Smørgrav { 719b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 720b7579f77SDag-Erling Smørgrav nm, nmlen, 1); 721b7579f77SDag-Erling Smørgrav struct infra_data* data; 722369c6923SCy Schubert int needtoinsert = 0, expired = 0; 723b7579f77SDag-Erling Smørgrav int rto = 1; 724369c6923SCy Schubert time_t oldprobedelay = 0; 725b7579f77SDag-Erling Smørgrav if(!e) { 726b7579f77SDag-Erling Smørgrav if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) 727b7579f77SDag-Erling Smørgrav return 0; 728b7579f77SDag-Erling Smørgrav needtoinsert = 1; 729b7579f77SDag-Erling Smørgrav } else if(((struct infra_data*)e->data)->ttl < timenow) { 730369c6923SCy Schubert oldprobedelay = ((struct infra_data*)e->data)->probedelay; 731b7579f77SDag-Erling Smørgrav data_entry_init(infra, e, timenow); 732369c6923SCy Schubert expired = 1; 733b7579f77SDag-Erling Smørgrav } 734b7579f77SDag-Erling Smørgrav /* have an entry, update the rtt */ 735b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 736b7579f77SDag-Erling Smørgrav if(roundtrip == -1) { 737369c6923SCy Schubert if(needtoinsert || expired) { 738369c6923SCy Schubert /* timeout on entry that has expired before the timer 739369c6923SCy Schubert * keep old timeout from the function caller */ 740369c6923SCy Schubert data->rtt.rto = orig_rtt; 741369c6923SCy Schubert data->probedelay = oldprobedelay; 742369c6923SCy Schubert } 743b7579f77SDag-Erling Smørgrav rtt_lost(&data->rtt, orig_rtt); 744b7579f77SDag-Erling Smørgrav if(qtype == LDNS_RR_TYPE_A) { 745b7579f77SDag-Erling Smørgrav if(data->timeout_A < TIMEOUT_COUNT_MAX) 746b7579f77SDag-Erling Smørgrav data->timeout_A++; 747b7579f77SDag-Erling Smørgrav } else if(qtype == LDNS_RR_TYPE_AAAA) { 748b7579f77SDag-Erling Smørgrav if(data->timeout_AAAA < TIMEOUT_COUNT_MAX) 749b7579f77SDag-Erling Smørgrav data->timeout_AAAA++; 750b7579f77SDag-Erling Smørgrav } else { 751b7579f77SDag-Erling Smørgrav if(data->timeout_other < TIMEOUT_COUNT_MAX) 752b7579f77SDag-Erling Smørgrav data->timeout_other++; 753b7579f77SDag-Erling Smørgrav } 754b7579f77SDag-Erling Smørgrav } else { 7558ed2b524SDag-Erling Smørgrav /* if we got a reply, but the old timeout was above server 7568ed2b524SDag-Erling Smørgrav * selection height, delete the timeout so the server is 7578ed2b524SDag-Erling Smørgrav * fully available again */ 7588ed2b524SDag-Erling Smørgrav if(rtt_unclamped(&data->rtt) >= USEFUL_SERVER_TOP_TIMEOUT) 7598ed2b524SDag-Erling Smørgrav rtt_init(&data->rtt); 760b7579f77SDag-Erling Smørgrav rtt_update(&data->rtt, roundtrip); 761b7579f77SDag-Erling Smørgrav data->probedelay = 0; 762b7579f77SDag-Erling Smørgrav if(qtype == LDNS_RR_TYPE_A) 763b7579f77SDag-Erling Smørgrav data->timeout_A = 0; 764b7579f77SDag-Erling Smørgrav else if(qtype == LDNS_RR_TYPE_AAAA) 765b7579f77SDag-Erling Smørgrav data->timeout_AAAA = 0; 766b7579f77SDag-Erling Smørgrav else data->timeout_other = 0; 767b7579f77SDag-Erling Smørgrav } 768b7579f77SDag-Erling Smørgrav if(data->rtt.rto > 0) 769b7579f77SDag-Erling Smørgrav rto = data->rtt.rto; 770b7579f77SDag-Erling Smørgrav 771b7579f77SDag-Erling Smørgrav if(needtoinsert) 772b7579f77SDag-Erling Smørgrav slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); 773b7579f77SDag-Erling Smørgrav else { lock_rw_unlock(&e->lock); } 774b7579f77SDag-Erling Smørgrav return rto; 775b7579f77SDag-Erling Smørgrav } 776b7579f77SDag-Erling Smørgrav 77717d15b25SDag-Erling Smørgrav long long infra_get_host_rto(struct infra_cache* infra, 778b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, 77917d15b25SDag-Erling Smørgrav size_t nmlen, struct rtt_info* rtt, int* delay, time_t timenow, 780b7579f77SDag-Erling Smørgrav int* tA, int* tAAAA, int* tother) 781b7579f77SDag-Erling Smørgrav { 782b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 783b7579f77SDag-Erling Smørgrav nm, nmlen, 0); 784b7579f77SDag-Erling Smørgrav struct infra_data* data; 78517d15b25SDag-Erling Smørgrav long long ttl = -2; 786b7579f77SDag-Erling Smørgrav if(!e) return -1; 787b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 788b7579f77SDag-Erling Smørgrav if(data->ttl >= timenow) { 78917d15b25SDag-Erling Smørgrav ttl = (long long)(data->ttl - timenow); 790b7579f77SDag-Erling Smørgrav memmove(rtt, &data->rtt, sizeof(*rtt)); 791b7579f77SDag-Erling Smørgrav if(timenow < data->probedelay) 792b7579f77SDag-Erling Smørgrav *delay = (int)(data->probedelay - timenow); 793b7579f77SDag-Erling Smørgrav else *delay = 0; 794b7579f77SDag-Erling Smørgrav } 795b7579f77SDag-Erling Smørgrav *tA = (int)data->timeout_A; 796b7579f77SDag-Erling Smørgrav *tAAAA = (int)data->timeout_AAAA; 797b7579f77SDag-Erling Smørgrav *tother = (int)data->timeout_other; 798b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 799b7579f77SDag-Erling Smørgrav return ttl; 800b7579f77SDag-Erling Smørgrav } 801b7579f77SDag-Erling Smørgrav 802b7579f77SDag-Erling Smørgrav int 803b7579f77SDag-Erling Smørgrav infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr, 804b7579f77SDag-Erling Smørgrav socklen_t addrlen, uint8_t* nm, size_t nmlen, int edns_version, 80517d15b25SDag-Erling Smørgrav time_t timenow) 806b7579f77SDag-Erling Smørgrav { 807b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 808b7579f77SDag-Erling Smørgrav nm, nmlen, 1); 809b7579f77SDag-Erling Smørgrav struct infra_data* data; 810b7579f77SDag-Erling Smørgrav int needtoinsert = 0; 811b7579f77SDag-Erling Smørgrav if(!e) { 812b7579f77SDag-Erling Smørgrav if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) 813b7579f77SDag-Erling Smørgrav return 0; 814b7579f77SDag-Erling Smørgrav needtoinsert = 1; 815b7579f77SDag-Erling Smørgrav } else if(((struct infra_data*)e->data)->ttl < timenow) { 816b7579f77SDag-Erling Smørgrav data_entry_init(infra, e, timenow); 817b7579f77SDag-Erling Smørgrav } 818b7579f77SDag-Erling Smørgrav /* have an entry, update the rtt, and the ttl */ 819b7579f77SDag-Erling Smørgrav data = (struct infra_data*)e->data; 820b7579f77SDag-Erling Smørgrav /* do not update if noEDNS and stored is yesEDNS */ 821b7579f77SDag-Erling Smørgrav if(!(edns_version == -1 && (data->edns_version != -1 && 822b7579f77SDag-Erling Smørgrav data->edns_lame_known))) { 823b7579f77SDag-Erling Smørgrav data->edns_version = edns_version; 824b7579f77SDag-Erling Smørgrav data->edns_lame_known = 1; 825b7579f77SDag-Erling Smørgrav } 826b7579f77SDag-Erling Smørgrav 827b7579f77SDag-Erling Smørgrav if(needtoinsert) 828b7579f77SDag-Erling Smørgrav slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); 829b7579f77SDag-Erling Smørgrav else { lock_rw_unlock(&e->lock); } 830b7579f77SDag-Erling Smørgrav return 1; 831b7579f77SDag-Erling Smørgrav } 832b7579f77SDag-Erling Smørgrav 833b7579f77SDag-Erling Smørgrav int 834b7579f77SDag-Erling Smørgrav infra_get_lame_rtt(struct infra_cache* infra, 835b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t addrlen, 836b7579f77SDag-Erling Smørgrav uint8_t* name, size_t namelen, uint16_t qtype, 83717d15b25SDag-Erling Smørgrav int* lame, int* dnsseclame, int* reclame, int* rtt, time_t timenow) 838b7579f77SDag-Erling Smørgrav { 839b7579f77SDag-Erling Smørgrav struct infra_data* host; 840b7579f77SDag-Erling Smørgrav struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, 841b7579f77SDag-Erling Smørgrav name, namelen, 0); 842b7579f77SDag-Erling Smørgrav if(!e) 843b7579f77SDag-Erling Smørgrav return 0; 844b7579f77SDag-Erling Smørgrav host = (struct infra_data*)e->data; 845b7579f77SDag-Erling Smørgrav *rtt = rtt_unclamped(&host->rtt); 846369c6923SCy Schubert if(host->rtt.rto >= PROBE_MAXRTO && timenow >= host->probedelay 847369c6923SCy Schubert && infra->infra_keep_probing) { 848369c6923SCy Schubert /* single probe, keep probing */ 849369c6923SCy Schubert if(*rtt >= USEFUL_SERVER_TOP_TIMEOUT) 850*be771a7bSCy Schubert *rtt = still_useful_timeout(); 851369c6923SCy Schubert } else if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay 852b7579f77SDag-Erling Smørgrav && rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) { 853b7579f77SDag-Erling Smørgrav /* single probe for this domain, and we are not probing */ 854b7579f77SDag-Erling Smørgrav /* unless the query type allows a probe to happen */ 855b7579f77SDag-Erling Smørgrav if(qtype == LDNS_RR_TYPE_A) { 856b7579f77SDag-Erling Smørgrav if(host->timeout_A >= TIMEOUT_COUNT_MAX) 857b7579f77SDag-Erling Smørgrav *rtt = USEFUL_SERVER_TOP_TIMEOUT; 858*be771a7bSCy Schubert else *rtt = still_useful_timeout(); 859b7579f77SDag-Erling Smørgrav } else if(qtype == LDNS_RR_TYPE_AAAA) { 860b7579f77SDag-Erling Smørgrav if(host->timeout_AAAA >= TIMEOUT_COUNT_MAX) 861b7579f77SDag-Erling Smørgrav *rtt = USEFUL_SERVER_TOP_TIMEOUT; 862*be771a7bSCy Schubert else *rtt = still_useful_timeout(); 863b7579f77SDag-Erling Smørgrav } else { 864b7579f77SDag-Erling Smørgrav if(host->timeout_other >= TIMEOUT_COUNT_MAX) 865b7579f77SDag-Erling Smørgrav *rtt = USEFUL_SERVER_TOP_TIMEOUT; 866*be771a7bSCy Schubert else *rtt = still_useful_timeout(); 867b7579f77SDag-Erling Smørgrav } 868b7579f77SDag-Erling Smørgrav } 869b7579f77SDag-Erling Smørgrav /* expired entry */ 870790c6b24SCy Schubert if(timenow > host->ttl) { 871b7579f77SDag-Erling Smørgrav /* see if this can be a re-probe of an unresponsive server */ 872790c6b24SCy Schubert if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) { 873b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 874*be771a7bSCy Schubert *rtt = still_useful_timeout(); 875b7579f77SDag-Erling Smørgrav *lame = 0; 876b7579f77SDag-Erling Smørgrav *dnsseclame = 0; 877b7579f77SDag-Erling Smørgrav *reclame = 0; 878b7579f77SDag-Erling Smørgrav return 1; 879b7579f77SDag-Erling Smørgrav } 880b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 881b7579f77SDag-Erling Smørgrav return 0; 882b7579f77SDag-Erling Smørgrav } 883b7579f77SDag-Erling Smørgrav /* check lameness first */ 884b7579f77SDag-Erling Smørgrav if(host->lame_type_A && qtype == LDNS_RR_TYPE_A) { 885b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 886b7579f77SDag-Erling Smørgrav *lame = 1; 887b7579f77SDag-Erling Smørgrav *dnsseclame = 0; 888b7579f77SDag-Erling Smørgrav *reclame = 0; 889b7579f77SDag-Erling Smørgrav return 1; 890b7579f77SDag-Erling Smørgrav } else if(host->lame_other && qtype != LDNS_RR_TYPE_A) { 891b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 892b7579f77SDag-Erling Smørgrav *lame = 1; 893b7579f77SDag-Erling Smørgrav *dnsseclame = 0; 894b7579f77SDag-Erling Smørgrav *reclame = 0; 895b7579f77SDag-Erling Smørgrav return 1; 896b7579f77SDag-Erling Smørgrav } else if(host->isdnsseclame) { 897b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 898b7579f77SDag-Erling Smørgrav *lame = 0; 899b7579f77SDag-Erling Smørgrav *dnsseclame = 1; 900b7579f77SDag-Erling Smørgrav *reclame = 0; 901b7579f77SDag-Erling Smørgrav return 1; 902b7579f77SDag-Erling Smørgrav } else if(host->rec_lame) { 903b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 904b7579f77SDag-Erling Smørgrav *lame = 0; 905b7579f77SDag-Erling Smørgrav *dnsseclame = 0; 906b7579f77SDag-Erling Smørgrav *reclame = 1; 907b7579f77SDag-Erling Smørgrav return 1; 908b7579f77SDag-Erling Smørgrav } 909b7579f77SDag-Erling Smørgrav /* no lameness for this type of query */ 910b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 911b7579f77SDag-Erling Smørgrav *lame = 0; 912b7579f77SDag-Erling Smørgrav *dnsseclame = 0; 913b7579f77SDag-Erling Smørgrav *reclame = 0; 914b7579f77SDag-Erling Smørgrav return 1; 915b7579f77SDag-Erling Smørgrav } 916b7579f77SDag-Erling Smørgrav 91709a3aaf3SDag-Erling Smørgrav int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name, 91809a3aaf3SDag-Erling Smørgrav size_t namelen) 91909a3aaf3SDag-Erling Smørgrav { 92009a3aaf3SDag-Erling Smørgrav int labs = dname_count_labels(name); 92109a3aaf3SDag-Erling Smørgrav struct domain_limit_data* d = (struct domain_limit_data*) 92209a3aaf3SDag-Erling Smørgrav name_tree_lookup(&infra->domain_limits, name, namelen, labs, 92309a3aaf3SDag-Erling Smørgrav LDNS_RR_CLASS_IN); 92409a3aaf3SDag-Erling Smørgrav if(!d) return infra_dp_ratelimit; 92509a3aaf3SDag-Erling Smørgrav 92609a3aaf3SDag-Erling Smørgrav if(d->node.labs == labs && d->lim != -1) 92709a3aaf3SDag-Erling Smørgrav return d->lim; /* exact match */ 92809a3aaf3SDag-Erling Smørgrav 92909a3aaf3SDag-Erling Smørgrav /* find 'below match' */ 93009a3aaf3SDag-Erling Smørgrav if(d->node.labs == labs) 93109a3aaf3SDag-Erling Smørgrav d = (struct domain_limit_data*)d->node.parent; 93209a3aaf3SDag-Erling Smørgrav while(d) { 93309a3aaf3SDag-Erling Smørgrav if(d->below != -1) 93409a3aaf3SDag-Erling Smørgrav return d->below; 93509a3aaf3SDag-Erling Smørgrav d = (struct domain_limit_data*)d->node.parent; 93609a3aaf3SDag-Erling Smørgrav } 93709a3aaf3SDag-Erling Smørgrav return infra_dp_ratelimit; 93809a3aaf3SDag-Erling Smørgrav } 93909a3aaf3SDag-Erling Smørgrav 9403005e0a3SDag-Erling Smørgrav size_t ip_rate_sizefunc(void* k, void* ATTR_UNUSED(d)) 9413005e0a3SDag-Erling Smørgrav { 9423005e0a3SDag-Erling Smørgrav struct ip_rate_key* key = (struct ip_rate_key*)k; 9433005e0a3SDag-Erling Smørgrav return sizeof(*key) + sizeof(struct ip_rate_data) 9443005e0a3SDag-Erling Smørgrav + lock_get_mem(&key->entry.lock); 9453005e0a3SDag-Erling Smørgrav } 9463005e0a3SDag-Erling Smørgrav 9473005e0a3SDag-Erling Smørgrav int ip_rate_compfunc(void* key1, void* key2) 9483005e0a3SDag-Erling Smørgrav { 9493005e0a3SDag-Erling Smørgrav struct ip_rate_key* k1 = (struct ip_rate_key*)key1; 9503005e0a3SDag-Erling Smørgrav struct ip_rate_key* k2 = (struct ip_rate_key*)key2; 9513005e0a3SDag-Erling Smørgrav return sockaddr_cmp_addr(&k1->addr, k1->addrlen, 9523005e0a3SDag-Erling Smørgrav &k2->addr, k2->addrlen); 9533005e0a3SDag-Erling Smørgrav } 9543005e0a3SDag-Erling Smørgrav 9553005e0a3SDag-Erling Smørgrav void ip_rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg)) 9563005e0a3SDag-Erling Smørgrav { 9573005e0a3SDag-Erling Smørgrav struct ip_rate_key* key = (struct ip_rate_key*)k; 9583005e0a3SDag-Erling Smørgrav if(!key) 9593005e0a3SDag-Erling Smørgrav return; 9603005e0a3SDag-Erling Smørgrav lock_rw_destroy(&key->entry.lock); 9613005e0a3SDag-Erling Smørgrav free(key); 9623005e0a3SDag-Erling Smørgrav } 9633005e0a3SDag-Erling Smørgrav 96409a3aaf3SDag-Erling Smørgrav /** find data item in array, for write access, caller unlocks */ 96509a3aaf3SDag-Erling Smørgrav static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra, 96609a3aaf3SDag-Erling Smørgrav uint8_t* name, size_t namelen, int wr) 96709a3aaf3SDag-Erling Smørgrav { 96809a3aaf3SDag-Erling Smørgrav struct rate_key key; 9693005e0a3SDag-Erling Smørgrav hashvalue_type h = dname_query_hash(name, 0xab); 97009a3aaf3SDag-Erling Smørgrav memset(&key, 0, sizeof(key)); 97109a3aaf3SDag-Erling Smørgrav key.name = name; 97209a3aaf3SDag-Erling Smørgrav key.namelen = namelen; 97309a3aaf3SDag-Erling Smørgrav key.entry.hash = h; 97409a3aaf3SDag-Erling Smørgrav return slabhash_lookup(infra->domain_rates, h, &key, wr); 97509a3aaf3SDag-Erling Smørgrav } 97609a3aaf3SDag-Erling Smørgrav 9773005e0a3SDag-Erling Smørgrav /** find data item in array for ip addresses */ 9783005e0a3SDag-Erling Smørgrav static struct lruhash_entry* infra_find_ip_ratedata(struct infra_cache* infra, 979865f46b2SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, int wr) 9803005e0a3SDag-Erling Smørgrav { 9813005e0a3SDag-Erling Smørgrav struct ip_rate_key key; 982865f46b2SCy Schubert hashvalue_type h = hash_addr(addr, addrlen, 0); 9833005e0a3SDag-Erling Smørgrav memset(&key, 0, sizeof(key)); 984865f46b2SCy Schubert key.addr = *addr; 985865f46b2SCy Schubert key.addrlen = addrlen; 9863005e0a3SDag-Erling Smørgrav key.entry.hash = h; 9873005e0a3SDag-Erling Smørgrav return slabhash_lookup(infra->client_ip_rates, h, &key, wr); 9883005e0a3SDag-Erling Smørgrav } 9893005e0a3SDag-Erling Smørgrav 99009a3aaf3SDag-Erling Smørgrav /** create rate data item for name, number 1 in now */ 99109a3aaf3SDag-Erling Smørgrav static void infra_create_ratedata(struct infra_cache* infra, 99209a3aaf3SDag-Erling Smørgrav uint8_t* name, size_t namelen, time_t timenow) 99309a3aaf3SDag-Erling Smørgrav { 9943005e0a3SDag-Erling Smørgrav hashvalue_type h = dname_query_hash(name, 0xab); 99509a3aaf3SDag-Erling Smørgrav struct rate_key* k = (struct rate_key*)calloc(1, sizeof(*k)); 99609a3aaf3SDag-Erling Smørgrav struct rate_data* d = (struct rate_data*)calloc(1, sizeof(*d)); 99709a3aaf3SDag-Erling Smørgrav if(!k || !d) { 99809a3aaf3SDag-Erling Smørgrav free(k); 99909a3aaf3SDag-Erling Smørgrav free(d); 100009a3aaf3SDag-Erling Smørgrav return; /* alloc failure */ 100109a3aaf3SDag-Erling Smørgrav } 100209a3aaf3SDag-Erling Smørgrav k->namelen = namelen; 100309a3aaf3SDag-Erling Smørgrav k->name = memdup(name, namelen); 100409a3aaf3SDag-Erling Smørgrav if(!k->name) { 100509a3aaf3SDag-Erling Smørgrav free(k); 100609a3aaf3SDag-Erling Smørgrav free(d); 100709a3aaf3SDag-Erling Smørgrav return; /* alloc failure */ 100809a3aaf3SDag-Erling Smørgrav } 100909a3aaf3SDag-Erling Smørgrav lock_rw_init(&k->entry.lock); 101009a3aaf3SDag-Erling Smørgrav k->entry.hash = h; 101109a3aaf3SDag-Erling Smørgrav k->entry.key = k; 101209a3aaf3SDag-Erling Smørgrav k->entry.data = d; 101309a3aaf3SDag-Erling Smørgrav d->qps[0] = 1; 101409a3aaf3SDag-Erling Smørgrav d->timestamp[0] = timenow; 101509a3aaf3SDag-Erling Smørgrav slabhash_insert(infra->domain_rates, h, &k->entry, d, NULL); 101609a3aaf3SDag-Erling Smørgrav } 101709a3aaf3SDag-Erling Smørgrav 10183005e0a3SDag-Erling Smørgrav /** create rate data item for ip address */ 10193005e0a3SDag-Erling Smørgrav static void infra_ip_create_ratedata(struct infra_cache* infra, 1020335c7cdaSCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow, 1021335c7cdaSCy Schubert int mesh_wait) 10223005e0a3SDag-Erling Smørgrav { 1023865f46b2SCy Schubert hashvalue_type h = hash_addr(addr, addrlen, 0); 10243005e0a3SDag-Erling Smørgrav struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k)); 10253005e0a3SDag-Erling Smørgrav struct ip_rate_data* d = (struct ip_rate_data*)calloc(1, sizeof(*d)); 10263005e0a3SDag-Erling Smørgrav if(!k || !d) { 10273005e0a3SDag-Erling Smørgrav free(k); 10283005e0a3SDag-Erling Smørgrav free(d); 10293005e0a3SDag-Erling Smørgrav return; /* alloc failure */ 10303005e0a3SDag-Erling Smørgrav } 1031865f46b2SCy Schubert k->addr = *addr; 1032865f46b2SCy Schubert k->addrlen = addrlen; 10333005e0a3SDag-Erling Smørgrav lock_rw_init(&k->entry.lock); 10343005e0a3SDag-Erling Smørgrav k->entry.hash = h; 10353005e0a3SDag-Erling Smørgrav k->entry.key = k; 10363005e0a3SDag-Erling Smørgrav k->entry.data = d; 10373005e0a3SDag-Erling Smørgrav d->qps[0] = 1; 10383005e0a3SDag-Erling Smørgrav d->timestamp[0] = timenow; 1039335c7cdaSCy Schubert d->mesh_wait = mesh_wait; 10403005e0a3SDag-Erling Smørgrav slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL); 10413005e0a3SDag-Erling Smørgrav } 10423005e0a3SDag-Erling Smørgrav 10439cf5bc93SCy Schubert /** Find the second and return its rate counter. If none and should_add, remove 10449cf5bc93SCy Schubert * oldest to accommodate. Else return none. */ 10459cf5bc93SCy Schubert static int* infra_rate_find_second_or_none(void* data, time_t t, int should_add) 104609a3aaf3SDag-Erling Smørgrav { 104709a3aaf3SDag-Erling Smørgrav struct rate_data* d = (struct rate_data*)data; 104809a3aaf3SDag-Erling Smørgrav int i, oldest; 104909a3aaf3SDag-Erling Smørgrav for(i=0; i<RATE_WINDOW; i++) { 105009a3aaf3SDag-Erling Smørgrav if(d->timestamp[i] == t) 105109a3aaf3SDag-Erling Smørgrav return &(d->qps[i]); 105209a3aaf3SDag-Erling Smørgrav } 10539cf5bc93SCy Schubert if(!should_add) return NULL; 105409a3aaf3SDag-Erling Smørgrav /* remove oldest timestamp, and insert it at t with 0 qps */ 105509a3aaf3SDag-Erling Smørgrav oldest = 0; 105609a3aaf3SDag-Erling Smørgrav for(i=0; i<RATE_WINDOW; i++) { 105709a3aaf3SDag-Erling Smørgrav if(d->timestamp[i] < d->timestamp[oldest]) 105809a3aaf3SDag-Erling Smørgrav oldest = i; 105909a3aaf3SDag-Erling Smørgrav } 106009a3aaf3SDag-Erling Smørgrav d->timestamp[oldest] = t; 106109a3aaf3SDag-Erling Smørgrav d->qps[oldest] = 0; 106209a3aaf3SDag-Erling Smørgrav return &(d->qps[oldest]); 106309a3aaf3SDag-Erling Smørgrav } 106409a3aaf3SDag-Erling Smørgrav 10659cf5bc93SCy Schubert /** find the second and return its rate counter, if none, remove oldest to 10669cf5bc93SCy Schubert * accommodate */ 10679cf5bc93SCy Schubert static int* infra_rate_give_second(void* data, time_t t) 10689cf5bc93SCy Schubert { 10699cf5bc93SCy Schubert return infra_rate_find_second_or_none(data, t, 1); 10709cf5bc93SCy Schubert } 10719cf5bc93SCy Schubert 10729cf5bc93SCy Schubert /** find the second and return its rate counter only if it exists. Caller 10739cf5bc93SCy Schubert * should check for NULL return value */ 10749cf5bc93SCy Schubert static int* infra_rate_get_second(void* data, time_t t) 10759cf5bc93SCy Schubert { 10769cf5bc93SCy Schubert return infra_rate_find_second_or_none(data, t, 0); 10779cf5bc93SCy Schubert } 10789cf5bc93SCy Schubert 10799cf5bc93SCy Schubert int infra_rate_max(void* data, time_t now, int backoff) 108009a3aaf3SDag-Erling Smørgrav { 108109a3aaf3SDag-Erling Smørgrav struct rate_data* d = (struct rate_data*)data; 108209a3aaf3SDag-Erling Smørgrav int i, max = 0; 108309a3aaf3SDag-Erling Smørgrav for(i=0; i<RATE_WINDOW; i++) { 10849cf5bc93SCy Schubert if(backoff) { 10859cf5bc93SCy Schubert if(now-d->timestamp[i] <= RATE_WINDOW && 10869cf5bc93SCy Schubert d->qps[i] > max) { 108709a3aaf3SDag-Erling Smørgrav max = d->qps[i]; 108809a3aaf3SDag-Erling Smørgrav } 10899cf5bc93SCy Schubert } else { 10909cf5bc93SCy Schubert if(now == d->timestamp[i]) { 10919cf5bc93SCy Schubert return d->qps[i]; 10929cf5bc93SCy Schubert } 10939cf5bc93SCy Schubert } 109409a3aaf3SDag-Erling Smørgrav } 109509a3aaf3SDag-Erling Smørgrav return max; 109609a3aaf3SDag-Erling Smørgrav } 109709a3aaf3SDag-Erling Smørgrav 109809a3aaf3SDag-Erling Smørgrav int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name, 10999cf5bc93SCy Schubert size_t namelen, time_t timenow, int backoff, struct query_info* qinfo, 1100e86b9096SDag-Erling Smørgrav struct comm_reply* replylist) 110109a3aaf3SDag-Erling Smørgrav { 110209a3aaf3SDag-Erling Smørgrav int lim, max; 110309a3aaf3SDag-Erling Smørgrav struct lruhash_entry* entry; 110409a3aaf3SDag-Erling Smørgrav 110509a3aaf3SDag-Erling Smørgrav if(!infra_dp_ratelimit) 110609a3aaf3SDag-Erling Smørgrav return 1; /* not enabled */ 110709a3aaf3SDag-Erling Smørgrav 110809a3aaf3SDag-Erling Smørgrav /* find ratelimit */ 110909a3aaf3SDag-Erling Smørgrav lim = infra_find_ratelimit(infra, name, namelen); 1110c7f4d7adSDag-Erling Smørgrav if(!lim) 1111c7f4d7adSDag-Erling Smørgrav return 1; /* disabled for this domain */ 111209a3aaf3SDag-Erling Smørgrav 111309a3aaf3SDag-Erling Smørgrav /* find or insert ratedata */ 111409a3aaf3SDag-Erling Smørgrav entry = infra_find_ratedata(infra, name, namelen, 1); 111509a3aaf3SDag-Erling Smørgrav if(entry) { 11169cf5bc93SCy Schubert int premax = infra_rate_max(entry->data, timenow, backoff); 11179cf5bc93SCy Schubert int* cur = infra_rate_give_second(entry->data, timenow); 111809a3aaf3SDag-Erling Smørgrav (*cur)++; 11199cf5bc93SCy Schubert max = infra_rate_max(entry->data, timenow, backoff); 112009a3aaf3SDag-Erling Smørgrav lock_rw_unlock(&entry->lock); 112109a3aaf3SDag-Erling Smørgrav 11229cf5bc93SCy Schubert if(premax <= lim && max > lim) { 1123*be771a7bSCy Schubert char buf[LDNS_MAX_DOMAINLEN], qnm[LDNS_MAX_DOMAINLEN]; 1124*be771a7bSCy Schubert char ts[12], cs[12], ip[128]; 112509a3aaf3SDag-Erling Smørgrav dname_str(name, buf); 1126e86b9096SDag-Erling Smørgrav dname_str(qinfo->qname, qnm); 1127e86b9096SDag-Erling Smørgrav sldns_wire2str_type_buf(qinfo->qtype, ts, sizeof(ts)); 1128e86b9096SDag-Erling Smørgrav sldns_wire2str_class_buf(qinfo->qclass, cs, sizeof(cs)); 1129e86b9096SDag-Erling Smørgrav ip[0]=0; 1130e86b9096SDag-Erling Smørgrav if(replylist) { 1131865f46b2SCy Schubert addr_to_str((struct sockaddr_storage *)&replylist->remote_addr, 1132865f46b2SCy Schubert replylist->remote_addrlen, ip, sizeof(ip)); 1133e86b9096SDag-Erling Smørgrav verbose(VERB_OPS, "ratelimit exceeded %s %d query %s %s %s from %s", buf, lim, qnm, cs, ts, ip); 1134e86b9096SDag-Erling Smørgrav } else { 1135e86b9096SDag-Erling Smørgrav verbose(VERB_OPS, "ratelimit exceeded %s %d query %s %s %s", buf, lim, qnm, cs, ts); 1136e86b9096SDag-Erling Smørgrav } 113709a3aaf3SDag-Erling Smørgrav } 11389cf5bc93SCy Schubert return (max <= lim); 113909a3aaf3SDag-Erling Smørgrav } 114009a3aaf3SDag-Erling Smørgrav 114109a3aaf3SDag-Erling Smørgrav /* create */ 114209a3aaf3SDag-Erling Smørgrav infra_create_ratedata(infra, name, namelen, timenow); 11439cf5bc93SCy Schubert return (1 <= lim); 114409a3aaf3SDag-Erling Smørgrav } 114509a3aaf3SDag-Erling Smørgrav 114609a3aaf3SDag-Erling Smørgrav void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name, 114709a3aaf3SDag-Erling Smørgrav size_t namelen, time_t timenow) 114809a3aaf3SDag-Erling Smørgrav { 114909a3aaf3SDag-Erling Smørgrav struct lruhash_entry* entry; 115009a3aaf3SDag-Erling Smørgrav int* cur; 115109a3aaf3SDag-Erling Smørgrav if(!infra_dp_ratelimit) 115209a3aaf3SDag-Erling Smørgrav return; /* not enabled */ 115309a3aaf3SDag-Erling Smørgrav entry = infra_find_ratedata(infra, name, namelen, 1); 115409a3aaf3SDag-Erling Smørgrav if(!entry) return; /* not cached */ 11559cf5bc93SCy Schubert cur = infra_rate_get_second(entry->data, timenow); 11569cf5bc93SCy Schubert if(cur == NULL) { 11579cf5bc93SCy Schubert /* our timenow is not available anymore; nothing to decrease */ 11589cf5bc93SCy Schubert lock_rw_unlock(&entry->lock); 11599cf5bc93SCy Schubert return; 11609cf5bc93SCy Schubert } 116109a3aaf3SDag-Erling Smørgrav if((*cur) > 0) 116209a3aaf3SDag-Erling Smørgrav (*cur)--; 116309a3aaf3SDag-Erling Smørgrav lock_rw_unlock(&entry->lock); 116409a3aaf3SDag-Erling Smørgrav } 116509a3aaf3SDag-Erling Smørgrav 116609a3aaf3SDag-Erling Smørgrav int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name, 11679cf5bc93SCy Schubert size_t namelen, time_t timenow, int backoff) 116809a3aaf3SDag-Erling Smørgrav { 116909a3aaf3SDag-Erling Smørgrav struct lruhash_entry* entry; 117009a3aaf3SDag-Erling Smørgrav int lim, max; 117109a3aaf3SDag-Erling Smørgrav if(!infra_dp_ratelimit) 117209a3aaf3SDag-Erling Smørgrav return 0; /* not enabled */ 117309a3aaf3SDag-Erling Smørgrav 117409a3aaf3SDag-Erling Smørgrav /* find ratelimit */ 117509a3aaf3SDag-Erling Smørgrav lim = infra_find_ratelimit(infra, name, namelen); 1176c7f4d7adSDag-Erling Smørgrav if(!lim) 1177c7f4d7adSDag-Erling Smørgrav return 0; /* disabled for this domain */ 117809a3aaf3SDag-Erling Smørgrav 117909a3aaf3SDag-Erling Smørgrav /* find current rate */ 118009a3aaf3SDag-Erling Smørgrav entry = infra_find_ratedata(infra, name, namelen, 0); 118109a3aaf3SDag-Erling Smørgrav if(!entry) 118209a3aaf3SDag-Erling Smørgrav return 0; /* not cached */ 11839cf5bc93SCy Schubert max = infra_rate_max(entry->data, timenow, backoff); 118409a3aaf3SDag-Erling Smørgrav lock_rw_unlock(&entry->lock); 118509a3aaf3SDag-Erling Smørgrav 1186865f46b2SCy Schubert return (max > lim); 118709a3aaf3SDag-Erling Smørgrav } 118809a3aaf3SDag-Erling Smørgrav 1189b7579f77SDag-Erling Smørgrav size_t 1190b7579f77SDag-Erling Smørgrav infra_get_mem(struct infra_cache* infra) 1191b7579f77SDag-Erling Smørgrav { 119209a3aaf3SDag-Erling Smørgrav size_t s = sizeof(*infra) + slabhash_get_mem(infra->hosts); 119309a3aaf3SDag-Erling Smørgrav if(infra->domain_rates) s += slabhash_get_mem(infra->domain_rates); 11943005e0a3SDag-Erling Smørgrav if(infra->client_ip_rates) s += slabhash_get_mem(infra->client_ip_rates); 119509a3aaf3SDag-Erling Smørgrav /* ignore domain_limits because walk through tree is big */ 119609a3aaf3SDag-Erling Smørgrav return s; 1197b7579f77SDag-Erling Smørgrav } 11983005e0a3SDag-Erling Smørgrav 11998f76bb7dSCy Schubert /* Returns 1 if the limit has not been exceeded, 0 otherwise. */ 12008f76bb7dSCy Schubert static int 12018f76bb7dSCy Schubert check_ip_ratelimit(struct sockaddr_storage* addr, socklen_t addrlen, 12028f76bb7dSCy Schubert struct sldns_buffer* buffer, int premax, int max, int has_cookie) 12038f76bb7dSCy Schubert { 12048f76bb7dSCy Schubert int limit; 12058f76bb7dSCy Schubert 12068f76bb7dSCy Schubert if(has_cookie) limit = infra_ip_ratelimit_cookie; 12078f76bb7dSCy Schubert else limit = infra_ip_ratelimit; 12088f76bb7dSCy Schubert 12098f76bb7dSCy Schubert /* Disabled */ 12108f76bb7dSCy Schubert if(limit == 0) return 1; 12118f76bb7dSCy Schubert 12128f76bb7dSCy Schubert if(premax <= limit && max > limit) { 12138f76bb7dSCy Schubert char client_ip[128], qnm[LDNS_MAX_DOMAINLEN+1+12+12]; 12148f76bb7dSCy Schubert addr_to_str(addr, addrlen, client_ip, sizeof(client_ip)); 12158f76bb7dSCy Schubert qnm[0]=0; 12168f76bb7dSCy Schubert if(sldns_buffer_limit(buffer)>LDNS_HEADER_SIZE && 12178f76bb7dSCy Schubert LDNS_QDCOUNT(sldns_buffer_begin(buffer))!=0) { 12188f76bb7dSCy Schubert (void)sldns_wire2str_rrquestion_buf( 12198f76bb7dSCy Schubert sldns_buffer_at(buffer, LDNS_HEADER_SIZE), 12208f76bb7dSCy Schubert sldns_buffer_limit(buffer)-LDNS_HEADER_SIZE, 12218f76bb7dSCy Schubert qnm, sizeof(qnm)); 12228f76bb7dSCy Schubert if(strlen(qnm)>0 && qnm[strlen(qnm)-1]=='\n') 12238f76bb7dSCy Schubert qnm[strlen(qnm)-1] = 0; /*remove newline*/ 12248f76bb7dSCy Schubert if(strchr(qnm, '\t')) 12258f76bb7dSCy Schubert *strchr(qnm, '\t') = ' '; 12268f76bb7dSCy Schubert if(strchr(qnm, '\t')) 12278f76bb7dSCy Schubert *strchr(qnm, '\t') = ' '; 12288f76bb7dSCy Schubert verbose(VERB_OPS, "ip_ratelimit exceeded %s %d%s %s", 12298f76bb7dSCy Schubert client_ip, limit, 12308f76bb7dSCy Schubert has_cookie?"(cookie)":"", qnm); 12318f76bb7dSCy Schubert } else { 12328f76bb7dSCy Schubert verbose(VERB_OPS, "ip_ratelimit exceeded %s %d%s (no query name)", 12338f76bb7dSCy Schubert client_ip, limit, 12348f76bb7dSCy Schubert has_cookie?"(cookie)":""); 12358f76bb7dSCy Schubert } 12368f76bb7dSCy Schubert } 12378f76bb7dSCy Schubert return (max <= limit); 12388f76bb7dSCy Schubert } 12398f76bb7dSCy Schubert 12403005e0a3SDag-Erling Smørgrav int infra_ip_ratelimit_inc(struct infra_cache* infra, 1241865f46b2SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow, 12428f76bb7dSCy Schubert int has_cookie, int backoff, struct sldns_buffer* buffer) 12433005e0a3SDag-Erling Smørgrav { 12443005e0a3SDag-Erling Smørgrav int max; 12453005e0a3SDag-Erling Smørgrav struct lruhash_entry* entry; 12463005e0a3SDag-Erling Smørgrav 12473005e0a3SDag-Erling Smørgrav /* not enabled */ 12483005e0a3SDag-Erling Smørgrav if(!infra_ip_ratelimit) { 12493005e0a3SDag-Erling Smørgrav return 1; 12503005e0a3SDag-Erling Smørgrav } 12513005e0a3SDag-Erling Smørgrav /* find or insert ratedata */ 1252865f46b2SCy Schubert entry = infra_find_ip_ratedata(infra, addr, addrlen, 1); 12533005e0a3SDag-Erling Smørgrav if(entry) { 12549cf5bc93SCy Schubert int premax = infra_rate_max(entry->data, timenow, backoff); 12559cf5bc93SCy Schubert int* cur = infra_rate_give_second(entry->data, timenow); 12563005e0a3SDag-Erling Smørgrav (*cur)++; 12579cf5bc93SCy Schubert max = infra_rate_max(entry->data, timenow, backoff); 12583005e0a3SDag-Erling Smørgrav lock_rw_unlock(&entry->lock); 12598f76bb7dSCy Schubert return check_ip_ratelimit(addr, addrlen, buffer, premax, max, 12608f76bb7dSCy Schubert has_cookie); 12613005e0a3SDag-Erling Smørgrav } 12623005e0a3SDag-Erling Smørgrav 12633005e0a3SDag-Erling Smørgrav /* create */ 1264335c7cdaSCy Schubert infra_ip_create_ratedata(infra, addr, addrlen, timenow, 0); 12653005e0a3SDag-Erling Smørgrav return 1; 12663005e0a3SDag-Erling Smørgrav } 1267335c7cdaSCy Schubert 1268335c7cdaSCy Schubert int infra_wait_limit_allowed(struct infra_cache* infra, struct comm_reply* rep, 1269335c7cdaSCy Schubert int cookie_valid, struct config_file* cfg) 1270335c7cdaSCy Schubert { 1271335c7cdaSCy Schubert struct lruhash_entry* entry; 1272335c7cdaSCy Schubert if(cfg->wait_limit == 0) 1273335c7cdaSCy Schubert return 1; 1274335c7cdaSCy Schubert 1275335c7cdaSCy Schubert entry = infra_find_ip_ratedata(infra, &rep->client_addr, 1276335c7cdaSCy Schubert rep->client_addrlen, 0); 1277335c7cdaSCy Schubert if(entry) { 1278335c7cdaSCy Schubert rbtree_type* tree; 1279335c7cdaSCy Schubert struct wait_limit_netblock_info* w; 1280335c7cdaSCy Schubert struct rate_data* d = (struct rate_data*)entry->data; 1281335c7cdaSCy Schubert int mesh_wait = d->mesh_wait; 1282335c7cdaSCy Schubert lock_rw_unlock(&entry->lock); 1283335c7cdaSCy Schubert 1284335c7cdaSCy Schubert /* have the wait amount, check how much is allowed */ 1285335c7cdaSCy Schubert if(cookie_valid) 1286335c7cdaSCy Schubert tree = &infra->wait_limits_cookie_netblock; 1287335c7cdaSCy Schubert else tree = &infra->wait_limits_netblock; 1288335c7cdaSCy Schubert w = (struct wait_limit_netblock_info*)addr_tree_lookup(tree, 1289335c7cdaSCy Schubert &rep->client_addr, rep->client_addrlen); 1290335c7cdaSCy Schubert if(w) { 1291335c7cdaSCy Schubert if(w->limit != -1 && mesh_wait > w->limit) 1292335c7cdaSCy Schubert return 0; 1293335c7cdaSCy Schubert } else { 1294335c7cdaSCy Schubert /* if there is no IP netblock specific information, 1295335c7cdaSCy Schubert * use the configured value. */ 1296335c7cdaSCy Schubert if(mesh_wait > (cookie_valid?cfg->wait_limit_cookie: 1297335c7cdaSCy Schubert cfg->wait_limit)) 1298335c7cdaSCy Schubert return 0; 1299335c7cdaSCy Schubert } 1300335c7cdaSCy Schubert } 1301335c7cdaSCy Schubert return 1; 1302335c7cdaSCy Schubert } 1303335c7cdaSCy Schubert 1304335c7cdaSCy Schubert void infra_wait_limit_inc(struct infra_cache* infra, struct comm_reply* rep, 1305335c7cdaSCy Schubert time_t timenow, struct config_file* cfg) 1306335c7cdaSCy Schubert { 1307335c7cdaSCy Schubert struct lruhash_entry* entry; 1308335c7cdaSCy Schubert if(cfg->wait_limit == 0) 1309335c7cdaSCy Schubert return; 1310335c7cdaSCy Schubert 1311335c7cdaSCy Schubert /* Find it */ 1312335c7cdaSCy Schubert entry = infra_find_ip_ratedata(infra, &rep->client_addr, 1313335c7cdaSCy Schubert rep->client_addrlen, 1); 1314335c7cdaSCy Schubert if(entry) { 1315335c7cdaSCy Schubert struct rate_data* d = (struct rate_data*)entry->data; 1316335c7cdaSCy Schubert d->mesh_wait++; 1317335c7cdaSCy Schubert lock_rw_unlock(&entry->lock); 1318335c7cdaSCy Schubert return; 1319335c7cdaSCy Schubert } 1320335c7cdaSCy Schubert 1321335c7cdaSCy Schubert /* Create it */ 1322335c7cdaSCy Schubert infra_ip_create_ratedata(infra, &rep->client_addr, 1323335c7cdaSCy Schubert rep->client_addrlen, timenow, 1); 1324335c7cdaSCy Schubert } 1325335c7cdaSCy Schubert 1326335c7cdaSCy Schubert void infra_wait_limit_dec(struct infra_cache* infra, struct comm_reply* rep, 1327335c7cdaSCy Schubert struct config_file* cfg) 1328335c7cdaSCy Schubert { 1329335c7cdaSCy Schubert struct lruhash_entry* entry; 1330335c7cdaSCy Schubert if(cfg->wait_limit == 0) 1331335c7cdaSCy Schubert return; 1332335c7cdaSCy Schubert 1333335c7cdaSCy Schubert entry = infra_find_ip_ratedata(infra, &rep->client_addr, 1334335c7cdaSCy Schubert rep->client_addrlen, 1); 1335335c7cdaSCy Schubert if(entry) { 1336335c7cdaSCy Schubert struct rate_data* d = (struct rate_data*)entry->data; 1337335c7cdaSCy Schubert if(d->mesh_wait > 0) 1338335c7cdaSCy Schubert d->mesh_wait--; 1339335c7cdaSCy Schubert lock_rw_unlock(&entry->lock); 1340335c7cdaSCy Schubert } 1341335c7cdaSCy Schubert } 1342