xref: /freebsd/contrib/unbound/services/cache/infra.c (revision 335c7cda)
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 
55b7579f77SDag-Erling Smørgrav /** Timeout when only a single probe query per IP is allowed. */
56b7579f77SDag-Erling Smørgrav #define PROBE_MAXRTO 12000 /* in msec */
57b7579f77SDag-Erling Smørgrav 
58b7579f77SDag-Erling Smørgrav /** number of timeouts for a type when the domain can be blocked ;
59b7579f77SDag-Erling Smørgrav  * even if another type has completely rtt maxed it, the different type
60b7579f77SDag-Erling Smørgrav  * can do this number of packets (until those all timeout too) */
61b7579f77SDag-Erling Smørgrav #define TIMEOUT_COUNT_MAX 3
62b7579f77SDag-Erling Smørgrav 
6309a3aaf3SDag-Erling Smørgrav /** ratelimit value for delegation point */
6409a3aaf3SDag-Erling Smørgrav int infra_dp_ratelimit = 0;
6509a3aaf3SDag-Erling Smørgrav 
663005e0a3SDag-Erling Smørgrav /** ratelimit value for client ip addresses,
673005e0a3SDag-Erling Smørgrav  *  in queries per second. */
683005e0a3SDag-Erling Smørgrav int infra_ip_ratelimit = 0;
693005e0a3SDag-Erling Smørgrav 
708f76bb7dSCy Schubert /** ratelimit value for client ip addresses,
718f76bb7dSCy Schubert  *  in queries per second.
728f76bb7dSCy Schubert  *  For clients with a valid DNS Cookie. */
738f76bb7dSCy Schubert int infra_ip_ratelimit_cookie = 0;
748f76bb7dSCy Schubert 
75b7579f77SDag-Erling Smørgrav size_t
infra_sizefunc(void * k,void * ATTR_UNUSED (d))76b7579f77SDag-Erling Smørgrav infra_sizefunc(void* k, void* ATTR_UNUSED(d))
77b7579f77SDag-Erling Smørgrav {
78b7579f77SDag-Erling Smørgrav 	struct infra_key* key = (struct infra_key*)k;
79b7579f77SDag-Erling Smørgrav 	return sizeof(*key) + sizeof(struct infra_data) + key->namelen
80b7579f77SDag-Erling Smørgrav 		+ lock_get_mem(&key->entry.lock);
81b7579f77SDag-Erling Smørgrav }
82b7579f77SDag-Erling Smørgrav 
83b7579f77SDag-Erling Smørgrav int
infra_compfunc(void * key1,void * key2)84b7579f77SDag-Erling Smørgrav infra_compfunc(void* key1, void* key2)
85b7579f77SDag-Erling Smørgrav {
86b7579f77SDag-Erling Smørgrav 	struct infra_key* k1 = (struct infra_key*)key1;
87b7579f77SDag-Erling Smørgrav 	struct infra_key* k2 = (struct infra_key*)key2;
88b7579f77SDag-Erling Smørgrav 	int r = sockaddr_cmp(&k1->addr, k1->addrlen, &k2->addr, k2->addrlen);
89b7579f77SDag-Erling Smørgrav 	if(r != 0)
90b7579f77SDag-Erling Smørgrav 		return r;
91b7579f77SDag-Erling Smørgrav 	if(k1->namelen != k2->namelen) {
92b7579f77SDag-Erling Smørgrav 		if(k1->namelen < k2->namelen)
93b7579f77SDag-Erling Smørgrav 			return -1;
94b7579f77SDag-Erling Smørgrav 		return 1;
95b7579f77SDag-Erling Smørgrav 	}
96b7579f77SDag-Erling Smørgrav 	return query_dname_compare(k1->zonename, k2->zonename);
97b7579f77SDag-Erling Smørgrav }
98b7579f77SDag-Erling Smørgrav 
99b7579f77SDag-Erling Smørgrav void
infra_delkeyfunc(void * k,void * ATTR_UNUSED (arg))100b7579f77SDag-Erling Smørgrav infra_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
101b7579f77SDag-Erling Smørgrav {
102b7579f77SDag-Erling Smørgrav 	struct infra_key* key = (struct infra_key*)k;
103b7579f77SDag-Erling Smørgrav 	if(!key)
104b7579f77SDag-Erling Smørgrav 		return;
105b7579f77SDag-Erling Smørgrav 	lock_rw_destroy(&key->entry.lock);
106b7579f77SDag-Erling Smørgrav 	free(key->zonename);
107b7579f77SDag-Erling Smørgrav 	free(key);
108b7579f77SDag-Erling Smørgrav }
109b7579f77SDag-Erling Smørgrav 
110b7579f77SDag-Erling Smørgrav void
infra_deldatafunc(void * d,void * ATTR_UNUSED (arg))111b7579f77SDag-Erling Smørgrav infra_deldatafunc(void* d, void* ATTR_UNUSED(arg))
112b7579f77SDag-Erling Smørgrav {
113b7579f77SDag-Erling Smørgrav 	struct infra_data* data = (struct infra_data*)d;
114b7579f77SDag-Erling Smørgrav 	free(data);
115b7579f77SDag-Erling Smørgrav }
116b7579f77SDag-Erling Smørgrav 
11709a3aaf3SDag-Erling Smørgrav size_t
rate_sizefunc(void * k,void * ATTR_UNUSED (d))11809a3aaf3SDag-Erling Smørgrav rate_sizefunc(void* k, void* ATTR_UNUSED(d))
11909a3aaf3SDag-Erling Smørgrav {
12009a3aaf3SDag-Erling Smørgrav 	struct rate_key* key = (struct rate_key*)k;
12109a3aaf3SDag-Erling Smørgrav 	return sizeof(*key) + sizeof(struct rate_data) + key->namelen
12209a3aaf3SDag-Erling Smørgrav 		+ lock_get_mem(&key->entry.lock);
12309a3aaf3SDag-Erling Smørgrav }
12409a3aaf3SDag-Erling Smørgrav 
12509a3aaf3SDag-Erling Smørgrav int
rate_compfunc(void * key1,void * key2)12609a3aaf3SDag-Erling Smørgrav rate_compfunc(void* key1, void* key2)
12709a3aaf3SDag-Erling Smørgrav {
12809a3aaf3SDag-Erling Smørgrav 	struct rate_key* k1 = (struct rate_key*)key1;
12909a3aaf3SDag-Erling Smørgrav 	struct rate_key* k2 = (struct rate_key*)key2;
13009a3aaf3SDag-Erling Smørgrav 	if(k1->namelen != k2->namelen) {
13109a3aaf3SDag-Erling Smørgrav 		if(k1->namelen < k2->namelen)
13209a3aaf3SDag-Erling Smørgrav 			return -1;
13309a3aaf3SDag-Erling Smørgrav 		return 1;
13409a3aaf3SDag-Erling Smørgrav 	}
13509a3aaf3SDag-Erling Smørgrav 	return query_dname_compare(k1->name, k2->name);
13609a3aaf3SDag-Erling Smørgrav }
13709a3aaf3SDag-Erling Smørgrav 
13809a3aaf3SDag-Erling Smørgrav void
rate_delkeyfunc(void * k,void * ATTR_UNUSED (arg))13909a3aaf3SDag-Erling Smørgrav rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
14009a3aaf3SDag-Erling Smørgrav {
14109a3aaf3SDag-Erling Smørgrav 	struct rate_key* key = (struct rate_key*)k;
14209a3aaf3SDag-Erling Smørgrav 	if(!key)
14309a3aaf3SDag-Erling Smørgrav 		return;
14409a3aaf3SDag-Erling Smørgrav 	lock_rw_destroy(&key->entry.lock);
14509a3aaf3SDag-Erling Smørgrav 	free(key->name);
14609a3aaf3SDag-Erling Smørgrav 	free(key);
14709a3aaf3SDag-Erling Smørgrav }
14809a3aaf3SDag-Erling Smørgrav 
14909a3aaf3SDag-Erling Smørgrav void
rate_deldatafunc(void * d,void * ATTR_UNUSED (arg))15009a3aaf3SDag-Erling Smørgrav rate_deldatafunc(void* d, void* ATTR_UNUSED(arg))
15109a3aaf3SDag-Erling Smørgrav {
15209a3aaf3SDag-Erling Smørgrav 	struct rate_data* data = (struct rate_data*)d;
15309a3aaf3SDag-Erling Smørgrav 	free(data);
15409a3aaf3SDag-Erling Smørgrav }
15509a3aaf3SDag-Erling Smørgrav 
15609a3aaf3SDag-Erling Smørgrav /** find or create element in domainlimit tree */
domain_limit_findcreate(struct infra_cache * infra,char * name)15709a3aaf3SDag-Erling Smørgrav static struct domain_limit_data* domain_limit_findcreate(
15809a3aaf3SDag-Erling Smørgrav 	struct infra_cache* infra, char* name)
15909a3aaf3SDag-Erling Smørgrav {
16009a3aaf3SDag-Erling Smørgrav 	uint8_t* nm;
16109a3aaf3SDag-Erling Smørgrav 	int labs;
16209a3aaf3SDag-Erling Smørgrav 	size_t nmlen;
16309a3aaf3SDag-Erling Smørgrav 	struct domain_limit_data* d;
16409a3aaf3SDag-Erling Smørgrav 
16509a3aaf3SDag-Erling Smørgrav 	/* parse name */
16609a3aaf3SDag-Erling Smørgrav 	nm = sldns_str2wire_dname(name, &nmlen);
16709a3aaf3SDag-Erling Smørgrav 	if(!nm) {
16809a3aaf3SDag-Erling Smørgrav 		log_err("could not parse %s", name);
16909a3aaf3SDag-Erling Smørgrav 		return NULL;
17009a3aaf3SDag-Erling Smørgrav 	}
17109a3aaf3SDag-Erling Smørgrav 	labs = dname_count_labels(nm);
17209a3aaf3SDag-Erling Smørgrav 
17309a3aaf3SDag-Erling Smørgrav 	/* can we find it? */
17409a3aaf3SDag-Erling Smørgrav 	d = (struct domain_limit_data*)name_tree_find(&infra->domain_limits,
17509a3aaf3SDag-Erling Smørgrav 		nm, nmlen, labs, LDNS_RR_CLASS_IN);
17609a3aaf3SDag-Erling Smørgrav 	if(d) {
17709a3aaf3SDag-Erling Smørgrav 		free(nm);
17809a3aaf3SDag-Erling Smørgrav 		return d;
17909a3aaf3SDag-Erling Smørgrav 	}
18009a3aaf3SDag-Erling Smørgrav 
18109a3aaf3SDag-Erling Smørgrav 	/* create it */
18209a3aaf3SDag-Erling Smørgrav 	d = (struct domain_limit_data*)calloc(1, sizeof(*d));
18309a3aaf3SDag-Erling Smørgrav 	if(!d) {
18409a3aaf3SDag-Erling Smørgrav 		free(nm);
18509a3aaf3SDag-Erling Smørgrav 		return NULL;
18609a3aaf3SDag-Erling Smørgrav 	}
18709a3aaf3SDag-Erling Smørgrav 	d->node.node.key = &d->node;
18809a3aaf3SDag-Erling Smørgrav 	d->node.name = nm;
18909a3aaf3SDag-Erling Smørgrav 	d->node.len = nmlen;
19009a3aaf3SDag-Erling Smørgrav 	d->node.labs = labs;
19109a3aaf3SDag-Erling Smørgrav 	d->node.dclass = LDNS_RR_CLASS_IN;
19209a3aaf3SDag-Erling Smørgrav 	d->lim = -1;
19309a3aaf3SDag-Erling Smørgrav 	d->below = -1;
19409a3aaf3SDag-Erling Smørgrav 	if(!name_tree_insert(&infra->domain_limits, &d->node, nm, nmlen,
19509a3aaf3SDag-Erling Smørgrav 		labs, LDNS_RR_CLASS_IN)) {
19609a3aaf3SDag-Erling Smørgrav 		log_err("duplicate element in domainlimit tree");
19709a3aaf3SDag-Erling Smørgrav 		free(nm);
19809a3aaf3SDag-Erling Smørgrav 		free(d);
19909a3aaf3SDag-Erling Smørgrav 		return NULL;
20009a3aaf3SDag-Erling Smørgrav 	}
20109a3aaf3SDag-Erling Smørgrav 	return d;
20209a3aaf3SDag-Erling Smørgrav }
20309a3aaf3SDag-Erling Smørgrav 
20409a3aaf3SDag-Erling Smørgrav /** insert rate limit configuration into lookup tree */
infra_ratelimit_cfg_insert(struct infra_cache * infra,struct config_file * cfg)20509a3aaf3SDag-Erling Smørgrav static int infra_ratelimit_cfg_insert(struct infra_cache* infra,
20609a3aaf3SDag-Erling Smørgrav 	struct config_file* cfg)
20709a3aaf3SDag-Erling Smørgrav {
20809a3aaf3SDag-Erling Smørgrav 	struct config_str2list* p;
20909a3aaf3SDag-Erling Smørgrav 	struct domain_limit_data* d;
21009a3aaf3SDag-Erling Smørgrav 	for(p = cfg->ratelimit_for_domain; p; p = p->next) {
21109a3aaf3SDag-Erling Smørgrav 		d = domain_limit_findcreate(infra, p->str);
21209a3aaf3SDag-Erling Smørgrav 		if(!d)
21309a3aaf3SDag-Erling Smørgrav 			return 0;
21409a3aaf3SDag-Erling Smørgrav 		d->lim = atoi(p->str2);
21509a3aaf3SDag-Erling Smørgrav 	}
21609a3aaf3SDag-Erling Smørgrav 	for(p = cfg->ratelimit_below_domain; p; p = p->next) {
21709a3aaf3SDag-Erling Smørgrav 		d = domain_limit_findcreate(infra, p->str);
21809a3aaf3SDag-Erling Smørgrav 		if(!d)
21909a3aaf3SDag-Erling Smørgrav 			return 0;
22009a3aaf3SDag-Erling Smørgrav 		d->below = atoi(p->str2);
22109a3aaf3SDag-Erling Smørgrav 	}
22209a3aaf3SDag-Erling Smørgrav 	return 1;
22309a3aaf3SDag-Erling Smørgrav }
22409a3aaf3SDag-Erling Smørgrav 
2254c75e3aaSDag-Erling Smørgrav /** setup domain limits tree (0 on failure) */
2264c75e3aaSDag-Erling Smørgrav static int
setup_domain_limits(struct infra_cache * infra,struct config_file * cfg)2274c75e3aaSDag-Erling Smørgrav setup_domain_limits(struct infra_cache* infra, struct config_file* cfg)
2284c75e3aaSDag-Erling Smørgrav {
2294c75e3aaSDag-Erling Smørgrav 	name_tree_init(&infra->domain_limits);
2304c75e3aaSDag-Erling Smørgrav 	if(!infra_ratelimit_cfg_insert(infra, cfg)) {
2314c75e3aaSDag-Erling Smørgrav 		return 0;
2324c75e3aaSDag-Erling Smørgrav 	}
2334c75e3aaSDag-Erling Smørgrav 	name_tree_init_parents(&infra->domain_limits);
2344c75e3aaSDag-Erling Smørgrav 	return 1;
2354c75e3aaSDag-Erling Smørgrav }
2364c75e3aaSDag-Erling Smørgrav 
237*335c7cdaSCy Schubert /** find or create element in wait limit netblock tree */
238*335c7cdaSCy Schubert static struct wait_limit_netblock_info*
wait_limit_netblock_findcreate(struct infra_cache * infra,char * str,int cookie)239*335c7cdaSCy Schubert wait_limit_netblock_findcreate(struct infra_cache* infra, char* str,
240*335c7cdaSCy Schubert 	int cookie)
241*335c7cdaSCy Schubert {
242*335c7cdaSCy Schubert 	rbtree_type* tree;
243*335c7cdaSCy Schubert 	struct sockaddr_storage addr;
244*335c7cdaSCy Schubert 	int net;
245*335c7cdaSCy Schubert 	socklen_t addrlen;
246*335c7cdaSCy Schubert 	struct wait_limit_netblock_info* d;
247*335c7cdaSCy Schubert 
248*335c7cdaSCy Schubert 	if(!netblockstrtoaddr(str, 0, &addr, &addrlen, &net)) {
249*335c7cdaSCy Schubert 		log_err("cannot parse wait limit netblock '%s'", str);
250*335c7cdaSCy Schubert 		return 0;
251*335c7cdaSCy Schubert 	}
252*335c7cdaSCy Schubert 
253*335c7cdaSCy Schubert 	/* can we find it? */
254*335c7cdaSCy Schubert 	if(cookie)
255*335c7cdaSCy Schubert 		tree = &infra->wait_limits_cookie_netblock;
256*335c7cdaSCy Schubert 	else
257*335c7cdaSCy Schubert 		tree = &infra->wait_limits_netblock;
258*335c7cdaSCy Schubert 	d = (struct wait_limit_netblock_info*)addr_tree_find(tree, &addr,
259*335c7cdaSCy Schubert 		addrlen, net);
260*335c7cdaSCy Schubert 	if(d)
261*335c7cdaSCy Schubert 		return d;
262*335c7cdaSCy Schubert 
263*335c7cdaSCy Schubert 	/* create it */
264*335c7cdaSCy Schubert 	d = (struct wait_limit_netblock_info*)calloc(1, sizeof(*d));
265*335c7cdaSCy Schubert 	if(!d)
266*335c7cdaSCy Schubert 		return NULL;
267*335c7cdaSCy Schubert 	d->limit = -1;
268*335c7cdaSCy Schubert 	if(!addr_tree_insert(tree, &d->node, &addr, addrlen, net)) {
269*335c7cdaSCy Schubert 		log_err("duplicate element in domainlimit tree");
270*335c7cdaSCy Schubert 		free(d);
271*335c7cdaSCy Schubert 		return NULL;
272*335c7cdaSCy Schubert 	}
273*335c7cdaSCy Schubert 	return d;
274*335c7cdaSCy Schubert }
275*335c7cdaSCy Schubert 
276*335c7cdaSCy Schubert 
277*335c7cdaSCy Schubert /** insert wait limit information into lookup tree */
278*335c7cdaSCy Schubert static int
infra_wait_limit_netblock_insert(struct infra_cache * infra,struct config_file * cfg)279*335c7cdaSCy Schubert infra_wait_limit_netblock_insert(struct infra_cache* infra,
280*335c7cdaSCy Schubert 	struct config_file* cfg)
281*335c7cdaSCy Schubert {
282*335c7cdaSCy Schubert 	struct config_str2list* p;
283*335c7cdaSCy Schubert 	struct wait_limit_netblock_info* d;
284*335c7cdaSCy Schubert 	for(p = cfg->wait_limit_netblock; p; p = p->next) {
285*335c7cdaSCy Schubert 		d = wait_limit_netblock_findcreate(infra, p->str, 0);
286*335c7cdaSCy Schubert 		if(!d)
287*335c7cdaSCy Schubert 			return 0;
288*335c7cdaSCy Schubert 		d->limit = atoi(p->str2);
289*335c7cdaSCy Schubert 	}
290*335c7cdaSCy Schubert 	for(p = cfg->wait_limit_cookie_netblock; p; p = p->next) {
291*335c7cdaSCy Schubert 		d = wait_limit_netblock_findcreate(infra, p->str, 1);
292*335c7cdaSCy Schubert 		if(!d)
293*335c7cdaSCy Schubert 			return 0;
294*335c7cdaSCy Schubert 		d->limit = atoi(p->str2);
295*335c7cdaSCy Schubert 	}
296*335c7cdaSCy Schubert 	return 1;
297*335c7cdaSCy Schubert }
298*335c7cdaSCy Schubert 
299*335c7cdaSCy Schubert /** setup wait limits tree (0 on failure) */
300*335c7cdaSCy Schubert static int
setup_wait_limits(struct infra_cache * infra,struct config_file * cfg)301*335c7cdaSCy Schubert setup_wait_limits(struct infra_cache* infra, struct config_file* cfg)
302*335c7cdaSCy Schubert {
303*335c7cdaSCy Schubert 	addr_tree_init(&infra->wait_limits_netblock);
304*335c7cdaSCy Schubert 	addr_tree_init(&infra->wait_limits_cookie_netblock);
305*335c7cdaSCy Schubert 	if(!infra_wait_limit_netblock_insert(infra, cfg))
306*335c7cdaSCy Schubert 		return 0;
307*335c7cdaSCy Schubert 	addr_tree_init_parents(&infra->wait_limits_netblock);
308*335c7cdaSCy Schubert 	addr_tree_init_parents(&infra->wait_limits_cookie_netblock);
309*335c7cdaSCy Schubert 	return 1;
310*335c7cdaSCy Schubert }
311*335c7cdaSCy Schubert 
312b7579f77SDag-Erling Smørgrav struct infra_cache*
infra_create(struct config_file * cfg)313b7579f77SDag-Erling Smørgrav infra_create(struct config_file* cfg)
314b7579f77SDag-Erling Smørgrav {
315b7579f77SDag-Erling Smørgrav 	struct infra_cache* infra = (struct infra_cache*)calloc(1,
316b7579f77SDag-Erling Smørgrav 		sizeof(struct infra_cache));
317b7579f77SDag-Erling Smørgrav 	size_t maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+
318b7579f77SDag-Erling Smørgrav 		sizeof(struct infra_data)+INFRA_BYTES_NAME);
3195469a995SCy Schubert 	if(!infra) {
3205469a995SCy Schubert 		return NULL;
3215469a995SCy Schubert 	}
322b7579f77SDag-Erling Smørgrav 	infra->hosts = slabhash_create(cfg->infra_cache_slabs,
323b7579f77SDag-Erling Smørgrav 		INFRA_HOST_STARTSIZE, maxmem, &infra_sizefunc, &infra_compfunc,
324b7579f77SDag-Erling Smørgrav 		&infra_delkeyfunc, &infra_deldatafunc, NULL);
325b7579f77SDag-Erling Smørgrav 	if(!infra->hosts) {
326b7579f77SDag-Erling Smørgrav 		free(infra);
327b7579f77SDag-Erling Smørgrav 		return NULL;
328b7579f77SDag-Erling Smørgrav 	}
329b7579f77SDag-Erling Smørgrav 	infra->host_ttl = cfg->host_ttl;
330369c6923SCy Schubert 	infra->infra_keep_probing = cfg->infra_keep_probing;
33109a3aaf3SDag-Erling Smørgrav 	infra_dp_ratelimit = cfg->ratelimit;
33209a3aaf3SDag-Erling Smørgrav 	infra->domain_rates = slabhash_create(cfg->ratelimit_slabs,
33309a3aaf3SDag-Erling Smørgrav 		INFRA_HOST_STARTSIZE, cfg->ratelimit_size,
33409a3aaf3SDag-Erling Smørgrav 		&rate_sizefunc, &rate_compfunc, &rate_delkeyfunc,
33509a3aaf3SDag-Erling Smørgrav 		&rate_deldatafunc, NULL);
33609a3aaf3SDag-Erling Smørgrav 	if(!infra->domain_rates) {
33709a3aaf3SDag-Erling Smørgrav 		infra_delete(infra);
33809a3aaf3SDag-Erling Smørgrav 		return NULL;
33909a3aaf3SDag-Erling Smørgrav 	}
34009a3aaf3SDag-Erling Smørgrav 	/* insert config data into ratelimits */
3414c75e3aaSDag-Erling Smørgrav 	if(!setup_domain_limits(infra, cfg)) {
34209a3aaf3SDag-Erling Smørgrav 		infra_delete(infra);
34309a3aaf3SDag-Erling Smørgrav 		return NULL;
34409a3aaf3SDag-Erling Smørgrav 	}
345*335c7cdaSCy Schubert 	if(!setup_wait_limits(infra, cfg)) {
346*335c7cdaSCy Schubert 		infra_delete(infra);
347*335c7cdaSCy Schubert 		return NULL;
348*335c7cdaSCy Schubert 	}
3493005e0a3SDag-Erling Smørgrav 	infra_ip_ratelimit = cfg->ip_ratelimit;
350971980c3SDag-Erling Smørgrav 	infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs,
3513005e0a3SDag-Erling Smørgrav 	    INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc,
3523005e0a3SDag-Erling Smørgrav 	    &ip_rate_compfunc, &ip_rate_delkeyfunc, &ip_rate_deldatafunc, NULL);
3533005e0a3SDag-Erling Smørgrav 	if(!infra->client_ip_rates) {
3543005e0a3SDag-Erling Smørgrav 		infra_delete(infra);
3553005e0a3SDag-Erling Smørgrav 		return NULL;
3563005e0a3SDag-Erling Smørgrav 	}
357b7579f77SDag-Erling Smørgrav 	return infra;
358b7579f77SDag-Erling Smørgrav }
359b7579f77SDag-Erling Smørgrav 
36009a3aaf3SDag-Erling Smørgrav /** delete domain_limit entries */
domain_limit_free(rbnode_type * n,void * ATTR_UNUSED (arg))3613005e0a3SDag-Erling Smørgrav static void domain_limit_free(rbnode_type* n, void* ATTR_UNUSED(arg))
36209a3aaf3SDag-Erling Smørgrav {
36309a3aaf3SDag-Erling Smørgrav 	if(n) {
36409a3aaf3SDag-Erling Smørgrav 		free(((struct domain_limit_data*)n)->node.name);
36509a3aaf3SDag-Erling Smørgrav 		free(n);
36609a3aaf3SDag-Erling Smørgrav 	}
36709a3aaf3SDag-Erling Smørgrav }
36809a3aaf3SDag-Erling Smørgrav 
369*335c7cdaSCy Schubert /** delete wait_limit_netblock_info entries */
wait_limit_netblock_del(rbnode_type * n,void * ATTR_UNUSED (arg))370*335c7cdaSCy Schubert static void wait_limit_netblock_del(rbnode_type* n, void* ATTR_UNUSED(arg))
371*335c7cdaSCy Schubert {
372*335c7cdaSCy Schubert 	free(n);
373*335c7cdaSCy Schubert }
374*335c7cdaSCy Schubert 
375b7579f77SDag-Erling Smørgrav void
infra_delete(struct infra_cache * infra)376b7579f77SDag-Erling Smørgrav infra_delete(struct infra_cache* infra)
377b7579f77SDag-Erling Smørgrav {
378b7579f77SDag-Erling Smørgrav 	if(!infra)
379b7579f77SDag-Erling Smørgrav 		return;
380b7579f77SDag-Erling Smørgrav 	slabhash_delete(infra->hosts);
38109a3aaf3SDag-Erling Smørgrav 	slabhash_delete(infra->domain_rates);
38209a3aaf3SDag-Erling Smørgrav 	traverse_postorder(&infra->domain_limits, domain_limit_free, NULL);
3833005e0a3SDag-Erling Smørgrav 	slabhash_delete(infra->client_ip_rates);
384*335c7cdaSCy Schubert 	traverse_postorder(&infra->wait_limits_netblock,
385*335c7cdaSCy Schubert 		wait_limit_netblock_del, NULL);
386*335c7cdaSCy Schubert 	traverse_postorder(&infra->wait_limits_cookie_netblock,
387*335c7cdaSCy Schubert 		wait_limit_netblock_del, NULL);
388b7579f77SDag-Erling Smørgrav 	free(infra);
389b7579f77SDag-Erling Smørgrav }
390b7579f77SDag-Erling Smørgrav 
391b7579f77SDag-Erling Smørgrav struct infra_cache*
infra_adjust(struct infra_cache * infra,struct config_file * cfg)392b7579f77SDag-Erling Smørgrav infra_adjust(struct infra_cache* infra, struct config_file* cfg)
393b7579f77SDag-Erling Smørgrav {
394b7579f77SDag-Erling Smørgrav 	size_t maxmem;
395b7579f77SDag-Erling Smørgrav 	if(!infra)
396b7579f77SDag-Erling Smørgrav 		return infra_create(cfg);
397b7579f77SDag-Erling Smørgrav 	infra->host_ttl = cfg->host_ttl;
398369c6923SCy Schubert 	infra->infra_keep_probing = cfg->infra_keep_probing;
3994c75e3aaSDag-Erling Smørgrav 	infra_dp_ratelimit = cfg->ratelimit;
4004c75e3aaSDag-Erling Smørgrav 	infra_ip_ratelimit = cfg->ip_ratelimit;
401b7579f77SDag-Erling Smørgrav 	maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+
402b7579f77SDag-Erling Smørgrav 		sizeof(struct infra_data)+INFRA_BYTES_NAME);
4034c75e3aaSDag-Erling Smørgrav 	/* divide cachesize by slabs and multiply by slabs, because if the
4044c75e3aaSDag-Erling Smørgrav 	 * cachesize is not an even multiple of slabs, that is the resulting
4054c75e3aaSDag-Erling Smørgrav 	 * size of the slabhash */
4064c75e3aaSDag-Erling Smørgrav 	if(!slabhash_is_size(infra->hosts, maxmem, cfg->infra_cache_slabs) ||
4074c75e3aaSDag-Erling Smørgrav 	   !slabhash_is_size(infra->domain_rates, cfg->ratelimit_size,
4084c75e3aaSDag-Erling Smørgrav 	   	cfg->ratelimit_slabs) ||
4094c75e3aaSDag-Erling Smørgrav 	   !slabhash_is_size(infra->client_ip_rates, cfg->ip_ratelimit_size,
4104c75e3aaSDag-Erling Smørgrav 	   	cfg->ip_ratelimit_slabs)) {
411b7579f77SDag-Erling Smørgrav 		infra_delete(infra);
412b7579f77SDag-Erling Smørgrav 		infra = infra_create(cfg);
4134c75e3aaSDag-Erling Smørgrav 	} else {
4144c75e3aaSDag-Erling Smørgrav 		/* reapply domain limits */
4154c75e3aaSDag-Erling Smørgrav 		traverse_postorder(&infra->domain_limits, domain_limit_free,
4164c75e3aaSDag-Erling Smørgrav 			NULL);
4174c75e3aaSDag-Erling Smørgrav 		if(!setup_domain_limits(infra, cfg)) {
4184c75e3aaSDag-Erling Smørgrav 			infra_delete(infra);
4194c75e3aaSDag-Erling Smørgrav 			return NULL;
4204c75e3aaSDag-Erling Smørgrav 		}
421b7579f77SDag-Erling Smørgrav 	}
422b7579f77SDag-Erling Smørgrav 	return infra;
423b7579f77SDag-Erling Smørgrav }
424b7579f77SDag-Erling Smørgrav 
4253005e0a3SDag-Erling Smørgrav /** calculate the hash value for a host key
4263005e0a3SDag-Erling Smørgrav  *  set use_port to a non-0 number to use the port in
4273005e0a3SDag-Erling Smørgrav  *  the hash calculation; 0 to ignore the port.*/
4283005e0a3SDag-Erling Smørgrav static hashvalue_type
hash_addr(struct sockaddr_storage * addr,socklen_t addrlen,int use_port)4293005e0a3SDag-Erling Smørgrav hash_addr(struct sockaddr_storage* addr, socklen_t addrlen,
4303005e0a3SDag-Erling Smørgrav   int use_port)
431b7579f77SDag-Erling Smørgrav {
4323005e0a3SDag-Erling Smørgrav 	hashvalue_type h = 0xab;
433b7579f77SDag-Erling Smørgrav 	/* select the pieces to hash, some OS have changing data inside */
434b7579f77SDag-Erling Smørgrav 	if(addr_is_ip6(addr, addrlen)) {
435b7579f77SDag-Erling Smørgrav 		struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr;
436b7579f77SDag-Erling Smørgrav 		h = hashlittle(&in6->sin6_family, sizeof(in6->sin6_family), h);
4373005e0a3SDag-Erling Smørgrav 		if(use_port){
438b7579f77SDag-Erling Smørgrav 			h = hashlittle(&in6->sin6_port, sizeof(in6->sin6_port), h);
4393005e0a3SDag-Erling Smørgrav 		}
440b7579f77SDag-Erling Smørgrav 		h = hashlittle(&in6->sin6_addr, INET6_SIZE, h);
441b7579f77SDag-Erling Smørgrav 	} else {
442b7579f77SDag-Erling Smørgrav 		struct sockaddr_in* in = (struct sockaddr_in*)addr;
443b7579f77SDag-Erling Smørgrav 		h = hashlittle(&in->sin_family, sizeof(in->sin_family), h);
4443005e0a3SDag-Erling Smørgrav 		if(use_port){
445b7579f77SDag-Erling Smørgrav 			h = hashlittle(&in->sin_port, sizeof(in->sin_port), h);
4463005e0a3SDag-Erling Smørgrav 		}
447b7579f77SDag-Erling Smørgrav 		h = hashlittle(&in->sin_addr, INET_SIZE, h);
448b7579f77SDag-Erling Smørgrav 	}
449b7579f77SDag-Erling Smørgrav 	return h;
450b7579f77SDag-Erling Smørgrav }
451b7579f77SDag-Erling Smørgrav 
452b7579f77SDag-Erling Smørgrav /** calculate infra hash for a key */
4533005e0a3SDag-Erling Smørgrav static hashvalue_type
hash_infra(struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * name)454b7579f77SDag-Erling Smørgrav hash_infra(struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name)
455b7579f77SDag-Erling Smørgrav {
4563005e0a3SDag-Erling Smørgrav 	return dname_query_hash(name, hash_addr(addr, addrlen, 1));
457b7579f77SDag-Erling Smørgrav }
458b7579f77SDag-Erling Smørgrav 
459b7579f77SDag-Erling Smørgrav /** lookup version that does not check host ttl (you check it) */
460b7579f77SDag-Erling Smørgrav struct lruhash_entry*
infra_lookup_nottl(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * name,size_t namelen,int wr)461b7579f77SDag-Erling Smørgrav infra_lookup_nottl(struct infra_cache* infra, struct sockaddr_storage* addr,
462b7579f77SDag-Erling Smørgrav 	socklen_t addrlen, uint8_t* name, size_t namelen, int wr)
463b7579f77SDag-Erling Smørgrav {
464b7579f77SDag-Erling Smørgrav 	struct infra_key k;
465b7579f77SDag-Erling Smørgrav 	k.addrlen = addrlen;
466b7579f77SDag-Erling Smørgrav 	memcpy(&k.addr, addr, addrlen);
467b7579f77SDag-Erling Smørgrav 	k.namelen = namelen;
468b7579f77SDag-Erling Smørgrav 	k.zonename = name;
469b7579f77SDag-Erling Smørgrav 	k.entry.hash = hash_infra(addr, addrlen, name);
470b7579f77SDag-Erling Smørgrav 	k.entry.key = (void*)&k;
471b7579f77SDag-Erling Smørgrav 	k.entry.data = NULL;
472b7579f77SDag-Erling Smørgrav 	return slabhash_lookup(infra->hosts, k.entry.hash, &k, wr);
473b7579f77SDag-Erling Smørgrav }
474b7579f77SDag-Erling Smørgrav 
475b7579f77SDag-Erling Smørgrav /** init the data elements */
476b7579f77SDag-Erling Smørgrav static void
data_entry_init(struct infra_cache * infra,struct lruhash_entry * e,time_t timenow)477b7579f77SDag-Erling Smørgrav data_entry_init(struct infra_cache* infra, struct lruhash_entry* e,
47817d15b25SDag-Erling Smørgrav 	time_t timenow)
479b7579f77SDag-Erling Smørgrav {
480b7579f77SDag-Erling Smørgrav 	struct infra_data* data = (struct infra_data*)e->data;
481b7579f77SDag-Erling Smørgrav 	data->ttl = timenow + infra->host_ttl;
482b7579f77SDag-Erling Smørgrav 	rtt_init(&data->rtt);
483b7579f77SDag-Erling Smørgrav 	data->edns_version = 0;
484b7579f77SDag-Erling Smørgrav 	data->edns_lame_known = 0;
485b7579f77SDag-Erling Smørgrav 	data->probedelay = 0;
486b7579f77SDag-Erling Smørgrav 	data->isdnsseclame = 0;
487b7579f77SDag-Erling Smørgrav 	data->rec_lame = 0;
488b7579f77SDag-Erling Smørgrav 	data->lame_type_A = 0;
489b7579f77SDag-Erling Smørgrav 	data->lame_other = 0;
490b7579f77SDag-Erling Smørgrav 	data->timeout_A = 0;
491b7579f77SDag-Erling Smørgrav 	data->timeout_AAAA = 0;
492b7579f77SDag-Erling Smørgrav 	data->timeout_other = 0;
493b7579f77SDag-Erling Smørgrav }
494b7579f77SDag-Erling Smørgrav 
495b7579f77SDag-Erling Smørgrav /**
496b7579f77SDag-Erling Smørgrav  * Create and init a new entry for a host
497b7579f77SDag-Erling Smørgrav  * @param infra: infra structure with config parameters.
498b7579f77SDag-Erling Smørgrav  * @param addr: host address.
499b7579f77SDag-Erling Smørgrav  * @param addrlen: length of addr.
500b7579f77SDag-Erling Smørgrav  * @param name: name of zone
501b7579f77SDag-Erling Smørgrav  * @param namelen: length of name.
502b7579f77SDag-Erling Smørgrav  * @param tm: time now.
503b7579f77SDag-Erling Smørgrav  * @return: the new entry or NULL on malloc failure.
504b7579f77SDag-Erling Smørgrav  */
505b7579f77SDag-Erling Smørgrav static struct lruhash_entry*
new_entry(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * name,size_t namelen,time_t tm)506b7579f77SDag-Erling Smørgrav new_entry(struct infra_cache* infra, struct sockaddr_storage* addr,
50717d15b25SDag-Erling Smørgrav 	socklen_t addrlen, uint8_t* name, size_t namelen, time_t tm)
508b7579f77SDag-Erling Smørgrav {
509b7579f77SDag-Erling Smørgrav 	struct infra_data* data;
510b7579f77SDag-Erling Smørgrav 	struct infra_key* key = (struct infra_key*)malloc(sizeof(*key));
511b7579f77SDag-Erling Smørgrav 	if(!key)
512b7579f77SDag-Erling Smørgrav 		return NULL;
513b7579f77SDag-Erling Smørgrav 	data = (struct infra_data*)malloc(sizeof(struct infra_data));
514b7579f77SDag-Erling Smørgrav 	if(!data) {
515b7579f77SDag-Erling Smørgrav 		free(key);
516b7579f77SDag-Erling Smørgrav 		return NULL;
517b7579f77SDag-Erling Smørgrav 	}
518b7579f77SDag-Erling Smørgrav 	key->zonename = memdup(name, namelen);
519b7579f77SDag-Erling Smørgrav 	if(!key->zonename) {
520b7579f77SDag-Erling Smørgrav 		free(key);
521b7579f77SDag-Erling Smørgrav 		free(data);
522b7579f77SDag-Erling Smørgrav 		return NULL;
523b7579f77SDag-Erling Smørgrav 	}
524b7579f77SDag-Erling Smørgrav 	key->namelen = namelen;
525b7579f77SDag-Erling Smørgrav 	lock_rw_init(&key->entry.lock);
526b7579f77SDag-Erling Smørgrav 	key->entry.hash = hash_infra(addr, addrlen, name);
527b7579f77SDag-Erling Smørgrav 	key->entry.key = (void*)key;
528b7579f77SDag-Erling Smørgrav 	key->entry.data = (void*)data;
529b7579f77SDag-Erling Smørgrav 	key->addrlen = addrlen;
530b7579f77SDag-Erling Smørgrav 	memcpy(&key->addr, addr, addrlen);
531b7579f77SDag-Erling Smørgrav 	data_entry_init(infra, &key->entry, tm);
532b7579f77SDag-Erling Smørgrav 	return &key->entry;
533b7579f77SDag-Erling Smørgrav }
534b7579f77SDag-Erling Smørgrav 
535b7579f77SDag-Erling Smørgrav int
infra_host(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * nm,size_t nmlen,time_t timenow,int * edns_vs,uint8_t * edns_lame_known,int * to)536b7579f77SDag-Erling Smørgrav infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
53717d15b25SDag-Erling Smørgrav         socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow,
538b7579f77SDag-Erling Smørgrav 	int* edns_vs, uint8_t* edns_lame_known, int* to)
539b7579f77SDag-Erling Smørgrav {
540b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
541b7579f77SDag-Erling Smørgrav 		nm, nmlen, 0);
542b7579f77SDag-Erling Smørgrav 	struct infra_data* data;
543b7579f77SDag-Erling Smørgrav 	int wr = 0;
544b7579f77SDag-Erling Smørgrav 	if(e && ((struct infra_data*)e->data)->ttl < timenow) {
545b7579f77SDag-Erling Smørgrav 		/* it expired, try to reuse existing entry */
546b7579f77SDag-Erling Smørgrav 		int old = ((struct infra_data*)e->data)->rtt.rto;
547369c6923SCy Schubert 		time_t tprobe = ((struct infra_data*)e->data)->probedelay;
548b7579f77SDag-Erling Smørgrav 		uint8_t tA = ((struct infra_data*)e->data)->timeout_A;
549b7579f77SDag-Erling Smørgrav 		uint8_t tAAAA = ((struct infra_data*)e->data)->timeout_AAAA;
550b7579f77SDag-Erling Smørgrav 		uint8_t tother = ((struct infra_data*)e->data)->timeout_other;
551b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&e->lock);
552b7579f77SDag-Erling Smørgrav 		e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1);
553b7579f77SDag-Erling Smørgrav 		if(e) {
554b7579f77SDag-Erling Smørgrav 			/* if its still there we have a writelock, init */
555b7579f77SDag-Erling Smørgrav 			/* re-initialise */
556b7579f77SDag-Erling Smørgrav 			/* do not touch lameness, it may be valid still */
557b7579f77SDag-Erling Smørgrav 			data_entry_init(infra, e, timenow);
558b7579f77SDag-Erling Smørgrav 			wr = 1;
559b7579f77SDag-Erling Smørgrav 			/* TOP_TIMEOUT remains on reuse */
560b7579f77SDag-Erling Smørgrav 			if(old >= USEFUL_SERVER_TOP_TIMEOUT) {
561b7579f77SDag-Erling Smørgrav 				((struct infra_data*)e->data)->rtt.rto
562b7579f77SDag-Erling Smørgrav 					= USEFUL_SERVER_TOP_TIMEOUT;
563369c6923SCy Schubert 				((struct infra_data*)e->data)->probedelay = tprobe;
564b7579f77SDag-Erling Smørgrav 				((struct infra_data*)e->data)->timeout_A = tA;
565b7579f77SDag-Erling Smørgrav 				((struct infra_data*)e->data)->timeout_AAAA = tAAAA;
566b7579f77SDag-Erling Smørgrav 				((struct infra_data*)e->data)->timeout_other = tother;
567b7579f77SDag-Erling Smørgrav 			}
568b7579f77SDag-Erling Smørgrav 		}
569b7579f77SDag-Erling Smørgrav 	}
570b7579f77SDag-Erling Smørgrav 	if(!e) {
571b7579f77SDag-Erling Smørgrav 		/* insert new entry */
572b7579f77SDag-Erling Smørgrav 		if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow)))
573b7579f77SDag-Erling Smørgrav 			return 0;
574b7579f77SDag-Erling Smørgrav 		data = (struct infra_data*)e->data;
575b7579f77SDag-Erling Smørgrav 		*edns_vs = data->edns_version;
576b7579f77SDag-Erling Smørgrav 		*edns_lame_known = data->edns_lame_known;
577b7579f77SDag-Erling Smørgrav 		*to = rtt_timeout(&data->rtt);
578b7579f77SDag-Erling Smørgrav 		slabhash_insert(infra->hosts, e->hash, e, data, NULL);
579b7579f77SDag-Erling Smørgrav 		return 1;
580b7579f77SDag-Erling Smørgrav 	}
581b7579f77SDag-Erling Smørgrav 	/* use existing entry */
582b7579f77SDag-Erling Smørgrav 	data = (struct infra_data*)e->data;
583b7579f77SDag-Erling Smørgrav 	*edns_vs = data->edns_version;
584b7579f77SDag-Erling Smørgrav 	*edns_lame_known = data->edns_lame_known;
585b7579f77SDag-Erling Smørgrav 	*to = rtt_timeout(&data->rtt);
586369c6923SCy Schubert 	if(*to >= PROBE_MAXRTO && (infra->infra_keep_probing ||
587369c6923SCy Schubert 		rtt_notimeout(&data->rtt)*4 <= *to)) {
588b7579f77SDag-Erling Smørgrav 		/* delay other queries, this is the probe query */
589b7579f77SDag-Erling Smørgrav 		if(!wr) {
590b7579f77SDag-Erling Smørgrav 			lock_rw_unlock(&e->lock);
591b7579f77SDag-Erling Smørgrav 			e = infra_lookup_nottl(infra, addr,addrlen,nm,nmlen, 1);
592b7579f77SDag-Erling Smørgrav 			if(!e) { /* flushed from cache real fast, no use to
593b7579f77SDag-Erling Smørgrav 				allocate just for the probedelay */
594b7579f77SDag-Erling Smørgrav 				return 1;
595b7579f77SDag-Erling Smørgrav 			}
596b7579f77SDag-Erling Smørgrav 			data = (struct infra_data*)e->data;
597b7579f77SDag-Erling Smørgrav 		}
598b7579f77SDag-Erling Smørgrav 		/* add 999 to round up the timeout value from msec to sec,
599b7579f77SDag-Erling Smørgrav 		 * then add a whole second so it is certain that this probe
600b7579f77SDag-Erling Smørgrav 		 * has timed out before the next is allowed */
601b7579f77SDag-Erling Smørgrav 		data->probedelay = timenow + ((*to)+1999)/1000;
602b7579f77SDag-Erling Smørgrav 	}
603b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&e->lock);
604b7579f77SDag-Erling Smørgrav 	return 1;
605b7579f77SDag-Erling Smørgrav }
606b7579f77SDag-Erling Smørgrav 
607b7579f77SDag-Erling Smørgrav int
infra_set_lame(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * nm,size_t nmlen,time_t timenow,int dnsseclame,int reclame,uint16_t qtype)608b7579f77SDag-Erling Smørgrav infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr,
60917d15b25SDag-Erling Smørgrav 	socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow,
610b7579f77SDag-Erling Smørgrav 	int dnsseclame, int reclame, uint16_t qtype)
611b7579f77SDag-Erling Smørgrav {
612b7579f77SDag-Erling Smørgrav 	struct infra_data* data;
613b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* e;
614b7579f77SDag-Erling Smørgrav 	int needtoinsert = 0;
615b7579f77SDag-Erling Smørgrav 	e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1);
616b7579f77SDag-Erling Smørgrav 	if(!e) {
617b7579f77SDag-Erling Smørgrav 		/* insert it */
618b7579f77SDag-Erling Smørgrav 		if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) {
619b7579f77SDag-Erling Smørgrav 			log_err("set_lame: malloc failure");
620b7579f77SDag-Erling Smørgrav 			return 0;
621b7579f77SDag-Erling Smørgrav 		}
622b7579f77SDag-Erling Smørgrav 		needtoinsert = 1;
623b7579f77SDag-Erling Smørgrav 	} else if( ((struct infra_data*)e->data)->ttl < timenow) {
624b7579f77SDag-Erling Smørgrav 		/* expired, reuse existing entry */
625b7579f77SDag-Erling Smørgrav 		data_entry_init(infra, e, timenow);
626b7579f77SDag-Erling Smørgrav 	}
627b7579f77SDag-Erling Smørgrav 	/* got an entry, now set the zone lame */
628b7579f77SDag-Erling Smørgrav 	data = (struct infra_data*)e->data;
629b7579f77SDag-Erling Smørgrav 	/* merge data (if any) */
630b7579f77SDag-Erling Smørgrav 	if(dnsseclame)
631b7579f77SDag-Erling Smørgrav 		data->isdnsseclame = 1;
632b7579f77SDag-Erling Smørgrav 	if(reclame)
633b7579f77SDag-Erling Smørgrav 		data->rec_lame = 1;
634b7579f77SDag-Erling Smørgrav 	if(!dnsseclame && !reclame && qtype == LDNS_RR_TYPE_A)
635b7579f77SDag-Erling Smørgrav 		data->lame_type_A = 1;
636b7579f77SDag-Erling Smørgrav 	if(!dnsseclame  && !reclame && qtype != LDNS_RR_TYPE_A)
637b7579f77SDag-Erling Smørgrav 		data->lame_other = 1;
638b7579f77SDag-Erling Smørgrav 	/* done */
639b7579f77SDag-Erling Smørgrav 	if(needtoinsert)
640b7579f77SDag-Erling Smørgrav 		slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
641b7579f77SDag-Erling Smørgrav 	else 	{ lock_rw_unlock(&e->lock); }
642b7579f77SDag-Erling Smørgrav 	return 1;
643b7579f77SDag-Erling Smørgrav }
644b7579f77SDag-Erling Smørgrav 
645b7579f77SDag-Erling Smørgrav void
infra_update_tcp_works(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * nm,size_t nmlen)646b7579f77SDag-Erling Smørgrav infra_update_tcp_works(struct infra_cache* infra,
647b7579f77SDag-Erling Smørgrav         struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm,
648b7579f77SDag-Erling Smørgrav 	size_t nmlen)
649b7579f77SDag-Erling Smørgrav {
650b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
651b7579f77SDag-Erling Smørgrav 		nm, nmlen, 1);
652b7579f77SDag-Erling Smørgrav 	struct infra_data* data;
653b7579f77SDag-Erling Smørgrav 	if(!e)
654b7579f77SDag-Erling Smørgrav 		return; /* doesn't exist */
655b7579f77SDag-Erling Smørgrav 	data = (struct infra_data*)e->data;
656b7579f77SDag-Erling Smørgrav 	if(data->rtt.rto >= RTT_MAX_TIMEOUT)
657b7579f77SDag-Erling Smørgrav 		/* do not disqualify this server altogether, it is better
658b7579f77SDag-Erling Smørgrav 		 * than nothing */
659b7579f77SDag-Erling Smørgrav 		data->rtt.rto = RTT_MAX_TIMEOUT-1000;
660b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&e->lock);
661b7579f77SDag-Erling Smørgrav }
662b7579f77SDag-Erling Smørgrav 
663b7579f77SDag-Erling Smørgrav int
infra_rtt_update(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * nm,size_t nmlen,int qtype,int roundtrip,int orig_rtt,time_t timenow)664b7579f77SDag-Erling Smørgrav infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr,
665b7579f77SDag-Erling Smørgrav 	socklen_t addrlen, uint8_t* nm, size_t nmlen, int qtype,
66617d15b25SDag-Erling Smørgrav 	int roundtrip, int orig_rtt, time_t timenow)
667b7579f77SDag-Erling Smørgrav {
668b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
669b7579f77SDag-Erling Smørgrav 		nm, nmlen, 1);
670b7579f77SDag-Erling Smørgrav 	struct infra_data* data;
671369c6923SCy Schubert 	int needtoinsert = 0, expired = 0;
672b7579f77SDag-Erling Smørgrav 	int rto = 1;
673369c6923SCy Schubert 	time_t oldprobedelay = 0;
674b7579f77SDag-Erling Smørgrav 	if(!e) {
675b7579f77SDag-Erling Smørgrav 		if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow)))
676b7579f77SDag-Erling Smørgrav 			return 0;
677b7579f77SDag-Erling Smørgrav 		needtoinsert = 1;
678b7579f77SDag-Erling Smørgrav 	} else if(((struct infra_data*)e->data)->ttl < timenow) {
679369c6923SCy Schubert 		oldprobedelay = ((struct infra_data*)e->data)->probedelay;
680b7579f77SDag-Erling Smørgrav 		data_entry_init(infra, e, timenow);
681369c6923SCy Schubert 		expired = 1;
682b7579f77SDag-Erling Smørgrav 	}
683b7579f77SDag-Erling Smørgrav 	/* have an entry, update the rtt */
684b7579f77SDag-Erling Smørgrav 	data = (struct infra_data*)e->data;
685b7579f77SDag-Erling Smørgrav 	if(roundtrip == -1) {
686369c6923SCy Schubert 		if(needtoinsert || expired) {
687369c6923SCy Schubert 			/* timeout on entry that has expired before the timer
688369c6923SCy Schubert 			 * keep old timeout from the function caller */
689369c6923SCy Schubert 			data->rtt.rto = orig_rtt;
690369c6923SCy Schubert 			data->probedelay = oldprobedelay;
691369c6923SCy Schubert 		}
692b7579f77SDag-Erling Smørgrav 		rtt_lost(&data->rtt, orig_rtt);
693b7579f77SDag-Erling Smørgrav 		if(qtype == LDNS_RR_TYPE_A) {
694b7579f77SDag-Erling Smørgrav 			if(data->timeout_A < TIMEOUT_COUNT_MAX)
695b7579f77SDag-Erling Smørgrav 				data->timeout_A++;
696b7579f77SDag-Erling Smørgrav 		} else if(qtype == LDNS_RR_TYPE_AAAA) {
697b7579f77SDag-Erling Smørgrav 			if(data->timeout_AAAA < TIMEOUT_COUNT_MAX)
698b7579f77SDag-Erling Smørgrav 				data->timeout_AAAA++;
699b7579f77SDag-Erling Smørgrav 		} else {
700b7579f77SDag-Erling Smørgrav 			if(data->timeout_other < TIMEOUT_COUNT_MAX)
701b7579f77SDag-Erling Smørgrav 				data->timeout_other++;
702b7579f77SDag-Erling Smørgrav 		}
703b7579f77SDag-Erling Smørgrav 	} else {
7048ed2b524SDag-Erling Smørgrav 		/* if we got a reply, but the old timeout was above server
7058ed2b524SDag-Erling Smørgrav 		 * selection height, delete the timeout so the server is
7068ed2b524SDag-Erling Smørgrav 		 * fully available again */
7078ed2b524SDag-Erling Smørgrav 		if(rtt_unclamped(&data->rtt) >= USEFUL_SERVER_TOP_TIMEOUT)
7088ed2b524SDag-Erling Smørgrav 			rtt_init(&data->rtt);
709b7579f77SDag-Erling Smørgrav 		rtt_update(&data->rtt, roundtrip);
710b7579f77SDag-Erling Smørgrav 		data->probedelay = 0;
711b7579f77SDag-Erling Smørgrav 		if(qtype == LDNS_RR_TYPE_A)
712b7579f77SDag-Erling Smørgrav 			data->timeout_A = 0;
713b7579f77SDag-Erling Smørgrav 		else if(qtype == LDNS_RR_TYPE_AAAA)
714b7579f77SDag-Erling Smørgrav 			data->timeout_AAAA = 0;
715b7579f77SDag-Erling Smørgrav 		else	data->timeout_other = 0;
716b7579f77SDag-Erling Smørgrav 	}
717b7579f77SDag-Erling Smørgrav 	if(data->rtt.rto > 0)
718b7579f77SDag-Erling Smørgrav 		rto = data->rtt.rto;
719b7579f77SDag-Erling Smørgrav 
720b7579f77SDag-Erling Smørgrav 	if(needtoinsert)
721b7579f77SDag-Erling Smørgrav 		slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
722b7579f77SDag-Erling Smørgrav 	else 	{ lock_rw_unlock(&e->lock); }
723b7579f77SDag-Erling Smørgrav 	return rto;
724b7579f77SDag-Erling Smørgrav }
725b7579f77SDag-Erling Smørgrav 
infra_get_host_rto(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * nm,size_t nmlen,struct rtt_info * rtt,int * delay,time_t timenow,int * tA,int * tAAAA,int * tother)72617d15b25SDag-Erling Smørgrav long long infra_get_host_rto(struct infra_cache* infra,
727b7579f77SDag-Erling Smørgrav         struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm,
72817d15b25SDag-Erling Smørgrav 	size_t nmlen, struct rtt_info* rtt, int* delay, time_t timenow,
729b7579f77SDag-Erling Smørgrav 	int* tA, int* tAAAA, int* tother)
730b7579f77SDag-Erling Smørgrav {
731b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
732b7579f77SDag-Erling Smørgrav 		nm, nmlen, 0);
733b7579f77SDag-Erling Smørgrav 	struct infra_data* data;
73417d15b25SDag-Erling Smørgrav 	long long ttl = -2;
735b7579f77SDag-Erling Smørgrav 	if(!e) return -1;
736b7579f77SDag-Erling Smørgrav 	data = (struct infra_data*)e->data;
737b7579f77SDag-Erling Smørgrav 	if(data->ttl >= timenow) {
73817d15b25SDag-Erling Smørgrav 		ttl = (long long)(data->ttl - timenow);
739b7579f77SDag-Erling Smørgrav 		memmove(rtt, &data->rtt, sizeof(*rtt));
740b7579f77SDag-Erling Smørgrav 		if(timenow < data->probedelay)
741b7579f77SDag-Erling Smørgrav 			*delay = (int)(data->probedelay - timenow);
742b7579f77SDag-Erling Smørgrav 		else	*delay = 0;
743b7579f77SDag-Erling Smørgrav 	}
744b7579f77SDag-Erling Smørgrav 	*tA = (int)data->timeout_A;
745b7579f77SDag-Erling Smørgrav 	*tAAAA = (int)data->timeout_AAAA;
746b7579f77SDag-Erling Smørgrav 	*tother = (int)data->timeout_other;
747b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&e->lock);
748b7579f77SDag-Erling Smørgrav 	return ttl;
749b7579f77SDag-Erling Smørgrav }
750b7579f77SDag-Erling Smørgrav 
751b7579f77SDag-Erling Smørgrav int
infra_edns_update(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * nm,size_t nmlen,int edns_version,time_t timenow)752b7579f77SDag-Erling Smørgrav infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr,
753b7579f77SDag-Erling Smørgrav 	socklen_t addrlen, uint8_t* nm, size_t nmlen, int edns_version,
75417d15b25SDag-Erling Smørgrav 	time_t timenow)
755b7579f77SDag-Erling Smørgrav {
756b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
757b7579f77SDag-Erling Smørgrav 		nm, nmlen, 1);
758b7579f77SDag-Erling Smørgrav 	struct infra_data* data;
759b7579f77SDag-Erling Smørgrav 	int needtoinsert = 0;
760b7579f77SDag-Erling Smørgrav 	if(!e) {
761b7579f77SDag-Erling Smørgrav 		if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow)))
762b7579f77SDag-Erling Smørgrav 			return 0;
763b7579f77SDag-Erling Smørgrav 		needtoinsert = 1;
764b7579f77SDag-Erling Smørgrav 	} else if(((struct infra_data*)e->data)->ttl < timenow) {
765b7579f77SDag-Erling Smørgrav 		data_entry_init(infra, e, timenow);
766b7579f77SDag-Erling Smørgrav 	}
767b7579f77SDag-Erling Smørgrav 	/* have an entry, update the rtt, and the ttl */
768b7579f77SDag-Erling Smørgrav 	data = (struct infra_data*)e->data;
769b7579f77SDag-Erling Smørgrav 	/* do not update if noEDNS and stored is yesEDNS */
770b7579f77SDag-Erling Smørgrav 	if(!(edns_version == -1 && (data->edns_version != -1 &&
771b7579f77SDag-Erling Smørgrav 		data->edns_lame_known))) {
772b7579f77SDag-Erling Smørgrav 		data->edns_version = edns_version;
773b7579f77SDag-Erling Smørgrav 		data->edns_lame_known = 1;
774b7579f77SDag-Erling Smørgrav 	}
775b7579f77SDag-Erling Smørgrav 
776b7579f77SDag-Erling Smørgrav 	if(needtoinsert)
777b7579f77SDag-Erling Smørgrav 		slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
778b7579f77SDag-Erling Smørgrav 	else 	{ lock_rw_unlock(&e->lock); }
779b7579f77SDag-Erling Smørgrav 	return 1;
780b7579f77SDag-Erling Smørgrav }
781b7579f77SDag-Erling Smørgrav 
782b7579f77SDag-Erling Smørgrav int
infra_get_lame_rtt(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * name,size_t namelen,uint16_t qtype,int * lame,int * dnsseclame,int * reclame,int * rtt,time_t timenow)783b7579f77SDag-Erling Smørgrav infra_get_lame_rtt(struct infra_cache* infra,
784b7579f77SDag-Erling Smørgrav         struct sockaddr_storage* addr, socklen_t addrlen,
785b7579f77SDag-Erling Smørgrav         uint8_t* name, size_t namelen, uint16_t qtype,
78617d15b25SDag-Erling Smørgrav 	int* lame, int* dnsseclame, int* reclame, int* rtt, time_t timenow)
787b7579f77SDag-Erling Smørgrav {
788b7579f77SDag-Erling Smørgrav 	struct infra_data* host;
789b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
790b7579f77SDag-Erling Smørgrav 		name, namelen, 0);
791b7579f77SDag-Erling Smørgrav 	if(!e)
792b7579f77SDag-Erling Smørgrav 		return 0;
793b7579f77SDag-Erling Smørgrav 	host = (struct infra_data*)e->data;
794b7579f77SDag-Erling Smørgrav 	*rtt = rtt_unclamped(&host->rtt);
795369c6923SCy Schubert 	if(host->rtt.rto >= PROBE_MAXRTO && timenow >= host->probedelay
796369c6923SCy Schubert 		&& infra->infra_keep_probing) {
797369c6923SCy Schubert 		/* single probe, keep probing */
798369c6923SCy Schubert 		if(*rtt >= USEFUL_SERVER_TOP_TIMEOUT)
799369c6923SCy Schubert 			*rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
800369c6923SCy Schubert 	} else if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay
801b7579f77SDag-Erling Smørgrav 		&& rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) {
802b7579f77SDag-Erling Smørgrav 		/* single probe for this domain, and we are not probing */
803b7579f77SDag-Erling Smørgrav 		/* unless the query type allows a probe to happen */
804b7579f77SDag-Erling Smørgrav 		if(qtype == LDNS_RR_TYPE_A) {
805b7579f77SDag-Erling Smørgrav 			if(host->timeout_A >= TIMEOUT_COUNT_MAX)
806b7579f77SDag-Erling Smørgrav 				*rtt = USEFUL_SERVER_TOP_TIMEOUT;
807b7579f77SDag-Erling Smørgrav 			else	*rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
808b7579f77SDag-Erling Smørgrav 		} else if(qtype == LDNS_RR_TYPE_AAAA) {
809b7579f77SDag-Erling Smørgrav 			if(host->timeout_AAAA >= TIMEOUT_COUNT_MAX)
810b7579f77SDag-Erling Smørgrav 				*rtt = USEFUL_SERVER_TOP_TIMEOUT;
811b7579f77SDag-Erling Smørgrav 			else	*rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
812b7579f77SDag-Erling Smørgrav 		} else {
813b7579f77SDag-Erling Smørgrav 			if(host->timeout_other >= TIMEOUT_COUNT_MAX)
814b7579f77SDag-Erling Smørgrav 				*rtt = USEFUL_SERVER_TOP_TIMEOUT;
815b7579f77SDag-Erling Smørgrav 			else	*rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
816b7579f77SDag-Erling Smørgrav 		}
817b7579f77SDag-Erling Smørgrav 	}
818b7579f77SDag-Erling Smørgrav 	/* expired entry */
819790c6b24SCy Schubert 	if(timenow > host->ttl) {
820790c6b24SCy Schubert 
821b7579f77SDag-Erling Smørgrav 		/* see if this can be a re-probe of an unresponsive server */
822b7579f77SDag-Erling Smørgrav 		/* minus 1000 because that is outside of the RTTBAND, so
823b7579f77SDag-Erling Smørgrav 		 * blacklisted servers stay blacklisted if this is chosen */
824790c6b24SCy Schubert 		if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
825b7579f77SDag-Erling Smørgrav 			lock_rw_unlock(&e->lock);
826b7579f77SDag-Erling Smørgrav 			*rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
827b7579f77SDag-Erling Smørgrav 			*lame = 0;
828b7579f77SDag-Erling Smørgrav 			*dnsseclame = 0;
829b7579f77SDag-Erling Smørgrav 			*reclame = 0;
830b7579f77SDag-Erling Smørgrav 			return 1;
831b7579f77SDag-Erling Smørgrav 		}
832b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&e->lock);
833b7579f77SDag-Erling Smørgrav 		return 0;
834b7579f77SDag-Erling Smørgrav 	}
835b7579f77SDag-Erling Smørgrav 	/* check lameness first */
836b7579f77SDag-Erling Smørgrav 	if(host->lame_type_A && qtype == LDNS_RR_TYPE_A) {
837b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&e->lock);
838b7579f77SDag-Erling Smørgrav 		*lame = 1;
839b7579f77SDag-Erling Smørgrav 		*dnsseclame = 0;
840b7579f77SDag-Erling Smørgrav 		*reclame = 0;
841b7579f77SDag-Erling Smørgrav 		return 1;
842b7579f77SDag-Erling Smørgrav 	} else if(host->lame_other && qtype != LDNS_RR_TYPE_A) {
843b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&e->lock);
844b7579f77SDag-Erling Smørgrav 		*lame = 1;
845b7579f77SDag-Erling Smørgrav 		*dnsseclame = 0;
846b7579f77SDag-Erling Smørgrav 		*reclame = 0;
847b7579f77SDag-Erling Smørgrav 		return 1;
848b7579f77SDag-Erling Smørgrav 	} else if(host->isdnsseclame) {
849b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&e->lock);
850b7579f77SDag-Erling Smørgrav 		*lame = 0;
851b7579f77SDag-Erling Smørgrav 		*dnsseclame = 1;
852b7579f77SDag-Erling Smørgrav 		*reclame = 0;
853b7579f77SDag-Erling Smørgrav 		return 1;
854b7579f77SDag-Erling Smørgrav 	} else if(host->rec_lame) {
855b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&e->lock);
856b7579f77SDag-Erling Smørgrav 		*lame = 0;
857b7579f77SDag-Erling Smørgrav 		*dnsseclame = 0;
858b7579f77SDag-Erling Smørgrav 		*reclame = 1;
859b7579f77SDag-Erling Smørgrav 		return 1;
860b7579f77SDag-Erling Smørgrav 	}
861b7579f77SDag-Erling Smørgrav 	/* no lameness for this type of query */
862b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&e->lock);
863b7579f77SDag-Erling Smørgrav 	*lame = 0;
864b7579f77SDag-Erling Smørgrav 	*dnsseclame = 0;
865b7579f77SDag-Erling Smørgrav 	*reclame = 0;
866b7579f77SDag-Erling Smørgrav 	return 1;
867b7579f77SDag-Erling Smørgrav }
868b7579f77SDag-Erling Smørgrav 
infra_find_ratelimit(struct infra_cache * infra,uint8_t * name,size_t namelen)86909a3aaf3SDag-Erling Smørgrav int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
87009a3aaf3SDag-Erling Smørgrav 	size_t namelen)
87109a3aaf3SDag-Erling Smørgrav {
87209a3aaf3SDag-Erling Smørgrav 	int labs = dname_count_labels(name);
87309a3aaf3SDag-Erling Smørgrav 	struct domain_limit_data* d = (struct domain_limit_data*)
87409a3aaf3SDag-Erling Smørgrav 		name_tree_lookup(&infra->domain_limits, name, namelen, labs,
87509a3aaf3SDag-Erling Smørgrav 		LDNS_RR_CLASS_IN);
87609a3aaf3SDag-Erling Smørgrav 	if(!d) return infra_dp_ratelimit;
87709a3aaf3SDag-Erling Smørgrav 
87809a3aaf3SDag-Erling Smørgrav 	if(d->node.labs == labs && d->lim != -1)
87909a3aaf3SDag-Erling Smørgrav 		return d->lim; /* exact match */
88009a3aaf3SDag-Erling Smørgrav 
88109a3aaf3SDag-Erling Smørgrav 	/* find 'below match' */
88209a3aaf3SDag-Erling Smørgrav 	if(d->node.labs == labs)
88309a3aaf3SDag-Erling Smørgrav 		d = (struct domain_limit_data*)d->node.parent;
88409a3aaf3SDag-Erling Smørgrav 	while(d) {
88509a3aaf3SDag-Erling Smørgrav 		if(d->below != -1)
88609a3aaf3SDag-Erling Smørgrav 			return d->below;
88709a3aaf3SDag-Erling Smørgrav 		d = (struct domain_limit_data*)d->node.parent;
88809a3aaf3SDag-Erling Smørgrav 	}
88909a3aaf3SDag-Erling Smørgrav 	return infra_dp_ratelimit;
89009a3aaf3SDag-Erling Smørgrav }
89109a3aaf3SDag-Erling Smørgrav 
ip_rate_sizefunc(void * k,void * ATTR_UNUSED (d))8923005e0a3SDag-Erling Smørgrav size_t ip_rate_sizefunc(void* k, void* ATTR_UNUSED(d))
8933005e0a3SDag-Erling Smørgrav {
8943005e0a3SDag-Erling Smørgrav 	struct ip_rate_key* key = (struct ip_rate_key*)k;
8953005e0a3SDag-Erling Smørgrav 	return sizeof(*key) + sizeof(struct ip_rate_data)
8963005e0a3SDag-Erling Smørgrav 		+ lock_get_mem(&key->entry.lock);
8973005e0a3SDag-Erling Smørgrav }
8983005e0a3SDag-Erling Smørgrav 
ip_rate_compfunc(void * key1,void * key2)8993005e0a3SDag-Erling Smørgrav int ip_rate_compfunc(void* key1, void* key2)
9003005e0a3SDag-Erling Smørgrav {
9013005e0a3SDag-Erling Smørgrav 	struct ip_rate_key* k1 = (struct ip_rate_key*)key1;
9023005e0a3SDag-Erling Smørgrav 	struct ip_rate_key* k2 = (struct ip_rate_key*)key2;
9033005e0a3SDag-Erling Smørgrav 	return sockaddr_cmp_addr(&k1->addr, k1->addrlen,
9043005e0a3SDag-Erling Smørgrav 		&k2->addr, k2->addrlen);
9053005e0a3SDag-Erling Smørgrav }
9063005e0a3SDag-Erling Smørgrav 
ip_rate_delkeyfunc(void * k,void * ATTR_UNUSED (arg))9073005e0a3SDag-Erling Smørgrav void ip_rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
9083005e0a3SDag-Erling Smørgrav {
9093005e0a3SDag-Erling Smørgrav 	struct ip_rate_key* key = (struct ip_rate_key*)k;
9103005e0a3SDag-Erling Smørgrav 	if(!key)
9113005e0a3SDag-Erling Smørgrav 		return;
9123005e0a3SDag-Erling Smørgrav 	lock_rw_destroy(&key->entry.lock);
9133005e0a3SDag-Erling Smørgrav 	free(key);
9143005e0a3SDag-Erling Smørgrav }
9153005e0a3SDag-Erling Smørgrav 
91609a3aaf3SDag-Erling Smørgrav /** find data item in array, for write access, caller unlocks */
infra_find_ratedata(struct infra_cache * infra,uint8_t * name,size_t namelen,int wr)91709a3aaf3SDag-Erling Smørgrav static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra,
91809a3aaf3SDag-Erling Smørgrav 	uint8_t* name, size_t namelen, int wr)
91909a3aaf3SDag-Erling Smørgrav {
92009a3aaf3SDag-Erling Smørgrav 	struct rate_key key;
9213005e0a3SDag-Erling Smørgrav 	hashvalue_type h = dname_query_hash(name, 0xab);
92209a3aaf3SDag-Erling Smørgrav 	memset(&key, 0, sizeof(key));
92309a3aaf3SDag-Erling Smørgrav 	key.name = name;
92409a3aaf3SDag-Erling Smørgrav 	key.namelen = namelen;
92509a3aaf3SDag-Erling Smørgrav 	key.entry.hash = h;
92609a3aaf3SDag-Erling Smørgrav 	return slabhash_lookup(infra->domain_rates, h, &key, wr);
92709a3aaf3SDag-Erling Smørgrav }
92809a3aaf3SDag-Erling Smørgrav 
9293005e0a3SDag-Erling Smørgrav /** find data item in array for ip addresses */
infra_find_ip_ratedata(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,int wr)9303005e0a3SDag-Erling Smørgrav static struct lruhash_entry* infra_find_ip_ratedata(struct infra_cache* infra,
931865f46b2SCy Schubert 	struct sockaddr_storage* addr, socklen_t addrlen, int wr)
9323005e0a3SDag-Erling Smørgrav {
9333005e0a3SDag-Erling Smørgrav 	struct ip_rate_key key;
934865f46b2SCy Schubert 	hashvalue_type h = hash_addr(addr, addrlen, 0);
9353005e0a3SDag-Erling Smørgrav 	memset(&key, 0, sizeof(key));
936865f46b2SCy Schubert 	key.addr = *addr;
937865f46b2SCy Schubert 	key.addrlen = addrlen;
9383005e0a3SDag-Erling Smørgrav 	key.entry.hash = h;
9393005e0a3SDag-Erling Smørgrav 	return slabhash_lookup(infra->client_ip_rates, h, &key, wr);
9403005e0a3SDag-Erling Smørgrav }
9413005e0a3SDag-Erling Smørgrav 
94209a3aaf3SDag-Erling Smørgrav /** create rate data item for name, number 1 in now */
infra_create_ratedata(struct infra_cache * infra,uint8_t * name,size_t namelen,time_t timenow)94309a3aaf3SDag-Erling Smørgrav static void infra_create_ratedata(struct infra_cache* infra,
94409a3aaf3SDag-Erling Smørgrav 	uint8_t* name, size_t namelen, time_t timenow)
94509a3aaf3SDag-Erling Smørgrav {
9463005e0a3SDag-Erling Smørgrav 	hashvalue_type h = dname_query_hash(name, 0xab);
94709a3aaf3SDag-Erling Smørgrav 	struct rate_key* k = (struct rate_key*)calloc(1, sizeof(*k));
94809a3aaf3SDag-Erling Smørgrav 	struct rate_data* d = (struct rate_data*)calloc(1, sizeof(*d));
94909a3aaf3SDag-Erling Smørgrav 	if(!k || !d) {
95009a3aaf3SDag-Erling Smørgrav 		free(k);
95109a3aaf3SDag-Erling Smørgrav 		free(d);
95209a3aaf3SDag-Erling Smørgrav 		return; /* alloc failure */
95309a3aaf3SDag-Erling Smørgrav 	}
95409a3aaf3SDag-Erling Smørgrav 	k->namelen = namelen;
95509a3aaf3SDag-Erling Smørgrav 	k->name = memdup(name, namelen);
95609a3aaf3SDag-Erling Smørgrav 	if(!k->name) {
95709a3aaf3SDag-Erling Smørgrav 		free(k);
95809a3aaf3SDag-Erling Smørgrav 		free(d);
95909a3aaf3SDag-Erling Smørgrav 		return; /* alloc failure */
96009a3aaf3SDag-Erling Smørgrav 	}
96109a3aaf3SDag-Erling Smørgrav 	lock_rw_init(&k->entry.lock);
96209a3aaf3SDag-Erling Smørgrav 	k->entry.hash = h;
96309a3aaf3SDag-Erling Smørgrav 	k->entry.key = k;
96409a3aaf3SDag-Erling Smørgrav 	k->entry.data = d;
96509a3aaf3SDag-Erling Smørgrav 	d->qps[0] = 1;
96609a3aaf3SDag-Erling Smørgrav 	d->timestamp[0] = timenow;
96709a3aaf3SDag-Erling Smørgrav 	slabhash_insert(infra->domain_rates, h, &k->entry, d, NULL);
96809a3aaf3SDag-Erling Smørgrav }
96909a3aaf3SDag-Erling Smørgrav 
9703005e0a3SDag-Erling Smørgrav /** create rate data item for ip address */
infra_ip_create_ratedata(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,time_t timenow,int mesh_wait)9713005e0a3SDag-Erling Smørgrav static void infra_ip_create_ratedata(struct infra_cache* infra,
972*335c7cdaSCy Schubert 	struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow,
973*335c7cdaSCy Schubert 	int mesh_wait)
9743005e0a3SDag-Erling Smørgrav {
975865f46b2SCy Schubert 	hashvalue_type h = hash_addr(addr, addrlen, 0);
9763005e0a3SDag-Erling Smørgrav 	struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k));
9773005e0a3SDag-Erling Smørgrav 	struct ip_rate_data* d = (struct ip_rate_data*)calloc(1, sizeof(*d));
9783005e0a3SDag-Erling Smørgrav 	if(!k || !d) {
9793005e0a3SDag-Erling Smørgrav 		free(k);
9803005e0a3SDag-Erling Smørgrav 		free(d);
9813005e0a3SDag-Erling Smørgrav 		return; /* alloc failure */
9823005e0a3SDag-Erling Smørgrav 	}
983865f46b2SCy Schubert 	k->addr = *addr;
984865f46b2SCy Schubert 	k->addrlen = addrlen;
9853005e0a3SDag-Erling Smørgrav 	lock_rw_init(&k->entry.lock);
9863005e0a3SDag-Erling Smørgrav 	k->entry.hash = h;
9873005e0a3SDag-Erling Smørgrav 	k->entry.key = k;
9883005e0a3SDag-Erling Smørgrav 	k->entry.data = d;
9893005e0a3SDag-Erling Smørgrav 	d->qps[0] = 1;
9903005e0a3SDag-Erling Smørgrav 	d->timestamp[0] = timenow;
991*335c7cdaSCy Schubert 	d->mesh_wait = mesh_wait;
9923005e0a3SDag-Erling Smørgrav 	slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL);
9933005e0a3SDag-Erling Smørgrav }
9943005e0a3SDag-Erling Smørgrav 
9959cf5bc93SCy Schubert /** Find the second and return its rate counter. If none and should_add, remove
9969cf5bc93SCy Schubert  *  oldest to accommodate. Else return none. */
infra_rate_find_second_or_none(void * data,time_t t,int should_add)9979cf5bc93SCy Schubert static int* infra_rate_find_second_or_none(void* data, time_t t, int should_add)
99809a3aaf3SDag-Erling Smørgrav {
99909a3aaf3SDag-Erling Smørgrav 	struct rate_data* d = (struct rate_data*)data;
100009a3aaf3SDag-Erling Smørgrav 	int i, oldest;
100109a3aaf3SDag-Erling Smørgrav 	for(i=0; i<RATE_WINDOW; i++) {
100209a3aaf3SDag-Erling Smørgrav 		if(d->timestamp[i] == t)
100309a3aaf3SDag-Erling Smørgrav 			return &(d->qps[i]);
100409a3aaf3SDag-Erling Smørgrav 	}
10059cf5bc93SCy Schubert 	if(!should_add) return NULL;
100609a3aaf3SDag-Erling Smørgrav 	/* remove oldest timestamp, and insert it at t with 0 qps */
100709a3aaf3SDag-Erling Smørgrav 	oldest = 0;
100809a3aaf3SDag-Erling Smørgrav 	for(i=0; i<RATE_WINDOW; i++) {
100909a3aaf3SDag-Erling Smørgrav 		if(d->timestamp[i] < d->timestamp[oldest])
101009a3aaf3SDag-Erling Smørgrav 			oldest = i;
101109a3aaf3SDag-Erling Smørgrav 	}
101209a3aaf3SDag-Erling Smørgrav 	d->timestamp[oldest] = t;
101309a3aaf3SDag-Erling Smørgrav 	d->qps[oldest] = 0;
101409a3aaf3SDag-Erling Smørgrav 	return &(d->qps[oldest]);
101509a3aaf3SDag-Erling Smørgrav }
101609a3aaf3SDag-Erling Smørgrav 
10179cf5bc93SCy Schubert /** find the second and return its rate counter, if none, remove oldest to
10189cf5bc93SCy Schubert  *  accommodate */
infra_rate_give_second(void * data,time_t t)10199cf5bc93SCy Schubert static int* infra_rate_give_second(void* data, time_t t)
10209cf5bc93SCy Schubert {
10219cf5bc93SCy Schubert     return infra_rate_find_second_or_none(data, t, 1);
10229cf5bc93SCy Schubert }
10239cf5bc93SCy Schubert 
10249cf5bc93SCy Schubert /** find the second and return its rate counter only if it exists. Caller
10259cf5bc93SCy Schubert  *  should check for NULL return value */
infra_rate_get_second(void * data,time_t t)10269cf5bc93SCy Schubert static int* infra_rate_get_second(void* data, time_t t)
10279cf5bc93SCy Schubert {
10289cf5bc93SCy Schubert     return infra_rate_find_second_or_none(data, t, 0);
10299cf5bc93SCy Schubert }
10309cf5bc93SCy Schubert 
infra_rate_max(void * data,time_t now,int backoff)10319cf5bc93SCy Schubert int infra_rate_max(void* data, time_t now, int backoff)
103209a3aaf3SDag-Erling Smørgrav {
103309a3aaf3SDag-Erling Smørgrav 	struct rate_data* d = (struct rate_data*)data;
103409a3aaf3SDag-Erling Smørgrav 	int i, max = 0;
103509a3aaf3SDag-Erling Smørgrav 	for(i=0; i<RATE_WINDOW; i++) {
10369cf5bc93SCy Schubert 		if(backoff) {
10379cf5bc93SCy Schubert 			if(now-d->timestamp[i] <= RATE_WINDOW &&
10389cf5bc93SCy Schubert 				d->qps[i] > max) {
103909a3aaf3SDag-Erling Smørgrav 				max = d->qps[i];
104009a3aaf3SDag-Erling Smørgrav 			}
10419cf5bc93SCy Schubert 		} else {
10429cf5bc93SCy Schubert 			if(now == d->timestamp[i]) {
10439cf5bc93SCy Schubert 				return d->qps[i];
10449cf5bc93SCy Schubert 			}
10459cf5bc93SCy Schubert 		}
104609a3aaf3SDag-Erling Smørgrav 	}
104709a3aaf3SDag-Erling Smørgrav 	return max;
104809a3aaf3SDag-Erling Smørgrav }
104909a3aaf3SDag-Erling Smørgrav 
infra_ratelimit_inc(struct infra_cache * infra,uint8_t * name,size_t namelen,time_t timenow,int backoff,struct query_info * qinfo,struct comm_reply * replylist)105009a3aaf3SDag-Erling Smørgrav int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
10519cf5bc93SCy Schubert 	size_t namelen, time_t timenow, int backoff, struct query_info* qinfo,
1052e86b9096SDag-Erling Smørgrav 	struct comm_reply* replylist)
105309a3aaf3SDag-Erling Smørgrav {
105409a3aaf3SDag-Erling Smørgrav 	int lim, max;
105509a3aaf3SDag-Erling Smørgrav 	struct lruhash_entry* entry;
105609a3aaf3SDag-Erling Smørgrav 
105709a3aaf3SDag-Erling Smørgrav 	if(!infra_dp_ratelimit)
105809a3aaf3SDag-Erling Smørgrav 		return 1; /* not enabled */
105909a3aaf3SDag-Erling Smørgrav 
106009a3aaf3SDag-Erling Smørgrav 	/* find ratelimit */
106109a3aaf3SDag-Erling Smørgrav 	lim = infra_find_ratelimit(infra, name, namelen);
1062c7f4d7adSDag-Erling Smørgrav 	if(!lim)
1063c7f4d7adSDag-Erling Smørgrav 		return 1; /* disabled for this domain */
106409a3aaf3SDag-Erling Smørgrav 
106509a3aaf3SDag-Erling Smørgrav 	/* find or insert ratedata */
106609a3aaf3SDag-Erling Smørgrav 	entry = infra_find_ratedata(infra, name, namelen, 1);
106709a3aaf3SDag-Erling Smørgrav 	if(entry) {
10689cf5bc93SCy Schubert 		int premax = infra_rate_max(entry->data, timenow, backoff);
10699cf5bc93SCy Schubert 		int* cur = infra_rate_give_second(entry->data, timenow);
107009a3aaf3SDag-Erling Smørgrav 		(*cur)++;
10719cf5bc93SCy Schubert 		max = infra_rate_max(entry->data, timenow, backoff);
107209a3aaf3SDag-Erling Smørgrav 		lock_rw_unlock(&entry->lock);
107309a3aaf3SDag-Erling Smørgrav 
10749cf5bc93SCy Schubert 		if(premax <= lim && max > lim) {
1075e86b9096SDag-Erling Smørgrav 			char buf[257], qnm[257], ts[12], cs[12], ip[128];
107609a3aaf3SDag-Erling Smørgrav 			dname_str(name, buf);
1077e86b9096SDag-Erling Smørgrav 			dname_str(qinfo->qname, qnm);
1078e86b9096SDag-Erling Smørgrav 			sldns_wire2str_type_buf(qinfo->qtype, ts, sizeof(ts));
1079e86b9096SDag-Erling Smørgrav 			sldns_wire2str_class_buf(qinfo->qclass, cs, sizeof(cs));
1080e86b9096SDag-Erling Smørgrav 			ip[0]=0;
1081e86b9096SDag-Erling Smørgrav 			if(replylist) {
1082865f46b2SCy Schubert 				addr_to_str((struct sockaddr_storage *)&replylist->remote_addr,
1083865f46b2SCy Schubert 					replylist->remote_addrlen, ip, sizeof(ip));
1084e86b9096SDag-Erling Smørgrav 				verbose(VERB_OPS, "ratelimit exceeded %s %d query %s %s %s from %s", buf, lim, qnm, cs, ts, ip);
1085e86b9096SDag-Erling Smørgrav 			} else {
1086e86b9096SDag-Erling Smørgrav 				verbose(VERB_OPS, "ratelimit exceeded %s %d query %s %s %s", buf, lim, qnm, cs, ts);
1087e86b9096SDag-Erling Smørgrav 			}
108809a3aaf3SDag-Erling Smørgrav 		}
10899cf5bc93SCy Schubert 		return (max <= lim);
109009a3aaf3SDag-Erling Smørgrav 	}
109109a3aaf3SDag-Erling Smørgrav 
109209a3aaf3SDag-Erling Smørgrav 	/* create */
109309a3aaf3SDag-Erling Smørgrav 	infra_create_ratedata(infra, name, namelen, timenow);
10949cf5bc93SCy Schubert 	return (1 <= lim);
109509a3aaf3SDag-Erling Smørgrav }
109609a3aaf3SDag-Erling Smørgrav 
infra_ratelimit_dec(struct infra_cache * infra,uint8_t * name,size_t namelen,time_t timenow)109709a3aaf3SDag-Erling Smørgrav void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name,
109809a3aaf3SDag-Erling Smørgrav 	size_t namelen, time_t timenow)
109909a3aaf3SDag-Erling Smørgrav {
110009a3aaf3SDag-Erling Smørgrav 	struct lruhash_entry* entry;
110109a3aaf3SDag-Erling Smørgrav 	int* cur;
110209a3aaf3SDag-Erling Smørgrav 	if(!infra_dp_ratelimit)
110309a3aaf3SDag-Erling Smørgrav 		return; /* not enabled */
110409a3aaf3SDag-Erling Smørgrav 	entry = infra_find_ratedata(infra, name, namelen, 1);
110509a3aaf3SDag-Erling Smørgrav 	if(!entry) return; /* not cached */
11069cf5bc93SCy Schubert 	cur = infra_rate_get_second(entry->data, timenow);
11079cf5bc93SCy Schubert 	if(cur == NULL) {
11089cf5bc93SCy Schubert 		/* our timenow is not available anymore; nothing to decrease */
11099cf5bc93SCy Schubert 		lock_rw_unlock(&entry->lock);
11109cf5bc93SCy Schubert 		return;
11119cf5bc93SCy Schubert 	}
111209a3aaf3SDag-Erling Smørgrav 	if((*cur) > 0)
111309a3aaf3SDag-Erling Smørgrav 		(*cur)--;
111409a3aaf3SDag-Erling Smørgrav 	lock_rw_unlock(&entry->lock);
111509a3aaf3SDag-Erling Smørgrav }
111609a3aaf3SDag-Erling Smørgrav 
infra_ratelimit_exceeded(struct infra_cache * infra,uint8_t * name,size_t namelen,time_t timenow,int backoff)111709a3aaf3SDag-Erling Smørgrav int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name,
11189cf5bc93SCy Schubert 	size_t namelen, time_t timenow, int backoff)
111909a3aaf3SDag-Erling Smørgrav {
112009a3aaf3SDag-Erling Smørgrav 	struct lruhash_entry* entry;
112109a3aaf3SDag-Erling Smørgrav 	int lim, max;
112209a3aaf3SDag-Erling Smørgrav 	if(!infra_dp_ratelimit)
112309a3aaf3SDag-Erling Smørgrav 		return 0; /* not enabled */
112409a3aaf3SDag-Erling Smørgrav 
112509a3aaf3SDag-Erling Smørgrav 	/* find ratelimit */
112609a3aaf3SDag-Erling Smørgrav 	lim = infra_find_ratelimit(infra, name, namelen);
1127c7f4d7adSDag-Erling Smørgrav 	if(!lim)
1128c7f4d7adSDag-Erling Smørgrav 		return 0; /* disabled for this domain */
112909a3aaf3SDag-Erling Smørgrav 
113009a3aaf3SDag-Erling Smørgrav 	/* find current rate */
113109a3aaf3SDag-Erling Smørgrav 	entry = infra_find_ratedata(infra, name, namelen, 0);
113209a3aaf3SDag-Erling Smørgrav 	if(!entry)
113309a3aaf3SDag-Erling Smørgrav 		return 0; /* not cached */
11349cf5bc93SCy Schubert 	max = infra_rate_max(entry->data, timenow, backoff);
113509a3aaf3SDag-Erling Smørgrav 	lock_rw_unlock(&entry->lock);
113609a3aaf3SDag-Erling Smørgrav 
1137865f46b2SCy Schubert 	return (max > lim);
113809a3aaf3SDag-Erling Smørgrav }
113909a3aaf3SDag-Erling Smørgrav 
1140b7579f77SDag-Erling Smørgrav size_t
infra_get_mem(struct infra_cache * infra)1141b7579f77SDag-Erling Smørgrav infra_get_mem(struct infra_cache* infra)
1142b7579f77SDag-Erling Smørgrav {
114309a3aaf3SDag-Erling Smørgrav 	size_t s = sizeof(*infra) + slabhash_get_mem(infra->hosts);
114409a3aaf3SDag-Erling Smørgrav 	if(infra->domain_rates) s += slabhash_get_mem(infra->domain_rates);
11453005e0a3SDag-Erling Smørgrav 	if(infra->client_ip_rates) s += slabhash_get_mem(infra->client_ip_rates);
114609a3aaf3SDag-Erling Smørgrav 	/* ignore domain_limits because walk through tree is big */
114709a3aaf3SDag-Erling Smørgrav 	return s;
1148b7579f77SDag-Erling Smørgrav }
11493005e0a3SDag-Erling Smørgrav 
11508f76bb7dSCy Schubert /* Returns 1 if the limit has not been exceeded, 0 otherwise. */
11518f76bb7dSCy Schubert static int
check_ip_ratelimit(struct sockaddr_storage * addr,socklen_t addrlen,struct sldns_buffer * buffer,int premax,int max,int has_cookie)11528f76bb7dSCy Schubert check_ip_ratelimit(struct sockaddr_storage* addr, socklen_t addrlen,
11538f76bb7dSCy Schubert 	struct sldns_buffer* buffer, int premax, int max, int has_cookie)
11548f76bb7dSCy Schubert {
11558f76bb7dSCy Schubert 	int limit;
11568f76bb7dSCy Schubert 
11578f76bb7dSCy Schubert 	if(has_cookie) limit = infra_ip_ratelimit_cookie;
11588f76bb7dSCy Schubert 	else           limit = infra_ip_ratelimit;
11598f76bb7dSCy Schubert 
11608f76bb7dSCy Schubert 	/* Disabled */
11618f76bb7dSCy Schubert 	if(limit == 0) return 1;
11628f76bb7dSCy Schubert 
11638f76bb7dSCy Schubert 	if(premax <= limit && max > limit) {
11648f76bb7dSCy Schubert 		char client_ip[128], qnm[LDNS_MAX_DOMAINLEN+1+12+12];
11658f76bb7dSCy Schubert 		addr_to_str(addr, addrlen, client_ip, sizeof(client_ip));
11668f76bb7dSCy Schubert 		qnm[0]=0;
11678f76bb7dSCy Schubert 		if(sldns_buffer_limit(buffer)>LDNS_HEADER_SIZE &&
11688f76bb7dSCy Schubert 			LDNS_QDCOUNT(sldns_buffer_begin(buffer))!=0) {
11698f76bb7dSCy Schubert 			(void)sldns_wire2str_rrquestion_buf(
11708f76bb7dSCy Schubert 				sldns_buffer_at(buffer, LDNS_HEADER_SIZE),
11718f76bb7dSCy Schubert 				sldns_buffer_limit(buffer)-LDNS_HEADER_SIZE,
11728f76bb7dSCy Schubert 				qnm, sizeof(qnm));
11738f76bb7dSCy Schubert 			if(strlen(qnm)>0 && qnm[strlen(qnm)-1]=='\n')
11748f76bb7dSCy Schubert 				qnm[strlen(qnm)-1] = 0; /*remove newline*/
11758f76bb7dSCy Schubert 			if(strchr(qnm, '\t'))
11768f76bb7dSCy Schubert 				*strchr(qnm, '\t') = ' ';
11778f76bb7dSCy Schubert 			if(strchr(qnm, '\t'))
11788f76bb7dSCy Schubert 				*strchr(qnm, '\t') = ' ';
11798f76bb7dSCy Schubert 			verbose(VERB_OPS, "ip_ratelimit exceeded %s %d%s %s",
11808f76bb7dSCy Schubert 				client_ip, limit,
11818f76bb7dSCy Schubert 				has_cookie?"(cookie)":"", qnm);
11828f76bb7dSCy Schubert 		} else {
11838f76bb7dSCy Schubert 			verbose(VERB_OPS, "ip_ratelimit exceeded %s %d%s (no query name)",
11848f76bb7dSCy Schubert 				client_ip, limit,
11858f76bb7dSCy Schubert 				has_cookie?"(cookie)":"");
11868f76bb7dSCy Schubert 		}
11878f76bb7dSCy Schubert 	}
11888f76bb7dSCy Schubert 	return (max <= limit);
11898f76bb7dSCy Schubert }
11908f76bb7dSCy Schubert 
infra_ip_ratelimit_inc(struct infra_cache * infra,struct sockaddr_storage * addr,socklen_t addrlen,time_t timenow,int has_cookie,int backoff,struct sldns_buffer * buffer)11913005e0a3SDag-Erling Smørgrav int infra_ip_ratelimit_inc(struct infra_cache* infra,
1192865f46b2SCy Schubert 	struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow,
11938f76bb7dSCy Schubert 	int has_cookie, int backoff, struct sldns_buffer* buffer)
11943005e0a3SDag-Erling Smørgrav {
11953005e0a3SDag-Erling Smørgrav 	int max;
11963005e0a3SDag-Erling Smørgrav 	struct lruhash_entry* entry;
11973005e0a3SDag-Erling Smørgrav 
11983005e0a3SDag-Erling Smørgrav 	/* not enabled */
11993005e0a3SDag-Erling Smørgrav 	if(!infra_ip_ratelimit) {
12003005e0a3SDag-Erling Smørgrav 		return 1;
12013005e0a3SDag-Erling Smørgrav 	}
12023005e0a3SDag-Erling Smørgrav 	/* find or insert ratedata */
1203865f46b2SCy Schubert 	entry = infra_find_ip_ratedata(infra, addr, addrlen, 1);
12043005e0a3SDag-Erling Smørgrav 	if(entry) {
12059cf5bc93SCy Schubert 		int premax = infra_rate_max(entry->data, timenow, backoff);
12069cf5bc93SCy Schubert 		int* cur = infra_rate_give_second(entry->data, timenow);
12073005e0a3SDag-Erling Smørgrav 		(*cur)++;
12089cf5bc93SCy Schubert 		max = infra_rate_max(entry->data, timenow, backoff);
12093005e0a3SDag-Erling Smørgrav 		lock_rw_unlock(&entry->lock);
12108f76bb7dSCy Schubert 		return check_ip_ratelimit(addr, addrlen, buffer, premax, max,
12118f76bb7dSCy Schubert 			has_cookie);
12123005e0a3SDag-Erling Smørgrav 	}
12133005e0a3SDag-Erling Smørgrav 
12143005e0a3SDag-Erling Smørgrav 	/* create */
1215*335c7cdaSCy Schubert 	infra_ip_create_ratedata(infra, addr, addrlen, timenow, 0);
12163005e0a3SDag-Erling Smørgrav 	return 1;
12173005e0a3SDag-Erling Smørgrav }
1218*335c7cdaSCy Schubert 
infra_wait_limit_allowed(struct infra_cache * infra,struct comm_reply * rep,int cookie_valid,struct config_file * cfg)1219*335c7cdaSCy Schubert int infra_wait_limit_allowed(struct infra_cache* infra, struct comm_reply* rep,
1220*335c7cdaSCy Schubert 	int cookie_valid, struct config_file* cfg)
1221*335c7cdaSCy Schubert {
1222*335c7cdaSCy Schubert 	struct lruhash_entry* entry;
1223*335c7cdaSCy Schubert 	if(cfg->wait_limit == 0)
1224*335c7cdaSCy Schubert 		return 1;
1225*335c7cdaSCy Schubert 
1226*335c7cdaSCy Schubert 	entry = infra_find_ip_ratedata(infra, &rep->client_addr,
1227*335c7cdaSCy Schubert 		rep->client_addrlen, 0);
1228*335c7cdaSCy Schubert 	if(entry) {
1229*335c7cdaSCy Schubert 		rbtree_type* tree;
1230*335c7cdaSCy Schubert 		struct wait_limit_netblock_info* w;
1231*335c7cdaSCy Schubert 		struct rate_data* d = (struct rate_data*)entry->data;
1232*335c7cdaSCy Schubert 		int mesh_wait = d->mesh_wait;
1233*335c7cdaSCy Schubert 		lock_rw_unlock(&entry->lock);
1234*335c7cdaSCy Schubert 
1235*335c7cdaSCy Schubert 		/* have the wait amount, check how much is allowed */
1236*335c7cdaSCy Schubert 		if(cookie_valid)
1237*335c7cdaSCy Schubert 			tree = &infra->wait_limits_cookie_netblock;
1238*335c7cdaSCy Schubert 		else	tree = &infra->wait_limits_netblock;
1239*335c7cdaSCy Schubert 		w = (struct wait_limit_netblock_info*)addr_tree_lookup(tree,
1240*335c7cdaSCy Schubert 			&rep->client_addr, rep->client_addrlen);
1241*335c7cdaSCy Schubert 		if(w) {
1242*335c7cdaSCy Schubert 			if(w->limit != -1 && mesh_wait > w->limit)
1243*335c7cdaSCy Schubert 				return 0;
1244*335c7cdaSCy Schubert 		} else {
1245*335c7cdaSCy Schubert 			/* if there is no IP netblock specific information,
1246*335c7cdaSCy Schubert 			 * use the configured value. */
1247*335c7cdaSCy Schubert 			if(mesh_wait > (cookie_valid?cfg->wait_limit_cookie:
1248*335c7cdaSCy Schubert 				cfg->wait_limit))
1249*335c7cdaSCy Schubert 				return 0;
1250*335c7cdaSCy Schubert 		}
1251*335c7cdaSCy Schubert 	}
1252*335c7cdaSCy Schubert 	return 1;
1253*335c7cdaSCy Schubert }
1254*335c7cdaSCy Schubert 
infra_wait_limit_inc(struct infra_cache * infra,struct comm_reply * rep,time_t timenow,struct config_file * cfg)1255*335c7cdaSCy Schubert void infra_wait_limit_inc(struct infra_cache* infra, struct comm_reply* rep,
1256*335c7cdaSCy Schubert 	time_t timenow, struct config_file* cfg)
1257*335c7cdaSCy Schubert {
1258*335c7cdaSCy Schubert 	struct lruhash_entry* entry;
1259*335c7cdaSCy Schubert 	if(cfg->wait_limit == 0)
1260*335c7cdaSCy Schubert 		return;
1261*335c7cdaSCy Schubert 
1262*335c7cdaSCy Schubert 	/* Find it */
1263*335c7cdaSCy Schubert 	entry = infra_find_ip_ratedata(infra, &rep->client_addr,
1264*335c7cdaSCy Schubert 		rep->client_addrlen, 1);
1265*335c7cdaSCy Schubert 	if(entry) {
1266*335c7cdaSCy Schubert 		struct rate_data* d = (struct rate_data*)entry->data;
1267*335c7cdaSCy Schubert 		d->mesh_wait++;
1268*335c7cdaSCy Schubert 		lock_rw_unlock(&entry->lock);
1269*335c7cdaSCy Schubert 		return;
1270*335c7cdaSCy Schubert 	}
1271*335c7cdaSCy Schubert 
1272*335c7cdaSCy Schubert 	/* Create it */
1273*335c7cdaSCy Schubert 	infra_ip_create_ratedata(infra, &rep->client_addr,
1274*335c7cdaSCy Schubert 		rep->client_addrlen, timenow, 1);
1275*335c7cdaSCy Schubert }
1276*335c7cdaSCy Schubert 
infra_wait_limit_dec(struct infra_cache * infra,struct comm_reply * rep,struct config_file * cfg)1277*335c7cdaSCy Schubert void infra_wait_limit_dec(struct infra_cache* infra, struct comm_reply* rep,
1278*335c7cdaSCy Schubert 	struct config_file* cfg)
1279*335c7cdaSCy Schubert {
1280*335c7cdaSCy Schubert 	struct lruhash_entry* entry;
1281*335c7cdaSCy Schubert 	if(cfg->wait_limit == 0)
1282*335c7cdaSCy Schubert 		return;
1283*335c7cdaSCy Schubert 
1284*335c7cdaSCy Schubert 	entry = infra_find_ip_ratedata(infra, &rep->client_addr,
1285*335c7cdaSCy Schubert 		rep->client_addrlen, 1);
1286*335c7cdaSCy Schubert 	if(entry) {
1287*335c7cdaSCy Schubert 		struct rate_data* d = (struct rate_data*)entry->data;
1288*335c7cdaSCy Schubert 		if(d->mesh_wait > 0)
1289*335c7cdaSCy Schubert 			d->mesh_wait--;
1290*335c7cdaSCy Schubert 		lock_rw_unlock(&entry->lock);
1291*335c7cdaSCy Schubert 	}
1292*335c7cdaSCy Schubert }
1293