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