2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

[master] DDoS mitigation features

3938.	[func]		Added quotas to be used in recursive resolvers
			that are under high query load for names in zones
			whose authoritative servers are nonresponsive or
			are experiencing a denial of service attack.

			- "fetches-per-server" limits the number of
			  simultaneous queries that can be sent to any
			  single authoritative server.  The configured
			  value is a starting point; it is automatically
			  adjusted downward if the server is partially or
			  completely non-responsive. The algorithm used to
			  adjust the quota can be configured via the
			  "fetch-quota-params" option.
			- "fetches-per-zone" limits the number of
			  simultaneous queries that can be sent for names
			  within a single domain.  (Note: Unlike
			  "fetches-per-server", this value is not
			  self-tuning.)
			- New stats counters have been added to count
			  queries spilled due to these quotas.

			See the ARM for details of these options. [RT #37125]
This commit is contained in:
Evan Hunt
2015-07-08 22:53:39 -07:00
parent e8f98ec8d4
commit 1479200aa0
41 changed files with 1976 additions and 102 deletions

View File

@@ -217,6 +217,9 @@ struct dumpcontext {
isc_mem_t *mctx;
isc_boolean_t dumpcache;
isc_boolean_t dumpzones;
isc_boolean_t dumpadb;
isc_boolean_t dumpbad;
isc_boolean_t dumpfail;
FILE *fp;
ISC_LIST(struct viewlistentry) viewlist;
struct viewlistentry *view;
@@ -2385,7 +2388,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
unsigned int dlzargc;
char **dlzargv;
const cfg_obj_t *disabled;
const cfg_obj_t *obj;
const cfg_obj_t *obj, *obj2;
const cfg_listelt_t *element;
in_port_t port;
dns_cache_t *cache = NULL;
@@ -3044,6 +3047,53 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
}
dns_adb_setadbsize(view->adb, max_adb_size);
/*
* Set up ADB quotas
*/
{
isc_uint32_t fps, freq;
double low, high, discount;
obj = NULL;
result = ns_config_get(maps, "fetches-per-server", &obj);
INSIST(result == ISC_R_SUCCESS);
obj2 = cfg_tuple_get(obj, "fetches");
fps = cfg_obj_asuint32(obj2);
obj2 = cfg_tuple_get(obj, "response");
if (!cfg_obj_isvoid(obj2)) {
const char *resp = cfg_obj_asstring(obj2);
isc_result_t r;
if (strcasecmp(resp, "drop") == 0)
r = DNS_R_DROP;
else if (strcasecmp(resp, "fail") == 0)
r = DNS_R_SERVFAIL;
else
INSIST(0);
dns_resolver_setquotaresponse(view->resolver,
dns_quotatype_server, r);
}
obj = NULL;
result = ns_config_get(maps, "fetch-quota-params", &obj);
INSIST(result == ISC_R_SUCCESS);
obj2 = cfg_tuple_get(obj, "frequency");
freq = cfg_obj_asuint32(obj2);
obj2 = cfg_tuple_get(obj, "low");
low = (double) cfg_obj_asfixedpoint(obj2) / 100.0;
obj2 = cfg_tuple_get(obj, "high");
high = (double) cfg_obj_asfixedpoint(obj2) / 100.0;
obj2 = cfg_tuple_get(obj, "discount");
discount = (double) cfg_obj_asfixedpoint(obj2) / 100.0;
dns_adb_setquota(view->adb, fps, freq, low, high, discount);
}
/*
* Set resolver's lame-ttl.
*/
@@ -3503,6 +3553,27 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
INSIST(result == ISC_R_SUCCESS);
dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
obj = NULL;
result = ns_config_get(maps, "fetches-per-zone", &obj);
INSIST(result == ISC_R_SUCCESS);
obj2 = cfg_tuple_get(obj, "fetches");
dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2));
obj2 = cfg_tuple_get(obj, "response");
if (!cfg_obj_isvoid(obj2)) {
const char *resp = cfg_obj_asstring(obj2);
isc_result_t r;
if (strcasecmp(resp, "drop") == 0)
r = DNS_R_DROP;
else if (strcasecmp(resp, "fail") == 0)
r = DNS_R_SERVFAIL;
else
INSIST(0);
dns_resolver_setquotaresponse(view->resolver,
dns_quotatype_zone, r);
}
#ifdef ALLOW_FILTER_AAAA
obj = NULL;
result = ns_config_get(maps, "filter-aaaa-on-v4", &obj);
@@ -5507,6 +5578,7 @@ load_configuration(const char *filename, ns_server_t *server,
ns_cachelist_t cachelist, tmpcachelist;
ns_cfgctx_t *nzctx;
unsigned int maxsocks;
isc_uint32_t softquota = 0;
ISC_LIST_INIT(viewlist);
ISC_LIST_INIT(builtin_viewlist);
@@ -5701,11 +5773,22 @@ load_configuration(const char *filename, ns_server_t *server,
configure_server_quota(maps, "tcp-clients", &server->tcpquota);
configure_server_quota(maps, "recursive-clients",
&server->recursionquota);
if (server->recursionquota.max > 1000)
isc_quota_soft(&server->recursionquota,
server->recursionquota.max - 100);
else
isc_quota_soft(&server->recursionquota, 0);
if (server->recursionquota.max > 1000) {
int margin = ISC_MAX(100, ns_g_cpus + 1);
if (margin > server->recursionquota.max - 100) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
"'recursive-clients %d' too low when "
"running with %d worker threads",
server->recursionquota.max, ns_g_cpus);
CHECK(ISC_R_RANGE);
}
softquota = server->recursionquota.max - margin;
} else
softquota = (server->recursionquota.max * 90) / 100;
isc_quota_soft(&server->recursionquota, softquota);
CHECK(configure_view_acl(NULL, config, "blackhole", NULL,
ns_g_aclconfctx, ns_g_mctx,
@@ -6854,7 +6937,6 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
result = isc_quota_init(&server->recursionquota, 100);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = dns_aclenv_init(mctx, &server->aclenv);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -7865,12 +7947,20 @@ dumpdone(void *arg, isc_result_t result) {
goto cleanup;
}
}
if ((dctx->dumpadb || dctx->dumpbad || dctx->dumpfail) &&
dctx->cache == NULL && dctx->view->view->cachedb != NULL)
dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
if (dctx->cache != NULL) {
dns_adb_dump(dctx->view->view->adb, dctx->fp);
dns_resolver_printbadcache(dctx->view->view->resolver,
dctx->fp);
dns_badcache_print(dctx->view->view->failcache,
"SERVFAIL cache", dctx->fp);
if (dctx->dumpadb)
dns_adb_dump(dctx->view->view->adb, dctx->fp);
if (dctx->dumpbad)
dns_resolver_printbadcache(dctx->view->view->resolver,
dctx->fp);
if (dctx->dumpfail)
dns_badcache_print(dctx->view->view->failcache,
"SERVFAIL cache", dctx->fp);
dns_db_detach(&dctx->cache);
}
if (dctx->dumpzones) {
@@ -7954,6 +8044,9 @@ ns_server_dumpdb(ns_server_t *server, char *args) {
dctx->mctx = server->mctx;
dctx->dumpcache = ISC_TRUE;
dctx->dumpadb = ISC_TRUE;
dctx->dumpbad = ISC_TRUE;
dctx->dumpfail = ISC_TRUE;
dctx->dumpzones = ISC_FALSE;
dctx->fp = NULL;
ISC_LIST_INIT(dctx->viewlist);
@@ -7977,15 +8070,36 @@ ns_server_dumpdb(ns_server_t *server, char *args) {
ptr = next_token(&args, " \t");
if (ptr != NULL && strcmp(ptr, "-all") == 0) {
/* also dump zones */
dctx->dumpzones = ISC_TRUE;
dctx->dumpcache = ISC_TRUE;
ptr = next_token(&args, " \t");
} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
dctx->dumpzones = ISC_FALSE;
dctx->dumpcache = ISC_TRUE;
/* this is the default */
ptr = next_token(&args, " \t");
} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
/* only dump zones, suppress caches */
dctx->dumpadb = ISC_FALSE;
dctx->dumpbad = ISC_FALSE;
dctx->dumpcache = ISC_FALSE;
dctx->dumpfail = ISC_FALSE;
dctx->dumpzones = ISC_TRUE;
ptr = next_token(&args, " \t");
} else if (ptr != NULL && strcmp(ptr, "-adb") == 0) {
/* only dump adb, suppress other caches */
dctx->dumpbad = ISC_FALSE;
dctx->dumpcache = ISC_FALSE;
dctx->dumpfail = ISC_FALSE;
ptr = next_token(&args, " \t");
} else if (ptr != NULL && strcmp(ptr, "-bad") == 0) {
/* only dump badcache, suppress other caches */
dctx->dumpadb = ISC_FALSE;
dctx->dumpcache = ISC_FALSE;
dctx->dumpfail = ISC_FALSE;
ptr = next_token(&args, " \t");
} else if (ptr != NULL && strcmp(ptr, "-fail") == 0) {
/* only dump servfail cache, suppress other caches */
dctx->dumpadb = ISC_FALSE;
dctx->dumpbad = ISC_FALSE;
dctx->dumpcache = ISC_FALSE;
ptr = next_token(&args, " \t");
}
@@ -8114,12 +8228,24 @@ ns_server_dumpsecroots(ns_server_t *server, char *args, isc_buffer_t **text) {
isc_result_t
ns_server_dumprecursing(ns_server_t *server) {
FILE *fp = NULL;
dns_view_t *view;
isc_result_t result;
CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
"could not open dump file", server->recfile);
fprintf(fp,";\n; Recursing Queries\n;\n");
fprintf(fp, ";\n; Recursing Queries\n;\n");
ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL;
view = ISC_LIST_NEXT(view, link))
{
fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n",
view->name);
dns_resolver_dumpfetches(view->resolver,
isc_statsformat_file, fp);
}
fprintf(fp, "; Dump complete\n");
cleanup: