mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
- Fix #1185: Source IP rate limiting, patch from Larissa Feng.
git-svn-id: file:///svn/unbound/trunk@3981 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
9b4b0de746
commit
3a1ffe4c69
20 changed files with 2818 additions and 2338 deletions
|
|
@ -762,6 +762,8 @@ print_stats(SSL* ssl, const char* nm, struct stats_info* s)
|
|||
struct timeval avg;
|
||||
if(!ssl_printf(ssl, "%s.num.queries"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.num_queries)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.queries_ip_ratelimited"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.num_queries_ip_ratelimited)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%lu\n", nm,
|
||||
(unsigned long)(s->svr.num_queries
|
||||
- s->svr.num_queries_missed_cache))) return 0;
|
||||
|
|
@ -2559,6 +2561,8 @@ struct ratelimit_list_arg {
|
|||
time_t now;
|
||||
};
|
||||
|
||||
#define ip_ratelimit_list_arg ratelimit_list_arg
|
||||
|
||||
/** list items in the ratelimit table */
|
||||
static void
|
||||
rate_list(struct lruhash_entry* e, void* arg)
|
||||
|
|
@ -2577,6 +2581,24 @@ rate_list(struct lruhash_entry* e, void* arg)
|
|||
ssl_printf(a->ssl, "%s %d limit %d\n", buf, max, lim);
|
||||
}
|
||||
|
||||
/** list items in the ip_ratelimit table */
|
||||
static void
|
||||
ip_rate_list(struct lruhash_entry* e, void* arg)
|
||||
{
|
||||
char ip[128];
|
||||
struct ip_ratelimit_list_arg* a = (struct ip_ratelimit_list_arg*)arg;
|
||||
struct ip_rate_key* k = (struct ip_rate_key*)e->key;
|
||||
struct ip_rate_data* d = (struct ip_rate_data*)e->data;
|
||||
int lim = infra_ip_ratelimit;
|
||||
int max = infra_rate_max(d, a->now);
|
||||
if(a->all == 0) {
|
||||
if(max < lim)
|
||||
return;
|
||||
}
|
||||
addr_to_str(&k->addr, k->addrlen, ip, sizeof(ip));
|
||||
ssl_printf(a->ssl, "%s %d limit %d\n", ip, max, lim);
|
||||
}
|
||||
|
||||
/** do the ratelimit_list command */
|
||||
static void
|
||||
do_ratelimit_list(SSL* ssl, struct worker* worker, char* arg)
|
||||
|
|
@ -2595,6 +2617,24 @@ do_ratelimit_list(SSL* ssl, struct worker* worker, char* arg)
|
|||
slabhash_traverse(a.infra->domain_rates, 0, rate_list, &a);
|
||||
}
|
||||
|
||||
/** do the ip_ratelimit_list command */
|
||||
static void
|
||||
do_ip_ratelimit_list(SSL* ssl, struct worker* worker, char* arg)
|
||||
{
|
||||
struct ip_ratelimit_list_arg a;
|
||||
a.all = 0;
|
||||
a.infra = worker->env.infra_cache;
|
||||
a.now = *worker->env.now;
|
||||
a.ssl = ssl;
|
||||
arg = skipwhite(arg);
|
||||
if(strcmp(arg, "+a") == 0)
|
||||
a.all = 1;
|
||||
if(a.infra->client_ip_rates==NULL ||
|
||||
(a.all == 0 && infra_ip_ratelimit == 0))
|
||||
return;
|
||||
slabhash_traverse(a.infra->client_ip_rates, 0, ip_rate_list, &a);
|
||||
}
|
||||
|
||||
/** tell other processes to execute the command */
|
||||
static void
|
||||
distribute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd)
|
||||
|
|
@ -2673,6 +2713,9 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd,
|
|||
} else if(cmdcmp(p, "ratelimit_list", 14)) {
|
||||
do_ratelimit_list(ssl, worker, p+14);
|
||||
return;
|
||||
} else if(cmdcmp(p, "ip_ratelimit_list", 17)) {
|
||||
do_ip_ratelimit_list(ssl, worker, p+17);
|
||||
return;
|
||||
} else if(cmdcmp(p, "stub_add", 8)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
|
|
|
|||
|
|
@ -102,12 +102,14 @@ void server_stats_log(struct server_stats* stats, struct worker* worker,
|
|||
int threadnum)
|
||||
{
|
||||
log_info("server stats for thread %d: %u queries, "
|
||||
"%u answers from cache, %u recursions, %u prefetch",
|
||||
"%u answers from cache, %u recursions, %u prefetch, %u rejected by "
|
||||
"ip ratelimiting",
|
||||
threadnum, (unsigned)stats->num_queries,
|
||||
(unsigned)(stats->num_queries -
|
||||
stats->num_queries_missed_cache),
|
||||
(unsigned)stats->num_queries_missed_cache,
|
||||
(unsigned)stats->num_queries_prefetch);
|
||||
(unsigned)stats->num_queries_prefetch,
|
||||
(unsigned)stats->num_queries_ip_ratelimited);
|
||||
log_info("server stats for thread %d: requestlist max %u avg %g "
|
||||
"exceeded %u jostled %u", threadnum,
|
||||
(unsigned)stats->max_query_list_size,
|
||||
|
|
@ -226,6 +228,7 @@ void server_stats_reply(struct worker* worker, int reset)
|
|||
void server_stats_add(struct stats_info* total, struct stats_info* a)
|
||||
{
|
||||
total->svr.num_queries += a->svr.num_queries;
|
||||
total->svr.num_queries_ip_ratelimited += a->svr.num_queries_ip_ratelimited;
|
||||
total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
|
||||
total->svr.num_queries_prefetch += a->svr.num_queries_prefetch;
|
||||
total->svr.sum_query_list_size += a->svr.sum_query_list_size;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ struct sldns_buffer;
|
|||
struct server_stats {
|
||||
/** number of queries from clients received. */
|
||||
size_t num_queries;
|
||||
/** number of queries that have been dropped/ratelimited by ip. */
|
||||
size_t num_queries_ip_ratelimited;
|
||||
/** number of queries that had a cache-miss. */
|
||||
size_t num_queries_missed_cache;
|
||||
/** number of prefetch queries - cachehits with prefetch */
|
||||
|
|
|
|||
|
|
@ -825,7 +825,29 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
worker->stats.num_queries++;
|
||||
|
||||
/* check if this query should be dropped based on source ip rate limiting */
|
||||
if(!infra_ip_ratelimit_inc(worker->env.infra_cache, repinfo,
|
||||
*worker->env.now)) {
|
||||
/* See if we are passed through with slip factor */
|
||||
if(worker->env.cfg->ip_ratelimit_factor != 0 &&
|
||||
ub_random_max(worker->env.rnd,
|
||||
worker->env.cfg->ip_ratelimit_factor) == 1) {
|
||||
|
||||
char addrbuf[128];
|
||||
addr_to_str(&repinfo->addr, repinfo->addrlen,
|
||||
addrbuf, sizeof(addrbuf));
|
||||
verbose(VERB_OPS, "ip_ratelimit allowed through for ip address %s ",
|
||||
addrbuf);
|
||||
} else {
|
||||
worker->stats.num_queries_ip_ratelimited++;
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* see if query is in the cache */
|
||||
if(!query_info_parse(&qinfo, c->buffer)) {
|
||||
verbose(VERB_ALGO, "worker parse request: formerror.");
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
- Fix #1184: Log DNS replies. This includes the same logging
|
||||
information that DNS queries and response code and response size,
|
||||
patch from Larissa Feng.
|
||||
- Fix #1185: Source IP rate limiting, patch from Larissa Feng.
|
||||
|
||||
3 January 2017: Wouter
|
||||
- configure --enable-systemd and lets unbound use systemd sockets if
|
||||
|
|
|
|||
|
|
@ -674,6 +674,20 @@ server:
|
|||
# can give this multiple times, the name closest to the zone is used.
|
||||
# ratelimit-below-domain: com 1000
|
||||
|
||||
# global query ratelimit for all ip addresses.
|
||||
# feature is experimental.
|
||||
# if 0(default) it is disabled, otherwise states qps allowed per ip address
|
||||
# ip-ratelimit: 0
|
||||
|
||||
# ip ratelimits are tracked in a cache, size in bytes of cache (or k,m).
|
||||
# ip-ratelimit-size: 4m
|
||||
# ip ratelimit cache slabs, reduces lock contention if equal to cpucount.
|
||||
# ip-ratelimit-slabs: 4
|
||||
|
||||
# 0 blocks when ip is ratelimited, otherwise let 1/xth traffic through
|
||||
# ip-ratelimit-factor: 10
|
||||
|
||||
|
||||
# Python config section. To enable:
|
||||
# o use --with-pythonmodule to configure before compiling.
|
||||
# o list python in the module-config string (above) to enable.
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ harden\-referral\-path, prefetch, prefetch\-key, log\-queries,
|
|||
hide\-identity, hide\-version, identity, version, val\-log\-level,
|
||||
val\-log\-squelch, ignore\-cd\-flag, add\-holddown, del\-holddown,
|
||||
keep\-missing, tcp\-upstream, ssl\-upstream, max\-udp\-size, ratelimit,
|
||||
cache\-max\-ttl, cache\-min\-ttl, cache\-max\-negative\-ttl.
|
||||
ip\-ratelimit, cache\-max\-ttl, cache\-min\-ttl, cache\-max\-negative\-ttl.
|
||||
.TP
|
||||
.B get_option \fIopt
|
||||
Get the value of the option. Give the option name without a trailing ':'.
|
||||
|
|
@ -280,6 +280,12 @@ just the ratelimited domains, with their estimated qps. The ratelimited
|
|||
domains return an error for uncached (new) queries, but cached queries work
|
||||
as normal.
|
||||
.TP
|
||||
.B ip_ratelimit_list \fR[\fI+a\fR]
|
||||
List the ip addresses that are ratelimited. Printed one per line with current
|
||||
estimated qps and qps limit from config. With +a it prints all ips, not
|
||||
just the ratelimited ips, with their estimated qps. The ratelimited
|
||||
ips are dropped before checking the cache.
|
||||
.TP
|
||||
.B view_list_local_zones \fIview\fR
|
||||
\fIlist_local_zones\fR for given view.
|
||||
.TP
|
||||
|
|
@ -319,6 +325,9 @@ The \fIstats\fR command shows a number of statistic counters.
|
|||
.I threadX.num.queries
|
||||
number of queries received by thread
|
||||
.TP
|
||||
.I threadX.num.queries_ip_ratelimited
|
||||
number of queries rate limited by thread
|
||||
.TP
|
||||
.I threadX.num.cachehits
|
||||
number of queries that were successfully answered using a cache lookup
|
||||
.TP
|
||||
|
|
|
|||
|
|
@ -1205,6 +1205,34 @@ in different parts of the namespace. The closest matching suffix is used
|
|||
to determine the qps limit. The rate for the exact matching domain name
|
||||
is not changed, use ratelimit\-for\-domain to set that, you might want
|
||||
to use different settings for a top\-level\-domain and subdomains.
|
||||
.TP 5
|
||||
.B ip\-ratelimit: \fI<number or 0>
|
||||
Enable global ratelimiting of queries accepted per ip address.
|
||||
If 0, the default, it is disabled. This option is experimental at this time.
|
||||
The ratelimit is in queries per second that are allowed. More queries are
|
||||
completely dropped and will not receive a reply, SERVFAIL or otherwise.
|
||||
IP ratelimiting happens before looking in the cache. This may be useful for
|
||||
mitigating amplification attacks.
|
||||
.TP 5
|
||||
.B ip\-ratelimit\-size: \fI<memory size>
|
||||
Give the size of the data structure in which the current ongoing rates are
|
||||
kept track in. Default 4m. In bytes or use m(mega), k(kilo), g(giga).
|
||||
The ip ratelimit structure is small, so this data structure likely does
|
||||
not need to be large.
|
||||
.TP 5
|
||||
.B ip\-ratelimit\-slabs: \fI<number>
|
||||
Give power of 2 number of slabs, this is used to reduce lock contention
|
||||
in the ip ratelimit tracking data structure. Close to the number of cpus is
|
||||
a fairly good setting.
|
||||
.TP 5
|
||||
.B ip\-ratelimit\-factor: \fI<number>
|
||||
Set the amount of queries to rate limit when the limit is exceeded.
|
||||
If set to 0, all queries are dropped for addresses where the limit is
|
||||
exceeded. If set to another value, 1 in that number is allowed through
|
||||
to complete. Default is 10, allowing 1/10 traffic to flow normally.
|
||||
This can make ordinary queries complete (if repeatedly queried for),
|
||||
and enter the cache, whilst also mitigating the traffic flow by the
|
||||
factor given.
|
||||
.SS "Remote Control Options"
|
||||
In the
|
||||
.B remote\-control:
|
||||
|
|
|
|||
127
services/cache/infra.c
vendored
127
services/cache/infra.c
vendored
|
|
@ -61,6 +61,10 @@
|
|||
/** ratelimit value for delegation point */
|
||||
int infra_dp_ratelimit = 0;
|
||||
|
||||
/** ratelimit value for client ip addresses,
|
||||
* in queries per second. */
|
||||
int infra_ip_ratelimit = 0;
|
||||
|
||||
size_t
|
||||
infra_sizefunc(void* k, void* ATTR_UNUSED(d))
|
||||
{
|
||||
|
|
@ -244,6 +248,14 @@ infra_create(struct config_file* cfg)
|
|||
}
|
||||
name_tree_init_parents(&infra->domain_limits);
|
||||
}
|
||||
infra_ip_ratelimit = cfg->ip_ratelimit;
|
||||
infra->client_ip_rates = slabhash_create(cfg->ratelimit_slabs,
|
||||
INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc,
|
||||
&ip_rate_compfunc, &ip_rate_delkeyfunc, &ip_rate_deldatafunc, NULL);
|
||||
if(!infra->client_ip_rates) {
|
||||
infra_delete(infra);
|
||||
return NULL;
|
||||
}
|
||||
return infra;
|
||||
}
|
||||
|
||||
|
|
@ -264,6 +276,7 @@ infra_delete(struct infra_cache* infra)
|
|||
slabhash_delete(infra->hosts);
|
||||
slabhash_delete(infra->domain_rates);
|
||||
traverse_postorder(&infra->domain_limits, domain_limit_free, NULL);
|
||||
slabhash_delete(infra->client_ip_rates);
|
||||
free(infra);
|
||||
}
|
||||
|
||||
|
|
@ -284,21 +297,28 @@ infra_adjust(struct infra_cache* infra, struct config_file* cfg)
|
|||
return infra;
|
||||
}
|
||||
|
||||
/** calculate the hash value for a host key */
|
||||
/** calculate the hash value for a host key
|
||||
* set use_port to a non-0 number to use the port in
|
||||
* the hash calculation; 0 to ignore the port.*/
|
||||
static hashvalue_t
|
||||
hash_addr(struct sockaddr_storage* addr, socklen_t addrlen)
|
||||
hash_addr(struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
int use_port)
|
||||
{
|
||||
hashvalue_t h = 0xab;
|
||||
/* select the pieces to hash, some OS have changing data inside */
|
||||
if(addr_is_ip6(addr, addrlen)) {
|
||||
struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr;
|
||||
h = hashlittle(&in6->sin6_family, sizeof(in6->sin6_family), h);
|
||||
h = hashlittle(&in6->sin6_port, sizeof(in6->sin6_port), h);
|
||||
if(use_port){
|
||||
h = hashlittle(&in6->sin6_port, sizeof(in6->sin6_port), h);
|
||||
}
|
||||
h = hashlittle(&in6->sin6_addr, INET6_SIZE, h);
|
||||
} else {
|
||||
struct sockaddr_in* in = (struct sockaddr_in*)addr;
|
||||
h = hashlittle(&in->sin_family, sizeof(in->sin_family), h);
|
||||
h = hashlittle(&in->sin_port, sizeof(in->sin_port), h);
|
||||
if(use_port){
|
||||
h = hashlittle(&in->sin_port, sizeof(in->sin_port), h);
|
||||
}
|
||||
h = hashlittle(&in->sin_addr, INET_SIZE, h);
|
||||
}
|
||||
return h;
|
||||
|
|
@ -308,7 +328,7 @@ hash_addr(struct sockaddr_storage* addr, socklen_t addrlen)
|
|||
static hashvalue_t
|
||||
hash_infra(struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name)
|
||||
{
|
||||
return dname_query_hash(name, hash_addr(addr, addrlen));
|
||||
return dname_query_hash(name, hash_addr(addr, addrlen, 1));
|
||||
}
|
||||
|
||||
/** lookup version that does not check host ttl (you check it) */
|
||||
|
|
@ -726,6 +746,30 @@ int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
|
|||
return infra_dp_ratelimit;
|
||||
}
|
||||
|
||||
size_t ip_rate_sizefunc(void* k, void* ATTR_UNUSED(d))
|
||||
{
|
||||
struct ip_rate_key* key = (struct ip_rate_key*)k;
|
||||
return sizeof(*key) + sizeof(struct ip_rate_data)
|
||||
+ lock_get_mem(&key->entry.lock);
|
||||
}
|
||||
|
||||
int ip_rate_compfunc(void* key1, void* key2)
|
||||
{
|
||||
struct ip_rate_key* k1 = (struct ip_rate_key*)key1;
|
||||
struct ip_rate_key* k2 = (struct ip_rate_key*)key2;
|
||||
return sockaddr_cmp_addr(&k1->addr, k1->addrlen,
|
||||
&k2->addr, k2->addrlen);
|
||||
}
|
||||
|
||||
void ip_rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
struct ip_rate_key* key = (struct ip_rate_key*)k;
|
||||
if(!key)
|
||||
return;
|
||||
lock_rw_destroy(&key->entry.lock);
|
||||
free(key);
|
||||
}
|
||||
|
||||
/** find data item in array, for write access, caller unlocks */
|
||||
static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra,
|
||||
uint8_t* name, size_t namelen, int wr)
|
||||
|
|
@ -739,6 +783,20 @@ static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra,
|
|||
return slabhash_lookup(infra->domain_rates, h, &key, wr);
|
||||
}
|
||||
|
||||
/** find data item in array for ip addresses */
|
||||
struct lruhash_entry* infra_find_ip_ratedata(struct infra_cache* infra,
|
||||
struct comm_reply* repinfo, int wr)
|
||||
{
|
||||
struct ip_rate_key key;
|
||||
hashvalue_t h = hash_addr(&(repinfo->addr),
|
||||
repinfo->addrlen, 0);
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.addr = repinfo->addr;
|
||||
key.addrlen = repinfo->addrlen;
|
||||
key.entry.hash = h;
|
||||
return slabhash_lookup(infra->client_ip_rates, h, &key, wr);
|
||||
}
|
||||
|
||||
/** create rate data item for name, number 1 in now */
|
||||
static void infra_create_ratedata(struct infra_cache* infra,
|
||||
uint8_t* name, size_t namelen, time_t timenow)
|
||||
|
|
@ -767,6 +825,30 @@ static void infra_create_ratedata(struct infra_cache* infra,
|
|||
slabhash_insert(infra->domain_rates, h, &k->entry, d, NULL);
|
||||
}
|
||||
|
||||
/** create rate data item for ip address */
|
||||
static void infra_ip_create_ratedata(struct infra_cache* infra,
|
||||
struct comm_reply* repinfo, time_t timenow)
|
||||
{
|
||||
hashvalue_t h = hash_addr(&(repinfo->addr),
|
||||
repinfo->addrlen, 0);
|
||||
struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k));
|
||||
struct ip_rate_data* d = (struct ip_rate_data*)calloc(1, sizeof(*d));
|
||||
if(!k || !d) {
|
||||
free(k);
|
||||
free(d);
|
||||
return; /* alloc failure */
|
||||
}
|
||||
k->addr = repinfo->addr;
|
||||
k->addrlen = repinfo->addrlen;
|
||||
lock_rw_init(&k->entry.lock);
|
||||
k->entry.hash = h;
|
||||
k->entry.key = k;
|
||||
k->entry.data = d;
|
||||
d->qps[0] = 1;
|
||||
d->timestamp[0] = timenow;
|
||||
slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL);
|
||||
}
|
||||
|
||||
/** find the second and return its rate counter, if none, remove oldest */
|
||||
static int* infra_rate_find_second(void* data, time_t t)
|
||||
{
|
||||
|
|
@ -875,6 +957,41 @@ infra_get_mem(struct infra_cache* infra)
|
|||
{
|
||||
size_t s = sizeof(*infra) + slabhash_get_mem(infra->hosts);
|
||||
if(infra->domain_rates) s += slabhash_get_mem(infra->domain_rates);
|
||||
if(infra->client_ip_rates) s += slabhash_get_mem(infra->client_ip_rates);
|
||||
/* ignore domain_limits because walk through tree is big */
|
||||
return s;
|
||||
}
|
||||
|
||||
int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
||||
struct comm_reply* repinfo, time_t timenow)
|
||||
{
|
||||
int max;
|
||||
struct lruhash_entry* entry;
|
||||
|
||||
/* not enabled */
|
||||
if(!infra_ip_ratelimit) {
|
||||
return 1;
|
||||
}
|
||||
/* find or insert ratedata */
|
||||
entry = infra_find_ip_ratedata(infra, repinfo, 1);
|
||||
if(entry) {
|
||||
int premax = infra_rate_max(entry->data, timenow);
|
||||
int* cur = infra_rate_find_second(entry->data, timenow);
|
||||
(*cur)++;
|
||||
max = infra_rate_max(entry->data, timenow);
|
||||
lock_rw_unlock(&entry->lock);
|
||||
|
||||
if(premax < infra_ip_ratelimit && max >= infra_ip_ratelimit) {
|
||||
char client_ip[128];
|
||||
addr_to_str((struct sockaddr_storage *)&repinfo->addr,
|
||||
repinfo->addrlen, client_ip, sizeof(client_ip));
|
||||
verbose(VERB_OPS, "ratelimit exceeded %s %d", client_ip,
|
||||
infra_ip_ratelimit);
|
||||
}
|
||||
return (max <= infra_ip_ratelimit);
|
||||
}
|
||||
|
||||
/* create */
|
||||
infra_ip_create_ratedata(infra, repinfo, timenow);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
48
services/cache/infra.h
vendored
48
services/cache/infra.h
vendored
|
|
@ -36,7 +36,10 @@
|
|||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains the infrastructure cache.
|
||||
* This file contains the infrastructure cache, as well as rate limiting.
|
||||
* Note that there are two sorts of rate-limiting here:
|
||||
* - Pre-cache, per-query rate limiting (query ratelimits)
|
||||
* - Post-cache, per-domain name rate limiting (infra-ratelimits)
|
||||
*/
|
||||
|
||||
#ifndef SERVICES_CACHE_INFRA_H
|
||||
|
|
@ -44,6 +47,8 @@
|
|||
#include "util/storage/lruhash.h"
|
||||
#include "util/storage/dnstree.h"
|
||||
#include "util/rtt.h"
|
||||
#include "util/netevent.h"
|
||||
#include "util/data/msgreply.h"
|
||||
struct slabhash;
|
||||
struct config_file;
|
||||
|
||||
|
|
@ -113,6 +118,8 @@ struct infra_cache {
|
|||
struct slabhash* domain_rates;
|
||||
/** ratelimit settings for domains, struct domain_limit_data */
|
||||
rbtree_t domain_limits;
|
||||
/** hash table with query rates per client ip: ip_rate_key, ip_rate_data */
|
||||
struct slabhash* client_ip_rates;
|
||||
};
|
||||
|
||||
/** ratelimit, unless overridden by domain_limits, 0 is off */
|
||||
|
|
@ -142,6 +149,21 @@ struct rate_key {
|
|||
size_t namelen;
|
||||
};
|
||||
|
||||
/** ip ratelimit, 0 is off */
|
||||
extern int infra_ip_ratelimit;
|
||||
|
||||
/**
|
||||
* key for ip_ratelimit lookups, a source IP.
|
||||
*/
|
||||
struct ip_rate_key {
|
||||
/** lruhash key entry */
|
||||
struct lruhash_entry entry;
|
||||
/** client ip information */
|
||||
struct sockaddr_storage addr;
|
||||
/** length of address */
|
||||
socklen_t addrlen;
|
||||
};
|
||||
|
||||
/** number of seconds to track qps rate */
|
||||
#define RATE_WINDOW 2
|
||||
|
||||
|
|
@ -160,6 +182,8 @@ struct rate_data {
|
|||
time_t timestamp[RATE_WINDOW];
|
||||
};
|
||||
|
||||
#define ip_rate_data rate_data
|
||||
|
||||
/** infra host cache default hash lookup size */
|
||||
#define INFRA_HOST_STARTSIZE 32
|
||||
/** bytes per zonename reserved in the hostcache, dnamelen(zonename.com.) */
|
||||
|
|
@ -381,6 +405,16 @@ int infra_rate_max(void* data, time_t now);
|
|||
int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
|
||||
size_t namelen);
|
||||
|
||||
/** Update query ratelimit hash and decide
|
||||
* whether or not a query should be dropped.
|
||||
* @param infra: infra cache
|
||||
* @param repinfo: information about client
|
||||
* @param timenow: what time it is now.
|
||||
* @return 1 if it could be incremented. 0 if the increment overshot the
|
||||
* ratelimit and the query should be dropped. */
|
||||
int infra_ip_ratelimit_inc(struct infra_cache* infra,
|
||||
struct comm_reply* repinfo, time_t timenow);
|
||||
|
||||
/**
|
||||
* Get memory used by the infra cache.
|
||||
* @param infra: infrastructure cache.
|
||||
|
|
@ -413,4 +447,16 @@ void rate_delkeyfunc(void* k, void* arg);
|
|||
/** delete data */
|
||||
void rate_deldatafunc(void* d, void* arg);
|
||||
|
||||
/* calculate size for the client ip hashtable */
|
||||
size_t ip_rate_sizefunc(void* k, void* d);
|
||||
|
||||
/* compare two addresses */
|
||||
int ip_rate_compfunc(void* key1, void* key2);
|
||||
|
||||
/* delete key, and destroy the lock */
|
||||
void ip_rate_delkeyfunc(void* d, void* arg);
|
||||
|
||||
/* delete data */
|
||||
#define ip_rate_deldatafunc rate_deldatafunc
|
||||
|
||||
#endif /* SERVICES_CACHE_INFRA_H */
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ usage(void)
|
|||
printf(" or off to turn off root forwarding\n");
|
||||
printf(" or give list of ip addresses\n");
|
||||
printf(" ratelimit_list [+a] list ratelimited domains\n");
|
||||
printf(" ip_ratelimit_list [+a] list ratelimited ip addresses\n");
|
||||
printf(" +a list all, also not ratelimited\n");
|
||||
printf("Version %s\n", PACKAGE_VERSION);
|
||||
printf("BSD licensed, see LICENSE in source package for details.\n");
|
||||
|
|
|
|||
|
|
@ -245,11 +245,15 @@ config_create(void)
|
|||
goto error_exit;
|
||||
#endif
|
||||
cfg->disable_dnssec_lame_check = 0;
|
||||
cfg->ip_ratelimit = 0;
|
||||
cfg->ratelimit = 0;
|
||||
cfg->ip_ratelimit_slabs = 4;
|
||||
cfg->ratelimit_slabs = 4;
|
||||
cfg->ip_ratelimit_size = 4*1024*1024;
|
||||
cfg->ratelimit_size = 4*1024*1024;
|
||||
cfg->ratelimit_for_domain = NULL;
|
||||
cfg->ratelimit_below_domain = NULL;
|
||||
cfg->ip_ratelimit_factor = 10;
|
||||
cfg->ratelimit_factor = 10;
|
||||
cfg->qname_minimisation = 0;
|
||||
cfg->qname_minimisation_strict = 0;
|
||||
|
|
@ -488,12 +492,19 @@ int config_set_option(struct config_file* cfg, const char* opt,
|
|||
else S_STR("module-config:", module_conf)
|
||||
else S_STR("python-script:", python_script)
|
||||
else S_YNO("disable-dnssec-lame-check:", disable_dnssec_lame_check)
|
||||
else if(strcmp(opt, "ip-ratelimit:") == 0) {
|
||||
IS_NUMBER_OR_ZERO; cfg->ip_ratelimit = atoi(val);
|
||||
infra_ip_ratelimit=cfg->ip_ratelimit;
|
||||
}
|
||||
else if(strcmp(opt, "ratelimit:") == 0) {
|
||||
IS_NUMBER_OR_ZERO; cfg->ratelimit = atoi(val);
|
||||
infra_dp_ratelimit=cfg->ratelimit;
|
||||
}
|
||||
else S_MEMSIZE("ip-ratelimit-size:", ip_ratelimit_size)
|
||||
else S_MEMSIZE("ratelimit-size:", ratelimit_size)
|
||||
else S_POW2("ip-ratelimit-slabs:", ip_ratelimit_slabs)
|
||||
else S_POW2("ratelimit-slabs:", ratelimit_slabs)
|
||||
else S_NUMBER_OR_ZERO("ip-ratelimit-factor:", ip_ratelimit_factor)
|
||||
else S_NUMBER_OR_ZERO("ratelimit-factor:", ratelimit_factor)
|
||||
else S_YNO("qname-minimisation:", qname_minimisation)
|
||||
else S_YNO("qname-minimisation-strict:", qname_minimisation_strict)
|
||||
|
|
@ -798,11 +809,15 @@ config_get_option(struct config_file* cfg, const char* opt,
|
|||
else O_DEC(opt, "max-udp-size", max_udp_size)
|
||||
else O_STR(opt, "python-script", python_script)
|
||||
else O_YNO(opt, "disable-dnssec-lame-check", disable_dnssec_lame_check)
|
||||
else O_DEC(opt, "ip-ratelimit", ip_ratelimit)
|
||||
else O_DEC(opt, "ratelimit", ratelimit)
|
||||
else O_MEM(opt, "ip-ratelimit-size", ip_ratelimit_size)
|
||||
else O_MEM(opt, "ratelimit-size", ratelimit_size)
|
||||
else O_DEC(opt, "ip-ratelimit-slabs", ip_ratelimit_slabs)
|
||||
else O_DEC(opt, "ratelimit-slabs", ratelimit_slabs)
|
||||
else O_LS2(opt, "ratelimit-for-domain", ratelimit_for_domain)
|
||||
else O_LS2(opt, "ratelimit-below-domain", ratelimit_below_domain)
|
||||
else O_DEC(opt, "ip-ratelimit-factor", ip_ratelimit_factor)
|
||||
else O_DEC(opt, "ratelimit-factor", ratelimit_factor)
|
||||
else O_DEC(opt, "val-sig-skew-min", val_sig_skew_min)
|
||||
else O_DEC(opt, "val-sig-skew-max", val_sig_skew_max)
|
||||
|
|
|
|||
|
|
@ -396,7 +396,16 @@ struct config_file {
|
|||
/** true to disable DNSSEC lameness check in iterator */
|
||||
int disable_dnssec_lame_check;
|
||||
|
||||
/** ratelimit 0 is off, otherwise qps (unless overridden) */
|
||||
/** ratelimit for ip addresses. 0 is off, otherwise qps (unless overridden) */
|
||||
int ip_ratelimit;
|
||||
/** number of slabs for ip_ratelimit cache */
|
||||
size_t ip_ratelimit_slabs;
|
||||
/** memory size in bytes for ip_ratelimit cache */
|
||||
size_t ip_ratelimit_size;
|
||||
/** ip_ratelimit factor, 0 blocks all, 10 allows 1/10 of traffic */
|
||||
int ip_ratelimit_factor;
|
||||
|
||||
/** ratelimit for domains. 0 is off, otherwise qps (unless overridden) */
|
||||
int ratelimit;
|
||||
/** number of slabs for ratelimit cache */
|
||||
size_t ratelimit_slabs;
|
||||
|
|
|
|||
2724
util/configlexer.c
2724
util/configlexer.c
File diff suppressed because it is too large
Load diff
|
|
@ -387,11 +387,15 @@ dnstap-log-forwarder-query-messages{COLON} {
|
|||
dnstap-log-forwarder-response-messages{COLON} {
|
||||
YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) }
|
||||
disable-dnssec-lame-check{COLON} { YDVAR(1, VAR_DISABLE_DNSSEC_LAME_CHECK) }
|
||||
ip-ratelimit{COLON} { YDVAR(1, VAR_IP_RATELIMIT) }
|
||||
ratelimit{COLON} { YDVAR(1, VAR_RATELIMIT) }
|
||||
ip-ratelimit-slabs{COLON} { YDVAR(1, VAR_IP_RATELIMIT_SLABS) }
|
||||
ratelimit-slabs{COLON} { YDVAR(1, VAR_RATELIMIT_SLABS) }
|
||||
ip-ratelimit-size{COLON} { YDVAR(1, VAR_IP_RATELIMIT_SIZE) }
|
||||
ratelimit-size{COLON} { YDVAR(1, VAR_RATELIMIT_SIZE) }
|
||||
ratelimit-for-domain{COLON} { YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) }
|
||||
ratelimit-below-domain{COLON} { YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) }
|
||||
ip-ratelimit-factor{COLON} { YDVAR(1, VAR_IP_RATELIMIT_FACTOR) }
|
||||
ratelimit-factor{COLON} { YDVAR(1, VAR_RATELIMIT_FACTOR) }
|
||||
<INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; }
|
||||
|
||||
|
|
|
|||
1932
util/configparser.c
1932
util/configparser.c
File diff suppressed because it is too large
Load diff
|
|
@ -203,31 +203,35 @@ extern int yydebug;
|
|||
VAR_HARDEN_ALGO_DOWNGRADE = 413,
|
||||
VAR_IP_TRANSPARENT = 414,
|
||||
VAR_DISABLE_DNSSEC_LAME_CHECK = 415,
|
||||
VAR_RATELIMIT = 416,
|
||||
VAR_RATELIMIT_SLABS = 417,
|
||||
VAR_RATELIMIT_SIZE = 418,
|
||||
VAR_RATELIMIT_FOR_DOMAIN = 419,
|
||||
VAR_RATELIMIT_BELOW_DOMAIN = 420,
|
||||
VAR_RATELIMIT_FACTOR = 421,
|
||||
VAR_CAPS_WHITELIST = 422,
|
||||
VAR_CACHE_MAX_NEGATIVE_TTL = 423,
|
||||
VAR_PERMIT_SMALL_HOLDDOWN = 424,
|
||||
VAR_QNAME_MINIMISATION = 425,
|
||||
VAR_QNAME_MINIMISATION_STRICT = 426,
|
||||
VAR_IP_FREEBIND = 427,
|
||||
VAR_DEFINE_TAG = 428,
|
||||
VAR_LOCAL_ZONE_TAG = 429,
|
||||
VAR_ACCESS_CONTROL_TAG = 430,
|
||||
VAR_LOCAL_ZONE_OVERRIDE = 431,
|
||||
VAR_ACCESS_CONTROL_TAG_ACTION = 432,
|
||||
VAR_ACCESS_CONTROL_TAG_DATA = 433,
|
||||
VAR_VIEW = 434,
|
||||
VAR_ACCESS_CONTROL_VIEW = 435,
|
||||
VAR_VIEW_FIRST = 436,
|
||||
VAR_SERVE_EXPIRED = 437,
|
||||
VAR_FAKE_DSA = 438,
|
||||
VAR_LOG_IDENTITY = 439,
|
||||
VAR_USE_SYSTEMD = 440
|
||||
VAR_IP_RATELIMIT = 416,
|
||||
VAR_IP_RATELIMIT_SLABS = 417,
|
||||
VAR_IP_RATELIMIT_SIZE = 418,
|
||||
VAR_RATELIMIT = 419,
|
||||
VAR_RATELIMIT_SLABS = 420,
|
||||
VAR_RATELIMIT_SIZE = 421,
|
||||
VAR_RATELIMIT_FOR_DOMAIN = 422,
|
||||
VAR_RATELIMIT_BELOW_DOMAIN = 423,
|
||||
VAR_IP_RATELIMIT_FACTOR = 424,
|
||||
VAR_RATELIMIT_FACTOR = 425,
|
||||
VAR_CAPS_WHITELIST = 426,
|
||||
VAR_CACHE_MAX_NEGATIVE_TTL = 427,
|
||||
VAR_PERMIT_SMALL_HOLDDOWN = 428,
|
||||
VAR_QNAME_MINIMISATION = 429,
|
||||
VAR_QNAME_MINIMISATION_STRICT = 430,
|
||||
VAR_IP_FREEBIND = 431,
|
||||
VAR_DEFINE_TAG = 432,
|
||||
VAR_LOCAL_ZONE_TAG = 433,
|
||||
VAR_ACCESS_CONTROL_TAG = 434,
|
||||
VAR_LOCAL_ZONE_OVERRIDE = 435,
|
||||
VAR_ACCESS_CONTROL_TAG_ACTION = 436,
|
||||
VAR_ACCESS_CONTROL_TAG_DATA = 437,
|
||||
VAR_VIEW = 438,
|
||||
VAR_ACCESS_CONTROL_VIEW = 439,
|
||||
VAR_VIEW_FIRST = 440,
|
||||
VAR_SERVE_EXPIRED = 441,
|
||||
VAR_FAKE_DSA = 442,
|
||||
VAR_LOG_IDENTITY = 443,
|
||||
VAR_USE_SYSTEMD = 444
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
|
|
@ -389,31 +393,35 @@ extern int yydebug;
|
|||
#define VAR_HARDEN_ALGO_DOWNGRADE 413
|
||||
#define VAR_IP_TRANSPARENT 414
|
||||
#define VAR_DISABLE_DNSSEC_LAME_CHECK 415
|
||||
#define VAR_RATELIMIT 416
|
||||
#define VAR_RATELIMIT_SLABS 417
|
||||
#define VAR_RATELIMIT_SIZE 418
|
||||
#define VAR_RATELIMIT_FOR_DOMAIN 419
|
||||
#define VAR_RATELIMIT_BELOW_DOMAIN 420
|
||||
#define VAR_RATELIMIT_FACTOR 421
|
||||
#define VAR_CAPS_WHITELIST 422
|
||||
#define VAR_CACHE_MAX_NEGATIVE_TTL 423
|
||||
#define VAR_PERMIT_SMALL_HOLDDOWN 424
|
||||
#define VAR_QNAME_MINIMISATION 425
|
||||
#define VAR_QNAME_MINIMISATION_STRICT 426
|
||||
#define VAR_IP_FREEBIND 427
|
||||
#define VAR_DEFINE_TAG 428
|
||||
#define VAR_LOCAL_ZONE_TAG 429
|
||||
#define VAR_ACCESS_CONTROL_TAG 430
|
||||
#define VAR_LOCAL_ZONE_OVERRIDE 431
|
||||
#define VAR_ACCESS_CONTROL_TAG_ACTION 432
|
||||
#define VAR_ACCESS_CONTROL_TAG_DATA 433
|
||||
#define VAR_VIEW 434
|
||||
#define VAR_ACCESS_CONTROL_VIEW 435
|
||||
#define VAR_VIEW_FIRST 436
|
||||
#define VAR_SERVE_EXPIRED 437
|
||||
#define VAR_FAKE_DSA 438
|
||||
#define VAR_LOG_IDENTITY 439
|
||||
#define VAR_USE_SYSTEMD 440
|
||||
#define VAR_IP_RATELIMIT 416
|
||||
#define VAR_IP_RATELIMIT_SLABS 417
|
||||
#define VAR_IP_RATELIMIT_SIZE 418
|
||||
#define VAR_RATELIMIT 419
|
||||
#define VAR_RATELIMIT_SLABS 420
|
||||
#define VAR_RATELIMIT_SIZE 421
|
||||
#define VAR_RATELIMIT_FOR_DOMAIN 422
|
||||
#define VAR_RATELIMIT_BELOW_DOMAIN 423
|
||||
#define VAR_IP_RATELIMIT_FACTOR 424
|
||||
#define VAR_RATELIMIT_FACTOR 425
|
||||
#define VAR_CAPS_WHITELIST 426
|
||||
#define VAR_CACHE_MAX_NEGATIVE_TTL 427
|
||||
#define VAR_PERMIT_SMALL_HOLDDOWN 428
|
||||
#define VAR_QNAME_MINIMISATION 429
|
||||
#define VAR_QNAME_MINIMISATION_STRICT 430
|
||||
#define VAR_IP_FREEBIND 431
|
||||
#define VAR_DEFINE_TAG 432
|
||||
#define VAR_LOCAL_ZONE_TAG 433
|
||||
#define VAR_ACCESS_CONTROL_TAG 434
|
||||
#define VAR_LOCAL_ZONE_OVERRIDE 435
|
||||
#define VAR_ACCESS_CONTROL_TAG_ACTION 436
|
||||
#define VAR_ACCESS_CONTROL_TAG_DATA 437
|
||||
#define VAR_VIEW 438
|
||||
#define VAR_ACCESS_CONTROL_VIEW 439
|
||||
#define VAR_VIEW_FIRST 440
|
||||
#define VAR_SERVE_EXPIRED 441
|
||||
#define VAR_FAKE_DSA 442
|
||||
#define VAR_LOG_IDENTITY 443
|
||||
#define VAR_USE_SYSTEMD 444
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
|
|
@ -424,7 +432,7 @@ union YYSTYPE
|
|||
|
||||
char* str;
|
||||
|
||||
#line 428 "util/configparser.h" /* yacc.c:1909 */
|
||||
#line 436 "util/configparser.h" /* yacc.c:1909 */
|
||||
};
|
||||
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
|
|
|
|||
|
|
@ -124,8 +124,10 @@ extern struct config_parser_state* cfg_parser;
|
|||
%token VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES
|
||||
%token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT
|
||||
%token VAR_DISABLE_DNSSEC_LAME_CHECK
|
||||
%token VAR_IP_RATELIMIT VAR_IP_RATELIMIT_SLABS VAR_IP_RATELIMIT_SIZE
|
||||
%token VAR_RATELIMIT VAR_RATELIMIT_SLABS VAR_RATELIMIT_SIZE
|
||||
%token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN VAR_RATELIMIT_FACTOR
|
||||
%token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN
|
||||
%token VAR_IP_RATELIMIT_FACTOR VAR_RATELIMIT_FACTOR
|
||||
%token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL VAR_PERMIT_SMALL_HOLDDOWN
|
||||
%token VAR_QNAME_MINIMISATION VAR_QNAME_MINIMISATION_STRICT VAR_IP_FREEBIND
|
||||
%token VAR_DEFINE_TAG VAR_LOCAL_ZONE_TAG VAR_ACCESS_CONTROL_TAG
|
||||
|
|
@ -198,9 +200,12 @@ content_server: server_num_threads | server_verbosity | server_port |
|
|||
server_unblock_lan_zones | server_insecure_lan_zones |
|
||||
server_dns64_prefix | server_dns64_synthall |
|
||||
server_infra_cache_min_rtt | server_harden_algo_downgrade |
|
||||
server_ip_transparent | server_ratelimit | server_ratelimit_slabs |
|
||||
server_ratelimit_size | server_ratelimit_for_domain |
|
||||
server_ip_transparent | server_ip_ratelimit | server_ratelimit |
|
||||
server_ip_ratelimit_slabs | server_ratelimit_slabs |
|
||||
server_ip_ratelimit_size | server_ratelimit_size |
|
||||
server_ratelimit_for_domain |
|
||||
server_ratelimit_below_domain | server_ratelimit_factor |
|
||||
server_ip_ratelimit_factor |
|
||||
server_caps_whitelist | server_cache_max_negative_ttl |
|
||||
server_permit_small_holddown | server_qname_minimisation |
|
||||
server_ip_freebind | server_define_tag | server_local_zone_tag |
|
||||
|
|
@ -1504,6 +1509,16 @@ server_access_control_view: VAR_ACCESS_CONTROL_VIEW STRING_ARG STRING_ARG
|
|||
}
|
||||
}
|
||||
;
|
||||
server_ip_ratelimit: VAR_IP_RATELIMIT STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_ip_ratelimit:%s)\n", $2));
|
||||
if(atoi($2) == 0 && strcmp($2, "0") != 0)
|
||||
yyerror("number expected");
|
||||
else cfg_parser->cfg->ip_ratelimit = atoi($2);
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
|
||||
server_ratelimit: VAR_RATELIMIT STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_ratelimit:%s)\n", $2));
|
||||
|
|
@ -1513,6 +1528,14 @@ server_ratelimit: VAR_RATELIMIT STRING_ARG
|
|||
free($2);
|
||||
}
|
||||
;
|
||||
server_ip_ratelimit_size: VAR_IP_RATELIMIT_SIZE STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_ip_ratelimit_size:%s)\n", $2));
|
||||
if(!cfg_parse_memsize($2, &cfg_parser->cfg->ip_ratelimit_size))
|
||||
yyerror("memory size expected");
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_ratelimit_size: VAR_RATELIMIT_SIZE STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_ratelimit_size:%s)\n", $2));
|
||||
|
|
@ -1521,6 +1544,19 @@ server_ratelimit_size: VAR_RATELIMIT_SIZE STRING_ARG
|
|||
free($2);
|
||||
}
|
||||
;
|
||||
server_ip_ratelimit_slabs: VAR_IP_RATELIMIT_SLABS STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_ip_ratelimit_slabs:%s)\n", $2));
|
||||
if(atoi($2) == 0)
|
||||
yyerror("number expected");
|
||||
else {
|
||||
cfg_parser->cfg->ip_ratelimit_slabs = atoi($2);
|
||||
if(!is_pow2(cfg_parser->cfg->ip_ratelimit_slabs))
|
||||
yyerror("must be a power of 2");
|
||||
}
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_ratelimit_slabs: VAR_RATELIMIT_SLABS STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_ratelimit_slabs:%s)\n", $2));
|
||||
|
|
@ -1560,6 +1596,15 @@ server_ratelimit_below_domain: VAR_RATELIMIT_BELOW_DOMAIN STRING_ARG STRING_ARG
|
|||
}
|
||||
}
|
||||
;
|
||||
server_ip_ratelimit_factor: VAR_IP_RATELIMIT_FACTOR STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_ip_ratelimit_factor:%s)\n", $2));
|
||||
if(atoi($2) == 0 && strcmp($2, "0") != 0)
|
||||
yyerror("number expected");
|
||||
else cfg_parser->cfg->ip_ratelimit_factor = atoi($2);
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_ratelimit_factor: VAR_RATELIMIT_FACTOR STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_ratelimit_factor:%s)\n", $2));
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ void log_dns_msg(const char* str, struct query_info* qinfo,
|
|||
* status code from, and size of a query response.
|
||||
*
|
||||
* @param v: at what verbosity level to print this.
|
||||
* @param qinfo: query section.
|
||||
* @param qinf: query section.
|
||||
* @param addr: address of the client.
|
||||
* @param addrlen: length of the client address.
|
||||
* @param dur: how long it took to complete the query.
|
||||
|
|
|
|||
|
|
@ -216,6 +216,7 @@ fptr_whitelist_hash_sizefunc(lruhash_sizefunc_t fptr)
|
|||
else if(fptr == &infra_sizefunc) return 1;
|
||||
else if(fptr == &key_entry_sizefunc) return 1;
|
||||
else if(fptr == &rate_sizefunc) return 1;
|
||||
else if(fptr == &ip_rate_sizefunc) return 1;
|
||||
else if(fptr == &test_slabhash_sizefunc) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -228,6 +229,7 @@ fptr_whitelist_hash_compfunc(lruhash_compfunc_t fptr)
|
|||
else if(fptr == &infra_compfunc) return 1;
|
||||
else if(fptr == &key_entry_compfunc) return 1;
|
||||
else if(fptr == &rate_compfunc) return 1;
|
||||
else if(fptr == &ip_rate_compfunc) return 1;
|
||||
else if(fptr == &test_slabhash_compfunc) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -240,6 +242,7 @@ fptr_whitelist_hash_delkeyfunc(lruhash_delkeyfunc_t fptr)
|
|||
else if(fptr == &infra_delkeyfunc) return 1;
|
||||
else if(fptr == &key_entry_delkeyfunc) return 1;
|
||||
else if(fptr == &rate_delkeyfunc) return 1;
|
||||
else if(fptr == &ip_rate_delkeyfunc) return 1;
|
||||
else if(fptr == &test_slabhash_delkey) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue