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:
@@ -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:
|
||||
|
Reference in New Issue
Block a user