xref: /freebsd/contrib/unbound/services/cache/infra.c (revision be771a7b7f4580a30d99e41a5bb1b93a385a119d)
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