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