2 * services/cache/infra.c - infrastructure cache, server rtt and capabilities
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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.
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.
39 * This file contains the infrastructure cache.
42 #include "sldns/rrdef.h"
43 #include "sldns/str2wire.h"
44 #include "services/cache/infra.h"
45 #include "util/storage/slabhash.h"
46 #include "util/storage/lookup3.h"
47 #include "util/data/dname.h"
49 #include "util/net_help.h"
50 #include "util/config_file.h"
51 #include "iterator/iterator.h"
53 /** Timeout when only a single probe query per IP is allowed. */
54 #define PROBE_MAXRTO 12000 /* in msec */
56 /** number of timeouts for a type when the domain can be blocked ;
57 * even if another type has completely rtt maxed it, the different type
58 * can do this number of packets (until those all timeout too) */
59 #define TIMEOUT_COUNT_MAX 3
61 /** ratelimit value for delegation point */
62 int infra_dp_ratelimit = 0;
64 /** ratelimit value for client ip addresses,
65 * in queries per second. */
66 int infra_ip_ratelimit = 0;
69 infra_sizefunc(void* k, void* ATTR_UNUSED(d))
71 struct infra_key* key = (struct infra_key*)k;
72 return sizeof(*key) + sizeof(struct infra_data) + key->namelen
73 + lock_get_mem(&key->entry.lock);
77 infra_compfunc(void* key1, void* key2)
79 struct infra_key* k1 = (struct infra_key*)key1;
80 struct infra_key* k2 = (struct infra_key*)key2;
81 int r = sockaddr_cmp(&k1->addr, k1->addrlen, &k2->addr, k2->addrlen);
84 if(k1->namelen != k2->namelen) {
85 if(k1->namelen < k2->namelen)
89 return query_dname_compare(k1->zonename, k2->zonename);
93 infra_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
95 struct infra_key* key = (struct infra_key*)k;
98 lock_rw_destroy(&key->entry.lock);
104 infra_deldatafunc(void* d, void* ATTR_UNUSED(arg))
106 struct infra_data* data = (struct infra_data*)d;
111 rate_sizefunc(void* k, void* ATTR_UNUSED(d))
113 struct rate_key* key = (struct rate_key*)k;
114 return sizeof(*key) + sizeof(struct rate_data) + key->namelen
115 + lock_get_mem(&key->entry.lock);
119 rate_compfunc(void* key1, void* key2)
121 struct rate_key* k1 = (struct rate_key*)key1;
122 struct rate_key* k2 = (struct rate_key*)key2;
123 if(k1->namelen != k2->namelen) {
124 if(k1->namelen < k2->namelen)
128 return query_dname_compare(k1->name, k2->name);
132 rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
134 struct rate_key* key = (struct rate_key*)k;
137 lock_rw_destroy(&key->entry.lock);
143 rate_deldatafunc(void* d, void* ATTR_UNUSED(arg))
145 struct rate_data* data = (struct rate_data*)d;
149 /** find or create element in domainlimit tree */
150 static struct domain_limit_data* domain_limit_findcreate(
151 struct infra_cache* infra, char* name)
156 struct domain_limit_data* d;
159 nm = sldns_str2wire_dname(name, &nmlen);
161 log_err("could not parse %s", name);
164 labs = dname_count_labels(nm);
166 /* can we find it? */
167 d = (struct domain_limit_data*)name_tree_find(&infra->domain_limits,
168 nm, nmlen, labs, LDNS_RR_CLASS_IN);
175 d = (struct domain_limit_data*)calloc(1, sizeof(*d));
180 d->node.node.key = &d->node;
184 d->node.dclass = LDNS_RR_CLASS_IN;
187 if(!name_tree_insert(&infra->domain_limits, &d->node, nm, nmlen,
188 labs, LDNS_RR_CLASS_IN)) {
189 log_err("duplicate element in domainlimit tree");
197 /** insert rate limit configuration into lookup tree */
198 static int infra_ratelimit_cfg_insert(struct infra_cache* infra,
199 struct config_file* cfg)
201 struct config_str2list* p;
202 struct domain_limit_data* d;
203 for(p = cfg->ratelimit_for_domain; p; p = p->next) {
204 d = domain_limit_findcreate(infra, p->str);
207 d->lim = atoi(p->str2);
209 for(p = cfg->ratelimit_below_domain; p; p = p->next) {
210 d = domain_limit_findcreate(infra, p->str);
213 d->below = atoi(p->str2);
219 infra_create(struct config_file* cfg)
221 struct infra_cache* infra = (struct infra_cache*)calloc(1,
222 sizeof(struct infra_cache));
223 size_t maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+
224 sizeof(struct infra_data)+INFRA_BYTES_NAME);
225 infra->hosts = slabhash_create(cfg->infra_cache_slabs,
226 INFRA_HOST_STARTSIZE, maxmem, &infra_sizefunc, &infra_compfunc,
227 &infra_delkeyfunc, &infra_deldatafunc, NULL);
232 infra->host_ttl = cfg->host_ttl;
233 name_tree_init(&infra->domain_limits);
234 infra_dp_ratelimit = cfg->ratelimit;
235 if(cfg->ratelimit != 0) {
236 infra->domain_rates = slabhash_create(cfg->ratelimit_slabs,
237 INFRA_HOST_STARTSIZE, cfg->ratelimit_size,
238 &rate_sizefunc, &rate_compfunc, &rate_delkeyfunc,
239 &rate_deldatafunc, NULL);
240 if(!infra->domain_rates) {
244 /* insert config data into ratelimits */
245 if(!infra_ratelimit_cfg_insert(infra, cfg)) {
249 name_tree_init_parents(&infra->domain_limits);
251 infra_ip_ratelimit = cfg->ip_ratelimit;
252 infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs,
253 INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc,
254 &ip_rate_compfunc, &ip_rate_delkeyfunc, &ip_rate_deldatafunc, NULL);
255 if(!infra->client_ip_rates) {
262 /** delete domain_limit entries */
263 static void domain_limit_free(rbnode_type* n, void* ATTR_UNUSED(arg))
266 free(((struct domain_limit_data*)n)->node.name);
272 infra_delete(struct infra_cache* infra)
276 slabhash_delete(infra->hosts);
277 slabhash_delete(infra->domain_rates);
278 traverse_postorder(&infra->domain_limits, domain_limit_free, NULL);
279 slabhash_delete(infra->client_ip_rates);
284 infra_adjust(struct infra_cache* infra, struct config_file* cfg)
288 return infra_create(cfg);
289 infra->host_ttl = cfg->host_ttl;
290 maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+
291 sizeof(struct infra_data)+INFRA_BYTES_NAME);
292 if(maxmem != slabhash_get_size(infra->hosts) ||
293 cfg->infra_cache_slabs != infra->hosts->size) {
295 infra = infra_create(cfg);
300 /** calculate the hash value for a host key
301 * set use_port to a non-0 number to use the port in
302 * the hash calculation; 0 to ignore the port.*/
303 static hashvalue_type
304 hash_addr(struct sockaddr_storage* addr, socklen_t addrlen,
307 hashvalue_type h = 0xab;
308 /* select the pieces to hash, some OS have changing data inside */
309 if(addr_is_ip6(addr, addrlen)) {
310 struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr;
311 h = hashlittle(&in6->sin6_family, sizeof(in6->sin6_family), h);
313 h = hashlittle(&in6->sin6_port, sizeof(in6->sin6_port), h);
315 h = hashlittle(&in6->sin6_addr, INET6_SIZE, h);
317 struct sockaddr_in* in = (struct sockaddr_in*)addr;
318 h = hashlittle(&in->sin_family, sizeof(in->sin_family), h);
320 h = hashlittle(&in->sin_port, sizeof(in->sin_port), h);
322 h = hashlittle(&in->sin_addr, INET_SIZE, h);
327 /** calculate infra hash for a key */
328 static hashvalue_type
329 hash_infra(struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name)
331 return dname_query_hash(name, hash_addr(addr, addrlen, 1));
334 /** lookup version that does not check host ttl (you check it) */
335 struct lruhash_entry*
336 infra_lookup_nottl(struct infra_cache* infra, struct sockaddr_storage* addr,
337 socklen_t addrlen, uint8_t* name, size_t namelen, int wr)
341 memcpy(&k.addr, addr, addrlen);
344 k.entry.hash = hash_infra(addr, addrlen, name);
345 k.entry.key = (void*)&k;
347 return slabhash_lookup(infra->hosts, k.entry.hash, &k, wr);
350 /** init the data elements */
352 data_entry_init(struct infra_cache* infra, struct lruhash_entry* e,
355 struct infra_data* data = (struct infra_data*)e->data;
356 data->ttl = timenow + infra->host_ttl;
357 rtt_init(&data->rtt);
358 data->edns_version = 0;
359 data->edns_lame_known = 0;
360 data->probedelay = 0;
361 data->isdnsseclame = 0;
363 data->lame_type_A = 0;
364 data->lame_other = 0;
366 data->timeout_AAAA = 0;
367 data->timeout_other = 0;
371 * Create and init a new entry for a host
372 * @param infra: infra structure with config parameters.
373 * @param addr: host address.
374 * @param addrlen: length of addr.
375 * @param name: name of zone
376 * @param namelen: length of name.
377 * @param tm: time now.
378 * @return: the new entry or NULL on malloc failure.
380 static struct lruhash_entry*
381 new_entry(struct infra_cache* infra, struct sockaddr_storage* addr,
382 socklen_t addrlen, uint8_t* name, size_t namelen, time_t tm)
384 struct infra_data* data;
385 struct infra_key* key = (struct infra_key*)malloc(sizeof(*key));
388 data = (struct infra_data*)malloc(sizeof(struct infra_data));
393 key->zonename = memdup(name, namelen);
399 key->namelen = namelen;
400 lock_rw_init(&key->entry.lock);
401 key->entry.hash = hash_infra(addr, addrlen, name);
402 key->entry.key = (void*)key;
403 key->entry.data = (void*)data;
404 key->addrlen = addrlen;
405 memcpy(&key->addr, addr, addrlen);
406 data_entry_init(infra, &key->entry, tm);
411 infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
412 socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow,
413 int* edns_vs, uint8_t* edns_lame_known, int* to)
415 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
417 struct infra_data* data;
419 if(e && ((struct infra_data*)e->data)->ttl < timenow) {
420 /* it expired, try to reuse existing entry */
421 int old = ((struct infra_data*)e->data)->rtt.rto;
422 uint8_t tA = ((struct infra_data*)e->data)->timeout_A;
423 uint8_t tAAAA = ((struct infra_data*)e->data)->timeout_AAAA;
424 uint8_t tother = ((struct infra_data*)e->data)->timeout_other;
425 lock_rw_unlock(&e->lock);
426 e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1);
428 /* if its still there we have a writelock, init */
430 /* do not touch lameness, it may be valid still */
431 data_entry_init(infra, e, timenow);
433 /* TOP_TIMEOUT remains on reuse */
434 if(old >= USEFUL_SERVER_TOP_TIMEOUT) {
435 ((struct infra_data*)e->data)->rtt.rto
436 = USEFUL_SERVER_TOP_TIMEOUT;
437 ((struct infra_data*)e->data)->timeout_A = tA;
438 ((struct infra_data*)e->data)->timeout_AAAA = tAAAA;
439 ((struct infra_data*)e->data)->timeout_other = tother;
444 /* insert new entry */
445 if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow)))
447 data = (struct infra_data*)e->data;
448 *edns_vs = data->edns_version;
449 *edns_lame_known = data->edns_lame_known;
450 *to = rtt_timeout(&data->rtt);
451 slabhash_insert(infra->hosts, e->hash, e, data, NULL);
454 /* use existing entry */
455 data = (struct infra_data*)e->data;
456 *edns_vs = data->edns_version;
457 *edns_lame_known = data->edns_lame_known;
458 *to = rtt_timeout(&data->rtt);
459 if(*to >= PROBE_MAXRTO && rtt_notimeout(&data->rtt)*4 <= *to) {
460 /* delay other queries, this is the probe query */
462 lock_rw_unlock(&e->lock);
463 e = infra_lookup_nottl(infra, addr,addrlen,nm,nmlen, 1);
464 if(!e) { /* flushed from cache real fast, no use to
465 allocate just for the probedelay */
468 data = (struct infra_data*)e->data;
470 /* add 999 to round up the timeout value from msec to sec,
471 * then add a whole second so it is certain that this probe
472 * has timed out before the next is allowed */
473 data->probedelay = timenow + ((*to)+1999)/1000;
475 lock_rw_unlock(&e->lock);
480 infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr,
481 socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow,
482 int dnsseclame, int reclame, uint16_t qtype)
484 struct infra_data* data;
485 struct lruhash_entry* e;
486 int needtoinsert = 0;
487 e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1);
490 if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) {
491 log_err("set_lame: malloc failure");
495 } else if( ((struct infra_data*)e->data)->ttl < timenow) {
496 /* expired, reuse existing entry */
497 data_entry_init(infra, e, timenow);
499 /* got an entry, now set the zone lame */
500 data = (struct infra_data*)e->data;
501 /* merge data (if any) */
503 data->isdnsseclame = 1;
506 if(!dnsseclame && !reclame && qtype == LDNS_RR_TYPE_A)
507 data->lame_type_A = 1;
508 if(!dnsseclame && !reclame && qtype != LDNS_RR_TYPE_A)
509 data->lame_other = 1;
512 slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
513 else { lock_rw_unlock(&e->lock); }
518 infra_update_tcp_works(struct infra_cache* infra,
519 struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm,
522 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
524 struct infra_data* data;
526 return; /* doesn't exist */
527 data = (struct infra_data*)e->data;
528 if(data->rtt.rto >= RTT_MAX_TIMEOUT)
529 /* do not disqualify this server altogether, it is better
531 data->rtt.rto = RTT_MAX_TIMEOUT-1000;
532 lock_rw_unlock(&e->lock);
536 infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr,
537 socklen_t addrlen, uint8_t* nm, size_t nmlen, int qtype,
538 int roundtrip, int orig_rtt, time_t timenow)
540 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
542 struct infra_data* data;
543 int needtoinsert = 0;
546 if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow)))
549 } else if(((struct infra_data*)e->data)->ttl < timenow) {
550 data_entry_init(infra, e, timenow);
552 /* have an entry, update the rtt */
553 data = (struct infra_data*)e->data;
554 if(roundtrip == -1) {
555 rtt_lost(&data->rtt, orig_rtt);
556 if(qtype == LDNS_RR_TYPE_A) {
557 if(data->timeout_A < TIMEOUT_COUNT_MAX)
559 } else if(qtype == LDNS_RR_TYPE_AAAA) {
560 if(data->timeout_AAAA < TIMEOUT_COUNT_MAX)
561 data->timeout_AAAA++;
563 if(data->timeout_other < TIMEOUT_COUNT_MAX)
564 data->timeout_other++;
567 /* if we got a reply, but the old timeout was above server
568 * selection height, delete the timeout so the server is
569 * fully available again */
570 if(rtt_unclamped(&data->rtt) >= USEFUL_SERVER_TOP_TIMEOUT)
571 rtt_init(&data->rtt);
572 rtt_update(&data->rtt, roundtrip);
573 data->probedelay = 0;
574 if(qtype == LDNS_RR_TYPE_A)
576 else if(qtype == LDNS_RR_TYPE_AAAA)
577 data->timeout_AAAA = 0;
578 else data->timeout_other = 0;
580 if(data->rtt.rto > 0)
584 slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
585 else { lock_rw_unlock(&e->lock); }
589 long long infra_get_host_rto(struct infra_cache* infra,
590 struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm,
591 size_t nmlen, struct rtt_info* rtt, int* delay, time_t timenow,
592 int* tA, int* tAAAA, int* tother)
594 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
596 struct infra_data* data;
599 data = (struct infra_data*)e->data;
600 if(data->ttl >= timenow) {
601 ttl = (long long)(data->ttl - timenow);
602 memmove(rtt, &data->rtt, sizeof(*rtt));
603 if(timenow < data->probedelay)
604 *delay = (int)(data->probedelay - timenow);
607 *tA = (int)data->timeout_A;
608 *tAAAA = (int)data->timeout_AAAA;
609 *tother = (int)data->timeout_other;
610 lock_rw_unlock(&e->lock);
615 infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr,
616 socklen_t addrlen, uint8_t* nm, size_t nmlen, int edns_version,
619 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
621 struct infra_data* data;
622 int needtoinsert = 0;
624 if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow)))
627 } else if(((struct infra_data*)e->data)->ttl < timenow) {
628 data_entry_init(infra, e, timenow);
630 /* have an entry, update the rtt, and the ttl */
631 data = (struct infra_data*)e->data;
632 /* do not update if noEDNS and stored is yesEDNS */
633 if(!(edns_version == -1 && (data->edns_version != -1 &&
634 data->edns_lame_known))) {
635 data->edns_version = edns_version;
636 data->edns_lame_known = 1;
640 slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
641 else { lock_rw_unlock(&e->lock); }
646 infra_get_lame_rtt(struct infra_cache* infra,
647 struct sockaddr_storage* addr, socklen_t addrlen,
648 uint8_t* name, size_t namelen, uint16_t qtype,
649 int* lame, int* dnsseclame, int* reclame, int* rtt, time_t timenow)
651 struct infra_data* host;
652 struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
656 host = (struct infra_data*)e->data;
657 *rtt = rtt_unclamped(&host->rtt);
658 if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay
659 && rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) {
660 /* single probe for this domain, and we are not probing */
661 /* unless the query type allows a probe to happen */
662 if(qtype == LDNS_RR_TYPE_A) {
663 if(host->timeout_A >= TIMEOUT_COUNT_MAX)
664 *rtt = USEFUL_SERVER_TOP_TIMEOUT;
665 else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
666 } else if(qtype == LDNS_RR_TYPE_AAAA) {
667 if(host->timeout_AAAA >= TIMEOUT_COUNT_MAX)
668 *rtt = USEFUL_SERVER_TOP_TIMEOUT;
669 else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
671 if(host->timeout_other >= TIMEOUT_COUNT_MAX)
672 *rtt = USEFUL_SERVER_TOP_TIMEOUT;
673 else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
676 if(timenow > host->ttl) {
678 /* see if this can be a re-probe of an unresponsive server */
679 /* minus 1000 because that is outside of the RTTBAND, so
680 * blacklisted servers stay blacklisted if this is chosen */
681 if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
682 lock_rw_unlock(&e->lock);
683 *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
689 lock_rw_unlock(&e->lock);
692 /* check lameness first */
693 if(host->lame_type_A && qtype == LDNS_RR_TYPE_A) {
694 lock_rw_unlock(&e->lock);
699 } else if(host->lame_other && qtype != LDNS_RR_TYPE_A) {
700 lock_rw_unlock(&e->lock);
705 } else if(host->isdnsseclame) {
706 lock_rw_unlock(&e->lock);
711 } else if(host->rec_lame) {
712 lock_rw_unlock(&e->lock);
718 /* no lameness for this type of query */
719 lock_rw_unlock(&e->lock);
726 int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
729 int labs = dname_count_labels(name);
730 struct domain_limit_data* d = (struct domain_limit_data*)
731 name_tree_lookup(&infra->domain_limits, name, namelen, labs,
733 if(!d) return infra_dp_ratelimit;
735 if(d->node.labs == labs && d->lim != -1)
736 return d->lim; /* exact match */
738 /* find 'below match' */
739 if(d->node.labs == labs)
740 d = (struct domain_limit_data*)d->node.parent;
744 d = (struct domain_limit_data*)d->node.parent;
746 return infra_dp_ratelimit;
749 size_t ip_rate_sizefunc(void* k, void* ATTR_UNUSED(d))
751 struct ip_rate_key* key = (struct ip_rate_key*)k;
752 return sizeof(*key) + sizeof(struct ip_rate_data)
753 + lock_get_mem(&key->entry.lock);
756 int ip_rate_compfunc(void* key1, void* key2)
758 struct ip_rate_key* k1 = (struct ip_rate_key*)key1;
759 struct ip_rate_key* k2 = (struct ip_rate_key*)key2;
760 return sockaddr_cmp_addr(&k1->addr, k1->addrlen,
761 &k2->addr, k2->addrlen);
764 void ip_rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
766 struct ip_rate_key* key = (struct ip_rate_key*)k;
769 lock_rw_destroy(&key->entry.lock);
773 /** find data item in array, for write access, caller unlocks */
774 static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra,
775 uint8_t* name, size_t namelen, int wr)
778 hashvalue_type h = dname_query_hash(name, 0xab);
779 memset(&key, 0, sizeof(key));
781 key.namelen = namelen;
783 return slabhash_lookup(infra->domain_rates, h, &key, wr);
786 /** find data item in array for ip addresses */
787 static struct lruhash_entry* infra_find_ip_ratedata(struct infra_cache* infra,
788 struct comm_reply* repinfo, int wr)
790 struct ip_rate_key key;
791 hashvalue_type h = hash_addr(&(repinfo->addr),
792 repinfo->addrlen, 0);
793 memset(&key, 0, sizeof(key));
794 key.addr = repinfo->addr;
795 key.addrlen = repinfo->addrlen;
797 return slabhash_lookup(infra->client_ip_rates, h, &key, wr);
800 /** create rate data item for name, number 1 in now */
801 static void infra_create_ratedata(struct infra_cache* infra,
802 uint8_t* name, size_t namelen, time_t timenow)
804 hashvalue_type h = dname_query_hash(name, 0xab);
805 struct rate_key* k = (struct rate_key*)calloc(1, sizeof(*k));
806 struct rate_data* d = (struct rate_data*)calloc(1, sizeof(*d));
810 return; /* alloc failure */
812 k->namelen = namelen;
813 k->name = memdup(name, namelen);
817 return; /* alloc failure */
819 lock_rw_init(&k->entry.lock);
824 d->timestamp[0] = timenow;
825 slabhash_insert(infra->domain_rates, h, &k->entry, d, NULL);
828 /** create rate data item for ip address */
829 static void infra_ip_create_ratedata(struct infra_cache* infra,
830 struct comm_reply* repinfo, time_t timenow)
832 hashvalue_type h = hash_addr(&(repinfo->addr),
833 repinfo->addrlen, 0);
834 struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k));
835 struct ip_rate_data* d = (struct ip_rate_data*)calloc(1, sizeof(*d));
839 return; /* alloc failure */
841 k->addr = repinfo->addr;
842 k->addrlen = repinfo->addrlen;
843 lock_rw_init(&k->entry.lock);
848 d->timestamp[0] = timenow;
849 slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL);
852 /** find the second and return its rate counter, if none, remove oldest */
853 static int* infra_rate_find_second(void* data, time_t t)
855 struct rate_data* d = (struct rate_data*)data;
857 for(i=0; i<RATE_WINDOW; i++) {
858 if(d->timestamp[i] == t)
861 /* remove oldest timestamp, and insert it at t with 0 qps */
863 for(i=0; i<RATE_WINDOW; i++) {
864 if(d->timestamp[i] < d->timestamp[oldest])
867 d->timestamp[oldest] = t;
869 return &(d->qps[oldest]);
872 int infra_rate_max(void* data, time_t now)
874 struct rate_data* d = (struct rate_data*)data;
876 for(i=0; i<RATE_WINDOW; i++) {
877 if(now-d->timestamp[i] <= RATE_WINDOW) {
885 int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
886 size_t namelen, time_t timenow)
889 struct lruhash_entry* entry;
891 if(!infra_dp_ratelimit)
892 return 1; /* not enabled */
895 lim = infra_find_ratelimit(infra, name, namelen);
897 return 1; /* disabled for this domain */
899 /* find or insert ratedata */
900 entry = infra_find_ratedata(infra, name, namelen, 1);
902 int premax = infra_rate_max(entry->data, timenow);
903 int* cur = infra_rate_find_second(entry->data, timenow);
905 max = infra_rate_max(entry->data, timenow);
906 lock_rw_unlock(&entry->lock);
908 if(premax < lim && max >= lim) {
910 dname_str(name, buf);
911 verbose(VERB_OPS, "ratelimit exceeded %s %d", buf, lim);
917 infra_create_ratedata(infra, name, namelen, timenow);
921 void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name,
922 size_t namelen, time_t timenow)
924 struct lruhash_entry* entry;
926 if(!infra_dp_ratelimit)
927 return; /* not enabled */
928 entry = infra_find_ratedata(infra, name, namelen, 1);
929 if(!entry) return; /* not cached */
930 cur = infra_rate_find_second(entry->data, timenow);
933 lock_rw_unlock(&entry->lock);
936 int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name,
937 size_t namelen, time_t timenow)
939 struct lruhash_entry* entry;
941 if(!infra_dp_ratelimit)
942 return 0; /* not enabled */
945 lim = infra_find_ratelimit(infra, name, namelen);
947 return 0; /* disabled for this domain */
949 /* find current rate */
950 entry = infra_find_ratedata(infra, name, namelen, 0);
952 return 0; /* not cached */
953 max = infra_rate_max(entry->data, timenow);
954 lock_rw_unlock(&entry->lock);
960 infra_get_mem(struct infra_cache* infra)
962 size_t s = sizeof(*infra) + slabhash_get_mem(infra->hosts);
963 if(infra->domain_rates) s += slabhash_get_mem(infra->domain_rates);
964 if(infra->client_ip_rates) s += slabhash_get_mem(infra->client_ip_rates);
965 /* ignore domain_limits because walk through tree is big */
969 int infra_ip_ratelimit_inc(struct infra_cache* infra,
970 struct comm_reply* repinfo, time_t timenow)
973 struct lruhash_entry* entry;
976 if(!infra_ip_ratelimit) {
979 /* find or insert ratedata */
980 entry = infra_find_ip_ratedata(infra, repinfo, 1);
982 int premax = infra_rate_max(entry->data, timenow);
983 int* cur = infra_rate_find_second(entry->data, timenow);
985 max = infra_rate_max(entry->data, timenow);
986 lock_rw_unlock(&entry->lock);
988 if(premax < infra_ip_ratelimit && max >= infra_ip_ratelimit) {
990 addr_to_str((struct sockaddr_storage *)&repinfo->addr,
991 repinfo->addrlen, client_ip, sizeof(client_ip));
992 verbose(VERB_OPS, "ratelimit exceeded %s %d", client_ip,
995 return (max <= infra_ip_ratelimit);
999 infra_ip_create_ratedata(infra, repinfo, timenow);