- 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:
Wouter Wijngaards 2017-01-05 13:57:12 +00:00
parent 9b4b0de746
commit 3a1ffe4c69
20 changed files with 2818 additions and 2338 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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 */

View file

@ -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.");

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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
View file

@ -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;
}

View file

@ -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 */

View file

@ -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");

View file

@ -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)

View file

@ -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;

File diff suppressed because it is too large Load diff

View file

@ -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++; }

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -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));

View file

@ -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.

View file

@ -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;
}