mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 01:59:26 +00:00
[master] DNS RRL
3494. [func] DNS RRL: Blunt the impact of DNS reflection and amplification attacks by rate-limiting substantially- identical responses. [RT #28130]
This commit is contained in:
parent
261ef37955
commit
55e5c51e66
4
CHANGES
4
CHANGES
@ -1,3 +1,7 @@
|
||||
3494. [func] DNS RRL: Blunt the impact of DNS reflection and
|
||||
amplification attacks by rate-limiting substantially-
|
||||
identical responses. [RT #28130]
|
||||
|
||||
3493. [contrib] Added BDBHPT dynamically-lodable DLZ module,
|
||||
contributed by Mark Goldfinch. [RT #32549]
|
||||
|
||||
|
@ -1000,6 +1000,11 @@ client_send(ns_client_t *client) {
|
||||
}
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto done;
|
||||
/*
|
||||
* Stop after the question if TC was set for rate limiting.
|
||||
*/
|
||||
if ((client->message->flags & DNS_MESSAGEFLAG_TC) != 0)
|
||||
goto renderend;
|
||||
result = dns_message_rendersection(client->message,
|
||||
DNS_SECTION_ANSWER,
|
||||
DNS_MESSAGERENDER_PARTIAL |
|
||||
@ -1205,6 +1210,49 @@ ns_client_error(ns_client_t *client, isc_result_t result) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Try to rate limit error responses.
|
||||
*/
|
||||
if (client->view != NULL && client->view->rrl != NULL) {
|
||||
isc_boolean_t wouldlog;
|
||||
char log_buf[DNS_RRL_LOG_BUF_LEN];
|
||||
dns_rrl_result_t rrl_result;
|
||||
|
||||
INSIST(rcode != dns_rcode_noerror &&
|
||||
rcode != dns_rcode_nxdomain);
|
||||
wouldlog = (ns_g_server->log_queries &&
|
||||
isc_log_wouldlog(ns_g_lctx, DNS_RRL_LOG_DROP));
|
||||
rrl_result = dns_rrl(client->view, &client->peeraddr,
|
||||
TCP_CLIENT(client),
|
||||
dns_rdataclass_in, dns_rdatatype_none,
|
||||
NULL, result, client->now,
|
||||
wouldlog, log_buf, sizeof(log_buf));
|
||||
if (rrl_result != DNS_RRL_RESULT_OK) {
|
||||
/*
|
||||
* Log dropped errors in the query category
|
||||
* so that they are not lost in silence.
|
||||
* Starts of rate-limited bursts are logged in
|
||||
* NS_LOGCATEGORY_RRL.
|
||||
*/
|
||||
if (wouldlog) {
|
||||
ns_client_log(client, NS_LOGCATEGORY_QUERIES,
|
||||
NS_LOGMODULE_CLIENT,
|
||||
DNS_RRL_LOG_DROP,
|
||||
"%s", log_buf);
|
||||
}
|
||||
/*
|
||||
* Some error responses cannot be 'slipped',
|
||||
* so don't try.
|
||||
* This will counted with dropped queries in the
|
||||
* QryDropped counter.
|
||||
*/
|
||||
if (!client->view->rrl->log_only) {
|
||||
ns_client_next(client, DNS_R_DROP);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Message may be an in-progress reply that we had trouble
|
||||
* with, in which case QR will be set. We need to clear QR before
|
||||
|
@ -227,6 +227,13 @@ view \"_bind\" chaos {\n\
|
||||
recursion no;\n\
|
||||
notify no;\n\
|
||||
allow-new-zones no;\n\
|
||||
\n\
|
||||
# Prevent use of this zone in DNS amplified reflection DoS attacks\n\
|
||||
rate-limit {\n\
|
||||
responses-per-second 3;\n\
|
||||
slip 0;\n\
|
||||
min-table-size 10;\n\
|
||||
};\n\
|
||||
\n\
|
||||
zone \"version.bind\" chaos {\n\
|
||||
type master;\n\
|
||||
|
@ -85,6 +85,7 @@ struct ns_query {
|
||||
#define NS_QUERYATTR_CACHEACLOK 0x2000
|
||||
#define NS_QUERYATTR_DNS64 0x4000
|
||||
#define NS_QUERYATTR_DNS64EXCLUDE 0x8000
|
||||
#define NS_QUERYATTR_RRL_CHECKED 0x10000
|
||||
|
||||
|
||||
isc_result_t
|
||||
|
@ -169,7 +169,10 @@ enum {
|
||||
|
||||
dns_nsstatscounter_dns64 = 37,
|
||||
|
||||
dns_nsstatscounter_max = 38
|
||||
dns_nsstatscounter_ratedropped = 38,
|
||||
dns_nsstatscounter_rateslipped = 39,
|
||||
|
||||
dns_nsstatscounter_max = 40
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -5857,6 +5857,105 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
|
||||
resume:
|
||||
CTRACE("query_find: resume");
|
||||
|
||||
/*
|
||||
* Rate limit these responses to this client.
|
||||
*/
|
||||
if (client->view->rrl != NULL &&
|
||||
fname != NULL && dns_name_isabsolute(fname) &&
|
||||
(client->query.attributes & NS_QUERYATTR_RRL_CHECKED) == 0) {
|
||||
dns_rdataset_t nc_rdataset;
|
||||
isc_boolean_t wouldlog;
|
||||
char log_buf[DNS_RRL_LOG_BUF_LEN];
|
||||
isc_result_t nc_result;
|
||||
dns_rrl_result_t rrl_result;
|
||||
|
||||
client->query.attributes |= NS_QUERYATTR_RRL_CHECKED;
|
||||
|
||||
wouldlog = isc_log_wouldlog(ns_g_lctx, DNS_RRL_LOG_DROP);
|
||||
tname = fname;
|
||||
if (result == DNS_R_NXDOMAIN) {
|
||||
/*
|
||||
* Use the database origin name to rate limit NXDOMAIN
|
||||
*/
|
||||
if (db != NULL)
|
||||
tname = dns_db_origin(db);
|
||||
rrl_result = result;
|
||||
} else if (result == DNS_R_NCACHENXDOMAIN &&
|
||||
rdataset != NULL &&
|
||||
dns_rdataset_isassociated(rdataset) &&
|
||||
(rdataset->attributes &
|
||||
DNS_RDATASETATTR_NEGATIVE) != 0) {
|
||||
/*
|
||||
* Try to use owner name in the negative cache SOA.
|
||||
*/
|
||||
dns_fixedname_init(&fixed);
|
||||
dns_rdataset_init(&nc_rdataset);
|
||||
for (nc_result = dns_rdataset_first(rdataset);
|
||||
nc_result == ISC_R_SUCCESS;
|
||||
nc_result = dns_rdataset_next(rdataset)) {
|
||||
dns_ncache_current(rdataset,
|
||||
dns_fixedname_name(&fixed),
|
||||
&nc_rdataset);
|
||||
if (nc_rdataset.type == dns_rdatatype_soa) {
|
||||
dns_rdataset_disassociate(&nc_rdataset);
|
||||
tname = dns_fixedname_name(&fixed);
|
||||
break;
|
||||
}
|
||||
dns_rdataset_disassociate(&nc_rdataset);
|
||||
}
|
||||
rrl_result = DNS_R_NXDOMAIN;
|
||||
} else if (result == DNS_R_DELEGATION) {
|
||||
rrl_result = result;
|
||||
} else {
|
||||
rrl_result = ISC_R_SUCCESS;
|
||||
}
|
||||
rrl_result = dns_rrl(client->view, &client->peeraddr,
|
||||
ISC_TF((client->attributes
|
||||
& NS_CLIENTATTR_TCP) != 0),
|
||||
client->message->rdclass, qtype, tname,
|
||||
rrl_result, client->now,
|
||||
wouldlog, log_buf, sizeof(log_buf));
|
||||
if (rrl_result != DNS_RRL_RESULT_OK) {
|
||||
/*
|
||||
* Log dropped or slipped responses in the query
|
||||
* category so that requests are not silently lost.
|
||||
* Starts of rate-limited bursts are logged in
|
||||
* DNS_LOGCATEGORY_RRL.
|
||||
*
|
||||
* Dropped responses are counted with dropped queries
|
||||
* in QryDropped while slipped responses are counted
|
||||
* with other truncated responses in RespTruncated.
|
||||
*/
|
||||
if (wouldlog && ns_g_server->log_queries) {
|
||||
ns_client_log(client, NS_LOGCATEGORY_QUERIES,
|
||||
NS_LOGMODULE_CLIENT,
|
||||
DNS_RRL_LOG_DROP,
|
||||
"%s", log_buf);
|
||||
}
|
||||
if (!client->view->rrl->log_only) {
|
||||
if (rrl_result == DNS_RRL_RESULT_DROP) {
|
||||
/*
|
||||
* These will also be counted in
|
||||
* dns_nsstatscounter_dropped
|
||||
*/
|
||||
inc_stats(client,
|
||||
dns_nsstatscounter_ratedropped);
|
||||
QUERY_ERROR(DNS_R_DROP);
|
||||
} else {
|
||||
/*
|
||||
* These will also be counted in
|
||||
* dns_nsstatscounter_truncatedresp
|
||||
*/
|
||||
inc_stats(client,
|
||||
dns_nsstatscounter_rateslipped);
|
||||
client->message->flags |=
|
||||
DNS_MESSAGEFLAG_TC;
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ISC_LIST_EMPTY(client->view->rpz_zones) &&
|
||||
(RECURSIONOK(client) || !client->view->rpz_recursive_only) &&
|
||||
rpz_ck_dnssec(client, result, rdataset, sigrdataset) &&
|
||||
@ -7321,12 +7420,14 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
|
||||
}
|
||||
|
||||
if (eresult != ISC_R_SUCCESS &&
|
||||
(!PARTIALANSWER(client) || WANTRECURSION(client))) {
|
||||
(!PARTIALANSWER(client) || WANTRECURSION(client)
|
||||
|| eresult == DNS_R_DROP)) {
|
||||
if (eresult == DNS_R_DUPLICATE || eresult == DNS_R_DROP) {
|
||||
/*
|
||||
* This was a duplicate query that we are
|
||||
* recursing on. Don't send a response now.
|
||||
* The original query will still cause a response.
|
||||
* recursing on or the result of rate limiting.
|
||||
* Don't send a response now for a duplicate query,
|
||||
* because the original will still cause a response.
|
||||
*/
|
||||
query_next(client, eresult);
|
||||
} else {
|
||||
|
@ -1678,6 +1678,199 @@ configure_rpz(dns_view_t *view, const cfg_listelt_t *element,
|
||||
return (result);
|
||||
}
|
||||
|
||||
#define CHECK_RRL(obj, cond, pat, val1, val2) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, \
|
||||
pat, val1, val2); \
|
||||
result = ISC_R_RANGE; \
|
||||
goto cleanup; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static isc_result_t
|
||||
configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
|
||||
const cfg_obj_t *obj;
|
||||
dns_rrl_t *rrl;
|
||||
isc_result_t result;
|
||||
int min_entries, i, j;
|
||||
|
||||
/*
|
||||
* Most DNS servers have few clients, but intentinally open
|
||||
* recursive and authoritative servers often have many.
|
||||
* So start with a small number of entries unless told otherwise
|
||||
* to reduce cold-start costs.
|
||||
*/
|
||||
min_entries = 500;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "min-table-size", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
min_entries = cfg_obj_asuint32(obj);
|
||||
if (min_entries < 1)
|
||||
min_entries = 1;
|
||||
}
|
||||
result = dns_rrl_init(&rrl, view, min_entries);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
i = ISC_MAX(20000, min_entries);
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "max-table-size", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
i = cfg_obj_asuint32(obj);
|
||||
CHECK_RRL(obj, i >= min_entries,
|
||||
"max-table-size %d < min-table-size %d",
|
||||
i, min_entries);
|
||||
}
|
||||
rrl->max_entries = i;
|
||||
|
||||
i = 0;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "responses-per-second", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
i = cfg_obj_asuint32(obj);
|
||||
CHECK_RRL(obj, i <= DNS_RRL_MAX_RATE,
|
||||
"responses-per-second %d > %d",
|
||||
i, DNS_RRL_MAX_RATE);
|
||||
}
|
||||
rrl->responses_per_second = i;
|
||||
rrl->scaled_responses_per_second = rrl->responses_per_second;
|
||||
|
||||
/*
|
||||
* The default error rate is the response rate,
|
||||
* and so off by default.
|
||||
*/
|
||||
i = rrl->responses_per_second;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "errors-per-second", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
i = cfg_obj_asuint32(obj);
|
||||
CHECK_RRL(obj, i <= DNS_RRL_MAX_RATE,
|
||||
"errors-per-second %d > %d",
|
||||
i, DNS_RRL_MAX_RATE);
|
||||
}
|
||||
rrl->errors_per_second = i;
|
||||
rrl->scaled_errors_per_second = rrl->errors_per_second;
|
||||
/*
|
||||
* The default NXDOMAIN rate is the response rate,
|
||||
* and so off by default.
|
||||
*/
|
||||
i = rrl->responses_per_second;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "nxdomains-per-second", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
i = cfg_obj_asuint32(obj);
|
||||
CHECK_RRL(obj, i <= DNS_RRL_MAX_RATE,
|
||||
"nxdomains-per-second %d > %d",
|
||||
i, DNS_RRL_MAX_RATE);
|
||||
}
|
||||
rrl->nxdomains_per_second = i;
|
||||
rrl->scaled_nxdomains_per_second = rrl->nxdomains_per_second;
|
||||
|
||||
/*
|
||||
* The all-per-second rate is off by default.
|
||||
*/
|
||||
i = 0;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "all-per-second", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
i = cfg_obj_asuint32(obj);
|
||||
CHECK_RRL(obj, i <= DNS_RRL_MAX_RATE, "all-per-second %d > %d",
|
||||
i, DNS_RRL_MAX_RATE);
|
||||
}
|
||||
rrl->all_per_second = i;
|
||||
rrl->scaled_all_per_second = rrl->all_per_second;
|
||||
|
||||
i = 2;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "slip", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
i = cfg_obj_asuint32(obj);
|
||||
CHECK_RRL(obj, i <= DNS_RRL_MAX_SLIP,
|
||||
"slip %d > %d", i, DNS_RRL_MAX_SLIP);
|
||||
}
|
||||
rrl->slip = i;
|
||||
rrl->scaled_slip = rrl->slip;
|
||||
|
||||
i = 15;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "window", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
i = cfg_obj_asuint32(obj);
|
||||
CHECK_RRL(obj, i >= 1 && i <= DNS_RRL_MAX_WINDOW,
|
||||
"window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
|
||||
}
|
||||
rrl->window = i;
|
||||
|
||||
i = 0;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "qps-scale", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
i = cfg_obj_asuint32(obj);
|
||||
CHECK_RRL(obj, i >= 1, "invalid 'qps-scale %d'%s", i, "");
|
||||
}
|
||||
rrl->qps_scale = i;
|
||||
rrl->qps = 1.0;
|
||||
|
||||
i = 24;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "IPv4-prefix-length", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
i = cfg_obj_asuint32(obj);
|
||||
CHECK_RRL(obj, i >= 8 && i <= 32,
|
||||
"invalid 'IPv4-prefix-length %d'%s", i, "");
|
||||
}
|
||||
rrl->ipv4_prefixlen = i;
|
||||
if (i == 32)
|
||||
rrl->ipv4_mask = 0xffffffff;
|
||||
else
|
||||
rrl->ipv4_mask = htonl(0xffffffff << (32-i));
|
||||
|
||||
i = 56;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "IPv6-prefix-length", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
i = cfg_obj_asuint32(obj);
|
||||
CHECK_RRL(obj, i >= 16 && i <= DNS_RRL_MAX_PREFIX,
|
||||
"IPv6-prefix-length %d < 16 or > %d",
|
||||
i, DNS_RRL_MAX_PREFIX);
|
||||
}
|
||||
rrl->ipv6_prefixlen = i;
|
||||
for (j = 0; j < 4; ++j) {
|
||||
if (i <= 0) {
|
||||
rrl->ipv6_mask[j] = 0;
|
||||
} else if (i < 32) {
|
||||
rrl->ipv6_mask[j] = htonl(0xffffffff << (32-i));
|
||||
} else {
|
||||
rrl->ipv6_mask[j] = 0xffffffff;
|
||||
}
|
||||
i -= 32;
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "exempt-clients", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = cfg_acl_fromconfig(obj, config, ns_g_lctx,
|
||||
ns_g_aclconfctx, ns_g_mctx,
|
||||
0, &rrl->exempt);
|
||||
CHECK_RRL(obj, result == ISC_R_SUCCESS,
|
||||
"invalid %s%s", "address match list", "");
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "log-only", &obj);
|
||||
if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj))
|
||||
rrl->log_only = ISC_TRUE;
|
||||
else
|
||||
rrl->log_only = ISC_FALSE;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
dns_rrl_view_destroy(view);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure 'view' according to 'vconfig', taking defaults from 'config'
|
||||
* where values are missing in 'vconfig'.
|
||||
@ -3100,6 +3293,14 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
|
||||
}
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "rate-limit", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = configure_rrl(view, config, obj);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
|
@ -207,6 +207,10 @@ init_desc(void) {
|
||||
SET_NSSTATDESC(recursclients, "recursing clients",
|
||||
"RecursClients");
|
||||
SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64");
|
||||
SET_NSSTATDESC(ratedropped, "responses dropped for rate limits",
|
||||
"RateDropped");
|
||||
SET_NSSTATDESC(rateslipped, "responses truncated for rate limits",
|
||||
"RateSlipped");
|
||||
INSIST(i == dns_nsstatscounter_max);
|
||||
|
||||
/* Initialize resolver statistics */
|
||||
|
@ -17,6 +17,7 @@ involving a different DNS setup. They are:
|
||||
nsupdate/ Dynamic update and IXFR tests
|
||||
resolver/ Regression tests for resolver bugs that have been fixed
|
||||
(not a complete resolver test suite)
|
||||
rrl/ query rate limiting
|
||||
rpz/ Tests of response policy zone (RPZ) rewriting
|
||||
stub/ Tests of stub zone functionality
|
||||
unknown/ Unknown type and class tests
|
||||
|
@ -61,7 +61,7 @@ SUBDIRS="acl additional allow_query addzone autosign builtin
|
||||
dsdigest ecdsa formerr forward glue gost ixfr inline limits
|
||||
logfileconfig lwresd masterfile masterformat metadata
|
||||
notify nsupdate pending pkcs11 redirect resolver rndc rpz
|
||||
rrsetorder rsabigexponent sortlist smartsign staticstub
|
||||
rrl rrsetorder rsabigexponent sortlist smartsign staticstub
|
||||
statistics stub tkey tsig tsiggss unknown upforwd verify
|
||||
views wildcard xfer xferquota zonechecks"
|
||||
|
||||
|
1
bin/tests/system/rrl/.gitignore
vendored
Normal file
1
bin/tests/system/rrl/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
flood
|
21
bin/tests/system/rrl/clean.sh
Normal file
21
bin/tests/system/rrl/clean.sh
Normal file
@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
|
||||
# Clean up after rrl tests.
|
||||
|
||||
rm -f dig.out*
|
||||
rm -f */named.memstats */named.run */named.stats */log */session.key
|
||||
rm -f ns3/bl*.db */*.jnl */*.core */*.pid
|
32
bin/tests/system/rrl/ns1/named.conf
Normal file
32
bin/tests/system/rrl/ns1/named.conf
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
controls { /* empty */ };
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.1;
|
||||
notify-source 10.53.0.1;
|
||||
transfer-source 10.53.0.1;
|
||||
port 5300;
|
||||
session-keyfile "session.key";
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.1; };
|
||||
listen-on-v6 { none; };
|
||||
notify no;
|
||||
};
|
||||
|
||||
zone "." {type master; file "root.db";};
|
31
bin/tests/system/rrl/ns1/root.db
Normal file
31
bin/tests/system/rrl/ns1/root.db
Normal file
@ -0,0 +1,31 @@
|
||||
; Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
;
|
||||
; Permission to use, copy, modify, and/or distribute this software for any
|
||||
; purpose with or without fee is hereby granted, provided that the above
|
||||
; copyright notice and this permission notice appear in all copies.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
; PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
$TTL 120
|
||||
@ SOA ns. hostmaster.ns. ( 1 3600 1200 604800 60 )
|
||||
@ NS ns.
|
||||
ns. A 10.53.0.1
|
||||
. A 10.53.0.1
|
||||
|
||||
; limit responses from here
|
||||
tld2. NS ns.tld2.
|
||||
ns.tld2. A 10.53.0.2
|
||||
|
||||
; limit recursion to here
|
||||
tld3. NS ns.tld3.
|
||||
ns.tld3. A 10.53.0.3
|
||||
|
||||
; generate SERVFAIL
|
||||
tld4. NS ns.tld3.
|
18
bin/tests/system/rrl/ns2/hints
Normal file
18
bin/tests/system/rrl/ns2/hints
Normal file
@ -0,0 +1,18 @@
|
||||
; Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
;
|
||||
; Permission to use, copy, modify, and/or distribute this software for any
|
||||
; purpose with or without fee is hereby granted, provided that the above
|
||||
; copyright notice and this permission notice appear in all copies.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
; PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
|
||||
. 0 NS ns1.
|
||||
ns1. 0 A 10.53.0.1
|
72
bin/tests/system/rrl/ns2/named.conf
Normal file
72
bin/tests/system/rrl/ns2/named.conf
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
controls { /* empty */ };
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.2;
|
||||
notify-source 10.53.0.2;
|
||||
transfer-source 10.53.0.2;
|
||||
port 5300;
|
||||
session-keyfile "session.key";
|
||||
pid-file "named.pid";
|
||||
statistics-file "named.stats";
|
||||
listen-on { 10.53.0.2; };
|
||||
listen-on-v6 { none; };
|
||||
notify no;
|
||||
|
||||
rate-limit {
|
||||
responses-per-second 2;
|
||||
all-per-second 70;
|
||||
IPv4-prefix-length 24;
|
||||
IPv6-prefix-length 64;
|
||||
slip 3;
|
||||
/* qps-scale 2; */
|
||||
exempt-clients { 10.53.0.7; };
|
||||
window 1;
|
||||
max-table-size 100;
|
||||
min-table-size 2;
|
||||
};
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm hmac-md5;
|
||||
};
|
||||
controls {
|
||||
inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
/*
|
||||
* These log settings have no effect unless "-g" is removed from ../../start.pl
|
||||
*/
|
||||
logging {
|
||||
channel debug {
|
||||
file "log-debug";
|
||||
print-category yes; print-severity yes; severity debug 10;
|
||||
};
|
||||
channel queries {
|
||||
file "log-queries";
|
||||
print-category yes; print-severity yes; severity info;
|
||||
};
|
||||
category rate-limit { debug; queries; };
|
||||
category queries { debug; queries; };
|
||||
};
|
||||
|
||||
zone "." { type hint; file "hints"; };
|
||||
|
||||
zone "tld2."{ type master; file "tld2.db"; };
|
42
bin/tests/system/rrl/ns2/tld2.db
Normal file
42
bin/tests/system/rrl/ns2/tld2.db
Normal file
@ -0,0 +1,42 @@
|
||||
; Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
;
|
||||
; Permission to use, copy, modify, and/or distribute this software for any
|
||||
; purpose with or without fee is hereby granted, provided that the above
|
||||
; copyright notice and this permission notice appear in all copies.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
; PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
|
||||
; rate limit response from this zone
|
||||
|
||||
$TTL 120
|
||||
@ SOA tld2. hostmaster.ns.tld2. ( 1 3600 1200 604800 60 )
|
||||
NS ns
|
||||
NS .
|
||||
ns A 10.53.0.2
|
||||
|
||||
a1 A 192.168.2.1
|
||||
|
||||
*.a2 A 192.168.2.2
|
||||
|
||||
; a3 is in tld3
|
||||
|
||||
; a4 does not exist to give NXDOMAIN
|
||||
|
||||
; a5 for TCP requests
|
||||
a5 A 192.168.2.5
|
||||
|
||||
; a6 for whitelisted clients
|
||||
a6 A 192.168.2.6
|
||||
|
||||
; a7 for SERVFAIL
|
||||
|
||||
; a8 for all-per-second limit
|
||||
$GENERATE 101-180 all$.a8 A 192.168.2.8
|
18
bin/tests/system/rrl/ns3/hints
Normal file
18
bin/tests/system/rrl/ns3/hints
Normal file
@ -0,0 +1,18 @@
|
||||
; Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
;
|
||||
; Permission to use, copy, modify, and/or distribute this software for any
|
||||
; purpose with or without fee is hereby granted, provided that the above
|
||||
; copyright notice and this permission notice appear in all copies.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
; PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
|
||||
. 0 NS ns1.
|
||||
ns1. 0 A 10.53.0.1
|
34
bin/tests/system/rrl/ns3/named.conf
Normal file
34
bin/tests/system/rrl/ns3/named.conf
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
controls { /* empty */ };
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.3;
|
||||
notify-source 10.53.0.3;
|
||||
transfer-source 10.53.0.3;
|
||||
port 5300;
|
||||
session-keyfile "session.key";
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.3; };
|
||||
listen-on-v6 { none; };
|
||||
notify no;
|
||||
};
|
||||
|
||||
zone "." { type hint; file "hints"; };
|
||||
|
||||
zone "tld3."{ type master; file "tld3.db"; };
|
25
bin/tests/system/rrl/ns3/tld3.db
Normal file
25
bin/tests/system/rrl/ns3/tld3.db
Normal file
@ -0,0 +1,25 @@
|
||||
; Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
;
|
||||
; Permission to use, copy, modify, and/or distribute this software for any
|
||||
; purpose with or without fee is hereby granted, provided that the above
|
||||
; copyright notice and this permission notice appear in all copies.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
; PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
|
||||
; rate limit response from this zone
|
||||
|
||||
$TTL 120
|
||||
@ SOA tld3. hostmaster.ns.tld3. ( 1 3600 1200 604800 60 )
|
||||
NS ns
|
||||
NS .
|
||||
ns A 10.53.0.3
|
||||
|
||||
*.a3 A 192.168.3.3
|
21
bin/tests/system/rrl/setup.sh
Normal file
21
bin/tests/system/rrl/setup.sh
Normal file
@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
SYSTEMTESTTOP=..
|
||||
. $SYSTEMTESTTOP/conf.sh
|
||||
. ./clean.sh
|
||||
|
224
bin/tests/system/rrl/tests.sh
Normal file
224
bin/tests/system/rrl/tests.sh
Normal file
@ -0,0 +1,224 @@
|
||||
# Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
# test response rate limiting
|
||||
|
||||
SYSTEMTESTTOP=..
|
||||
. $SYSTEMTESTTOP/conf.sh
|
||||
|
||||
#set -x
|
||||
#set -o noclobber
|
||||
|
||||
ns1=10.53.0.1 # root, defining the others
|
||||
ns2=10.53.0.2 # test server
|
||||
ns3=10.53.0.3 # secondary test server
|
||||
ns7=10.53.0.7 # whitelisted client
|
||||
|
||||
USAGE="$0: [-x]"
|
||||
while getopts "x" c; do
|
||||
case $c in
|
||||
x) set -x;;
|
||||
*) echo "$USAGE" 1>&2; exit 1;;
|
||||
esac
|
||||
done
|
||||
shift `expr $OPTIND - 1 || true`
|
||||
if test "$#" -ne 0; then
|
||||
echo "$USAGE" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
# really quit on control-C
|
||||
trap 'exit 1' 1 2 15
|
||||
|
||||
|
||||
ret=0
|
||||
setret () {
|
||||
ret=1
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
|
||||
# Wait until soon after the start of a second to make results consistent.
|
||||
# The start of a second credits a rate limit.
|
||||
# This would be far easier in C or by assuming a modern version of perl.
|
||||
sec_start () {
|
||||
START=`date`
|
||||
while true; do
|
||||
NOW=`date`
|
||||
if test "$START" != "$NOW"; then
|
||||
return
|
||||
fi
|
||||
$PERL -e 'select(undef, undef, undef, 0.05)' || true
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# $1=result name $2=domain name $3=dig options
|
||||
digcmd () {
|
||||
OFILE=$1; shift
|
||||
DIG_DOM=$1; shift
|
||||
ARGS="+noadd +noauth +nosearch +time=1 +tries=1 +ignore $* -p 5300 $DIG_DOM @$ns2"
|
||||
#echo I:dig $ARGS 1>&2
|
||||
START=`date +%y%m%d%H%M.%S`
|
||||
RESULT=`$DIG $ARGS 2>&1 | tee $OFILE=TEMP \
|
||||
| sed -n -e 's/^[^;].* \([^ ]\{1,\}\)$/\1/p' \
|
||||
-e 's/;; flags.* tc .*/TC/p' \
|
||||
-e 's/;; .* status: NXDOMAIN.*/NXDOMAIN/p' \
|
||||
-e 's/;; .* status: SERVFAIL.*/SERVFAIL/p' \
|
||||
-e 's/;; connection timed out.*/drop/p' \
|
||||
-e 's/;; communications error to.*/drop/p' \
|
||||
| tr -d '\n'`
|
||||
mv "$OFILE=TEMP" "$OFILE=$RESULT"
|
||||
touch -t $START "$OFILE=$RESULT"
|
||||
}
|
||||
|
||||
|
||||
# $1=number of tests $2=target domain $3=dig options
|
||||
CNT=1
|
||||
burst () {
|
||||
BURST_LIMIT=$1; shift
|
||||
BURST_DOM_BASE="$1"; shift
|
||||
while test "$BURST_LIMIT" -ge 1; do
|
||||
if test $CNT -lt 10; then
|
||||
CNT="00$CNT"
|
||||
else
|
||||
if test $CNT -lt 100; then
|
||||
CNT="0$CNT"
|
||||
fi
|
||||
fi
|
||||
eval BURST_DOM="$BURST_DOM_BASE"
|
||||
FILE="dig.out-$BURST_DOM-$CNT"
|
||||
digcmd $FILE $BURST_DOM $* &
|
||||
CNT=`expr $CNT + 1`
|
||||
BURST_LIMIT=`expr "$BURST_LIMIT" - 1`
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# $1=domain $2=IP address $3=# of IP addresses $4=TC $5=drop
|
||||
# $6=NXDOMAIN $7=SERVFAIL or other errors
|
||||
ck_result() {
|
||||
BAD=
|
||||
wait
|
||||
ADDRS=`ls dig.out-$1-*=$2 2>/dev/null | wc -l | tr -d ' '`
|
||||
TC=`ls dig.out-$1-*=TC 2>/dev/null | wc -l | tr -d ' '`
|
||||
DROP=`ls dig.out-$1-*=drop 2>/dev/null | wc -l | tr -d ' '`
|
||||
NXDOMAIN=`ls dig.out-$1-*=NXDOMAIN 2>/dev/null | wc -l | tr -d ' '`
|
||||
SERVFAIL=`ls dig.out-$1-*=SERVFAIL 2>/dev/null | wc -l | tr -d ' '`
|
||||
if test $ADDRS -ne "$3"; then
|
||||
setret "I:$ADDRS instead of $3 $2 responses for $1"
|
||||
BAD=yes
|
||||
fi
|
||||
if test $TC -ne "$4"; then
|
||||
setret "I:$TC instead of $4 truncation responses for $1"
|
||||
BAD=yes
|
||||
fi
|
||||
if test $DROP -ne "$5"; then
|
||||
setret "I:$DROP instead of $5 dropped responses for $1"
|
||||
BAD=yes
|
||||
fi
|
||||
if test $NXDOMAIN -ne "$6"; then
|
||||
setret "I:$NXDOMAIN instead of $6 NXDOMAIN responses for $1"
|
||||
BAD=yes
|
||||
fi
|
||||
if test $SERVFAIL -ne "$7"; then
|
||||
setret "I:$SERVFAIL instead of $7 error responses for $1"
|
||||
BAD=yes
|
||||
fi
|
||||
if test -z "$BAD"; then
|
||||
rm -f dig.out-$1-*
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
#########
|
||||
sec_start
|
||||
|
||||
# basic rate limiting
|
||||
burst 3 a1.tld2
|
||||
# 1 second delay allows an additional response.
|
||||
sleep 1
|
||||
burst 21 a1.tld2
|
||||
# request 30 different qnames to try a wild card
|
||||
burst 30 'x$CNT.a2.tld2'
|
||||
|
||||
# IP TC drop NXDOMAIN SERVFAIL
|
||||
# check for 24 results
|
||||
# including the 1 second delay
|
||||
ck_result a1.tld2 192.168.2.1 3 7 14 0 0
|
||||
|
||||
# Check the wild card answers.
|
||||
# The parent name of the 30 requests is counted.
|
||||
ck_result 'x*.a2.tld2' 192.168.2.2 2 10 18 0 0
|
||||
|
||||
|
||||
#########
|
||||
sec_start
|
||||
|
||||
burst 1 'y$CNT.a3.tld3'; wait; burst 20 'y$CNT.a3.tld3'
|
||||
burst 20 'z$CNT.a4.tld2'
|
||||
|
||||
# Recursion.
|
||||
# The first answer is counted separately because it is counted against
|
||||
# the rate limit on recursing to the server for a3.tld3. The remaining 20
|
||||
# are counted as local responses from the cache.
|
||||
ck_result 'y*.a3.tld3' 192.168.3.3 3 6 12 0 0
|
||||
|
||||
# NXDOMAIN responses are also limited based on the parent name.
|
||||
ck_result 'z*.a4.tld2' x 0 6 12 2 0
|
||||
|
||||
|
||||
#########
|
||||
sec_start
|
||||
|
||||
burst 20 a5.tld2 +tcp
|
||||
burst 20 a6.tld2 -b $ns7
|
||||
burst 20 a7.tld4
|
||||
|
||||
# TCP responses are not rate limited
|
||||
ck_result a5.tld2 192.168.2.5 20 0 0 0 0
|
||||
|
||||
# whitelisted client is not rate limited
|
||||
ck_result a6.tld2 192.168.2.6 20 0 0 0 0
|
||||
|
||||
# Errors such as SERVFAIL are rate limited. The numbers are confusing, because
|
||||
# other rate limiting can be triggered before the SERVFAIL limit is reached.
|
||||
ck_result a7.tld4 192.168.2.1 0 6 12 0 2
|
||||
|
||||
|
||||
#########
|
||||
sec_start
|
||||
|
||||
# all-per-second
|
||||
# The qnames are all unique but the client IP address is constant.
|
||||
CNT=101
|
||||
burst 80 'all$CNT.a8.tld2'
|
||||
ck_result 'a*.a8.tld2' 192.168.2.8 70 0 10 0 0
|
||||
|
||||
|
||||
$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats
|
||||
ckstats () {
|
||||
CNT=`sed -n -e "s/[ ]*\([0-9]*\).responses $1 for rate limits.*/\1/p" \
|
||||
ns2/named.stats`
|
||||
CNT=`expr 0$CNT + 0`
|
||||
if test "$CNT" -ne $2; then
|
||||
setret "I:wrong $1 statistics of $CNT instead of $2"
|
||||
fi
|
||||
}
|
||||
ckstats dropped 77
|
||||
ckstats truncated 35
|
||||
|
||||
|
||||
echo "I:exit status: $ret"
|
||||
exit $ret
|
@ -4826,6 +4826,34 @@ category notify { null; };
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row rowsep="0">
|
||||
<entry colname="1">
|
||||
<para><command>rate-limit</command></para>
|
||||
</entry>
|
||||
<entry colname="2">
|
||||
<para>
|
||||
The start, periodic, and final notices of the
|
||||
rate limiting of a stream of responses are logged at
|
||||
<command>info</command> severity in this category.
|
||||
These messages include a hash value of the domain name
|
||||
of the response and the name itself,
|
||||
except when there is insufficient memory to record
|
||||
the name for the final notice
|
||||
The final notice is normally delayed until about one
|
||||
minute after rate limit stops.
|
||||
A lack of memory can hurry the final notice,
|
||||
in which case it starts with an asterisk (*).
|
||||
Various internal events are logged at debug 1 level
|
||||
and higher.
|
||||
</para>
|
||||
<para>
|
||||
Rate limiting of individual requests
|
||||
is logged in the <command>queries</command> category
|
||||
and can be controlled with the
|
||||
<command>querylog</command> option.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
@ -5361,6 +5389,21 @@ badresp:1,adberr:0,findfail:0,valfail:0]
|
||||
<optional> resolver-query-timeout <replaceable>number</replaceable> ; </optional>
|
||||
<optional> deny-answer-addresses { <replaceable>address_match_list</replaceable> } <optional> except-from { <replaceable>namelist</replaceable> } </optional>;</optional>
|
||||
<optional> deny-answer-aliases { <replaceable>namelist</replaceable> } <optional> except-from { <replaceable>namelist</replaceable> } </optional>;</optional>
|
||||
<optional> rate-limit {
|
||||
<optional> responses-per-second <replaceable>number</replaceable> ; </optional>
|
||||
<optional> errors-per-second <replaceable>number</replaceable> ; </optional>
|
||||
<optional> nxdomains-per-second <replaceable>number</replaceable> ; </optional>
|
||||
<optional> all-per-second <replaceable>number</replaceable> ; </optional>
|
||||
<optional> window <replaceable>number</replaceable> ; </optional>
|
||||
<optional> log-only <replaceable>yes_or_no</replaceable> ; </optional>
|
||||
<optional> qps-scale <replaceable>number</replaceable> ; </optional>
|
||||
<optional> IPv4-prefix-length <replaceable>number</replaceable> ; </optional>
|
||||
<optional> IPv6-prefix-length <replaceable>number</replaceable> ; </optional>
|
||||
<optional> slip <replaceable>number</replaceable> ; </optional>
|
||||
<optional> exempt-clients { <replaceable>address_match_list</replaceable> } ; </optional>
|
||||
<optional> max-table-size <replaceable>number</replaceable> ; </optional>
|
||||
<optional> min-table-size <replaceable>number</replaceable> ; </optional>
|
||||
} ; </optional>
|
||||
<optional> response-policy { <replaceable>zone_name</replaceable>
|
||||
<optional> policy given | disabled | passthru | nxdomain | nodata | cname <replaceable>domain</replaceable> </optional>
|
||||
<optional> recursive-only <replaceable>yes_or_no</replaceable> </optional> <optional> max-policy-ttl <replaceable>number</replaceable> </optional> ;
|
||||
@ -9898,6 +9941,215 @@ ns.domain.com.rpz-nsdname CNAME .
|
||||
have a maximum QPS rate about 50% lower.
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Rate Limiting</title>
|
||||
<para>
|
||||
Excessive essentially identical UDP <emphasis>responses</emphasis>
|
||||
can be discarded by configuring a
|
||||
<command>rate-limit</command> clause in an
|
||||
<command>options</command> statement.
|
||||
This mechanism keeps BIND 9 from being used
|
||||
in amplifying reflection denial of service attacks
|
||||
as well as partially protecting BIND 9 itself from
|
||||
some denial of service attacks.
|
||||
Very short truncated responses can be sent to provide
|
||||
rate-limited responses to legitimate
|
||||
clients within a range of attacked and forged IP addresses,
|
||||
Legitimate clients react to truncated response by retrying
|
||||
with TCP.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Rate limiting works by setting
|
||||
<command>responses-per-second</command>
|
||||
to a number of repetitions per second for responses for a given name
|
||||
and record type to a DNS client.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>Responses-per-second</command> is a limit on
|
||||
identical responses instead of a limit on all responses or
|
||||
even all responses to a single client.
|
||||
10 identical responses per second is a generous limit except perhaps
|
||||
when many clients are using a single IP address via network
|
||||
address translation (NAT).
|
||||
The default limit of zero specifies an unbounded limit to turn off
|
||||
rate-limiting in a view or to only rate-limit NXDOMAIN or other
|
||||
errors.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The notion of "identical responses"
|
||||
and "single DNS client" cannot be simplistic.
|
||||
All responses to a CIDR block with prefix
|
||||
length specified with <command>IPv4-prefix-length</command>
|
||||
(default 24) or <command>IPv6-prefix-length</command>
|
||||
(default 56) are assumed to come from a single DNS client.
|
||||
Requests for a name that result in DNS NXDOMAIN
|
||||
errors are considered identical.
|
||||
This controls some attacks using random names, but
|
||||
accommodates servers that expect many legitimate NXDOMAIN responses
|
||||
such as anti-spam blacklists.
|
||||
By default the limit on NXDOMAIN errors is the same as the
|
||||
<command>responses-per-second</command> value,
|
||||
but it can be set separately with
|
||||
<command>nxdomains-per-second</command>.
|
||||
All requests for all names or types that result in DNS errors
|
||||
such as SERVFAIL and FORMERR (but not NXDOMAIN) are considered
|
||||
identical.
|
||||
This controls attacks using invalid requests or distant,
|
||||
broken authoritative servers.
|
||||
By default the limit on errors is the same as the
|
||||
<command>responses-per-second</command> value,
|
||||
but it can be set separately with
|
||||
<command>errors-per-second</command>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Rate limiting uses a "credit" or "token bucket" scheme.
|
||||
Each identical response has a conceptual account
|
||||
that is given <command>responses-per-second</command>,
|
||||
<command>errors-per-second</command>, and
|
||||
<command>nxdomains-per-second</command> credits every second.
|
||||
A DNS request triggering some desired response debits
|
||||
the account by one.
|
||||
Responses are not sent while the account is negative.
|
||||
The account cannot become more positive than
|
||||
the per-second limit
|
||||
or more negative than <command>window</command>
|
||||
times the per-second limit.
|
||||
A DNS client that sends requests that are not
|
||||
answered can be penalized for up to <command>window</command>
|
||||
seconds (default 15).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Responses generated from local wildcards are counted and limited
|
||||
as if they were for the parent domain name.
|
||||
This prevents flooding by requesting random.wild.example.com.
|
||||
For similar reasons, NXDOMAIN responses are counted and rate
|
||||
limited by the valid domain name nearest to the
|
||||
query name with an SOA record.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Many attacks using DNS involve UDP requests with forged source
|
||||
addresses.
|
||||
Rate limiting prevents the use of BIND 9 to flood a network
|
||||
with responses to requests with forged source addresses,
|
||||
but could let a third party block responses to legitimate requests.
|
||||
There is a mechanism that can answer some legitimate
|
||||
requests from a client whose address is being forged in a flood.
|
||||
Setting <command>slip</command> to 2 (its default) causes every
|
||||
other UDP request to be answered with a small response
|
||||
claiming that the response would have been truncated.
|
||||
The small size and relative infrequency of the response make
|
||||
it unattractive for abuse.
|
||||
<command>Slip</command> must be between 0 and 10.
|
||||
A value of 0 does not "slip"
|
||||
or sends no rate limiting truncated responses.
|
||||
Some error responses includinge REFUSED and SERVFAIL
|
||||
cannot be replaced with truncated responses and are instead
|
||||
leaked at the <command>slip</command> rate.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When the approximate query per second rate exceeds
|
||||
the <command>qps-scale</command> value,
|
||||
then the <command>responses-per-second</command>,
|
||||
<command>errors-per-second</command>,
|
||||
<command>nxdomains-per-second</command> and
|
||||
<command>all-per-second</command> values are reduced by the
|
||||
ratio of the current rate to the <command>qps-scale</command> value.
|
||||
This feature can tighten defenses during attacks.
|
||||
For example, with
|
||||
<command>qps-scale 250; responses-per-second 20;</command> and
|
||||
a total query rate of 1000 queries/second for all queries from
|
||||
all DNS clients including via TCP,
|
||||
then the effective responses/second limit changes to
|
||||
(250/1000)*20 or 5.
|
||||
Responses sent via TCP are not limited
|
||||
but are counted to compute the query per second rate.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Communities of DNS clients can be given their own parameters or no
|
||||
rate limiting by putting
|
||||
<command>rate-limit</command> statements in <command>view</command>
|
||||
statements instead of the global <command>option</command>
|
||||
statement.
|
||||
A <command>rate-limit</command> statement in a view replaces
|
||||
instead of being merged with a <command>rate-limit</command>
|
||||
statement among the main options.
|
||||
DNS clients within a view can be exempted from rate limits
|
||||
with the <command>exempt-clients</command> clause.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
UDP responses of all kinds can be limited with the
|
||||
<command>all-per-second</command> phrase.
|
||||
This rate limiting is unlike the rate limiting provided by
|
||||
<command>responses-per-second</command>,
|
||||
<command>errors-per-second</command>, and
|
||||
<command>nxdomains-per-second</command> on a DNS server
|
||||
which are often invisible to the victim of a DNS reflection attack.
|
||||
Unless the forged requests of the attack are the same as the
|
||||
legitimate requests of the victim, the victim's requests are
|
||||
not affected.
|
||||
Responses affected by an <command>all-per-second</command> limit
|
||||
are always dropped; the <command>slip</command> value has no
|
||||
effect.
|
||||
An <command>all-per-second</command> limit should be
|
||||
at least 4 times as large as the other limits,
|
||||
because single DNS clients often send bursts of legitimate
|
||||
requests.
|
||||
For example, the receipt of a single mail message can prompt
|
||||
requests from an SMTP server for NS, PTR, A, and AAAA records
|
||||
as the incoming SMTP/TCP/IP connection is considered.
|
||||
The SMTP server can need additional NS, A, AAAA, MX, TXT, and SPF
|
||||
records as it considers the STMP <command>Mail From</command>
|
||||
command.
|
||||
Web browsers often repeatedly resolve the same names that
|
||||
are repeated in HTML <IMG> tags in a page.
|
||||
<command>All-per-second</command> is similar to the
|
||||
rate limiting offered by firewalls but often inferior.
|
||||
Attacks that justify ignoring the
|
||||
contents of DNS responses are likely to be attacks on the
|
||||
DNS server itself.
|
||||
They usually should be discarded before the DNS server
|
||||
spends resources make TCP connections or parsing DNS requesets,
|
||||
but that rate limiting must be done before the
|
||||
DNS server sees the requests.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The maximum size of the table used to track requests and
|
||||
rate limit responses is set with <command>max-table-size</command>.
|
||||
Each entry in the table is between 40 and 80 bytes.
|
||||
The table needs approximately as many entries as the number
|
||||
of requests received per second.
|
||||
The default is 20,000.
|
||||
To reduce the cold start of growing the table,
|
||||
<command>min-table-size</command> (default 500)
|
||||
can set the minimum table size.
|
||||
Enable <command>rate-limit</command> category logging to monitor
|
||||
expansions of the table and inform
|
||||
choices for the initial and maximum table size.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Use <command>log-only yes</command> to test rate limiting parameters
|
||||
without actually dropping any requests.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Responses dropped by rate limits are included in the
|
||||
<command>RateDropped</command> and <command>QryDropped</command>
|
||||
statistics.
|
||||
Responses that truncated by rate limits are included in
|
||||
<command>RateSlipped</command> and <command>RespTruncated</command>.
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="server_statement_grammar">
|
||||
@ -14577,6 +14829,32 @@ HOST-127.EXAMPLE. MX 0 .
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row rowsep="0">
|
||||
<entry colname="1">
|
||||
<para><command>RateDropped</command></para>
|
||||
</entry>
|
||||
<entry colname="2">
|
||||
<para><command></command></para>
|
||||
</entry>
|
||||
<entry colname="3">
|
||||
<para>
|
||||
Responses dropped by rate limits.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row rowsep="0">
|
||||
<entry colname="1">
|
||||
<para><command>RateSlipped</command></para>
|
||||
</entry>
|
||||
<entry colname="2">
|
||||
<para><command></command></para>
|
||||
</entry>
|
||||
<entry colname="3">
|
||||
<para>
|
||||
Responses truncated by rate limits.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
@ -70,8 +70,8 @@ DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
|
||||
portlist.@O@ private.@O@ \
|
||||
rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \
|
||||
rdatalist.@O@ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ \
|
||||
request.@O@ resolver.@O@ result.@O@ rootns.@O@ rpz.@O@ \
|
||||
rriterator.@O@ sdb.@O@ \
|
||||
request.@O@ resolver.@O@ result.@O@ rootns.@O@ \
|
||||
rpz.@O@ rrl.@O@ rriterator.@O@ sdb.@O@ \
|
||||
sdlz.@O@ soa.@O@ ssu.@O@ ssu_external.@O@ \
|
||||
stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \
|
||||
tsec.@O@ tsig.@O@ ttl.@O@ update.@O@ validator.@O@ \
|
||||
@ -98,7 +98,7 @@ DNSSRCS = acache.c acl.c adb.c byaddr.c \
|
||||
name.c ncache.c nsec.c nsec3.c order.c peer.c portlist.c \
|
||||
rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c rdatalist.c \
|
||||
rdataset.c rdatasetiter.c rdataslab.c request.c \
|
||||
resolver.c result.c rootns.c rpz.c rriterator.c \
|
||||
resolver.c result.c rootns.c rpz.c rrl.c rriterator.c \
|
||||
sdb.c sdlz.c soa.c ssu.c ssu_external.c \
|
||||
stats.c tcpmsg.c time.c timer.c tkey.c \
|
||||
tsec.c tsig.c ttl.c update.c validator.c \
|
||||
|
@ -43,6 +43,7 @@ LIBDNS_EXTERNAL_DATA extern isc_logmodule_t dns_modules[];
|
||||
#define DNS_LOGCATEGORY_DELEGATION_ONLY (&dns_categories[10])
|
||||
#define DNS_LOGCATEGORY_EDNS_DISABLED (&dns_categories[11])
|
||||
#define DNS_LOGCATEGORY_RPZ (&dns_categories[12])
|
||||
#define DNS_LOGCATEGORY_RRL (&dns_categories[13])
|
||||
|
||||
/* Backwards compatibility. */
|
||||
#define DNS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL
|
||||
|
273
lib/dns/include/dns/rrl.h
Normal file
273
lib/dns/include/dns/rrl.h
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DNS_RRL_H
|
||||
#define DNS_RRL_H 1
|
||||
|
||||
/*
|
||||
* Rate limit DNS responses.
|
||||
*/
|
||||
|
||||
#include <isc/lang.h>
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
|
||||
/*
|
||||
* Memory allocation or other failures.
|
||||
*/
|
||||
#define DNS_RRL_LOG_FAIL ISC_LOG_WARNING
|
||||
/*
|
||||
* dropped or slipped responses.
|
||||
*/
|
||||
#define DNS_RRL_LOG_DROP ISC_LOG_INFO
|
||||
/*
|
||||
* Major events in dropping or slipping.
|
||||
*/
|
||||
#define DNS_RRL_LOG_DEBUG1 ISC_LOG_DEBUG(3)
|
||||
/*
|
||||
* Limit computations.
|
||||
*/
|
||||
#define DNS_RRL_LOG_DEBUG2 ISC_LOG_DEBUG(4)
|
||||
/*
|
||||
* Even less interesting.
|
||||
*/
|
||||
#define DNS_RRL_LOG_DEBUG3 ISC_LOG_DEBUG(9)
|
||||
|
||||
|
||||
#define DNS_RRL_LOG_ERR_LEN 64
|
||||
#define DNS_RRL_LOG_BUF_LEN (sizeof("would continue limiting") + \
|
||||
DNS_RRL_LOG_ERR_LEN + \
|
||||
sizeof(" responses to ") + \
|
||||
ISC_NETADDR_FORMATSIZE + \
|
||||
sizeof("/128 for IN ") + \
|
||||
DNS_RDATATYPE_FORMATSIZE + \
|
||||
DNS_NAME_FORMATSIZE)
|
||||
|
||||
|
||||
typedef struct dns_rrl_hash dns_rrl_hash_t;
|
||||
|
||||
/*
|
||||
* Response types.
|
||||
*/
|
||||
typedef enum {
|
||||
DNS_RRL_RTYPE_FREE = 0,
|
||||
DNS_RRL_RTYPE_QUERY,
|
||||
DNS_RRL_RTYPE_DELEGATION,
|
||||
DNS_RRL_RTYPE_NXDOMAIN,
|
||||
DNS_RRL_RTYPE_ERROR,
|
||||
DNS_RRL_RTYPE_ALL,
|
||||
DNS_RRL_RTYPE_TCP,
|
||||
} dns_rrl_rtype_t;
|
||||
|
||||
/*
|
||||
* A rate limit bucket key.
|
||||
* This should be small to limit the total size of the database.
|
||||
* The hash of the qname should be wide enough to make the probability
|
||||
* of collisions among requests from a single IP address block less than 50%.
|
||||
* We need a 32-bit hash value for 10000 qps (e.g. random qnames forged
|
||||
* by attacker) to collide with legitimate qnames from the target with
|
||||
* probability at most 1%.
|
||||
*/
|
||||
#define DNS_RRL_MAX_PREFIX 64
|
||||
typedef union dns_rrl_key dns_rrl_key_t;
|
||||
union dns_rrl_key {
|
||||
struct {
|
||||
isc_uint32_t ip[DNS_RRL_MAX_PREFIX/32];
|
||||
isc_uint32_t qname_hash;
|
||||
dns_rdatatype_t qtype;
|
||||
isc_uint8_t qclass;
|
||||
dns_rrl_rtype_t rtype :3;
|
||||
isc_boolean_t ipv6 :1;
|
||||
} s;
|
||||
isc_uint16_t w[1];
|
||||
};
|
||||
|
||||
/*
|
||||
* A rate-limit entry.
|
||||
* This should be small to limit the total size of the table of entries.
|
||||
*/
|
||||
typedef struct dns_rrl_entry dns_rrl_entry_t;
|
||||
typedef ISC_LIST(dns_rrl_entry_t) dns_rrl_bin_t;
|
||||
struct dns_rrl_entry {
|
||||
ISC_LINK(dns_rrl_entry_t) lru;
|
||||
ISC_LINK(dns_rrl_entry_t) hlink;
|
||||
dns_rrl_key_t key;
|
||||
# define DNS_RRL_RESPONSE_BITS 24
|
||||
signed int responses :DNS_RRL_RESPONSE_BITS;
|
||||
# define DNS_RRL_QNAMES_BITS 8
|
||||
unsigned int log_qname :DNS_RRL_QNAMES_BITS;
|
||||
|
||||
# define DNS_RRL_TS_GEN_BITS 2
|
||||
unsigned int ts_gen :DNS_RRL_TS_GEN_BITS;
|
||||
isc_boolean_t ts_valid :1;
|
||||
# define DNS_RRL_HASH_GEN_BITS 1
|
||||
unsigned int hash_gen :DNS_RRL_HASH_GEN_BITS;
|
||||
isc_boolean_t logged :1;
|
||||
# define DNS_RRL_LOG_BITS 11
|
||||
unsigned int log_secs :DNS_RRL_LOG_BITS;
|
||||
|
||||
# define DNS_RRL_TS_BITS 12
|
||||
unsigned int ts :DNS_RRL_TS_BITS;
|
||||
|
||||
# define DNS_RRL_MAX_SLIP 10
|
||||
unsigned int slip_cnt :4;
|
||||
};
|
||||
|
||||
#define DNS_RRL_MAX_TIME_TRAVEL 5
|
||||
#define DNS_RRL_FOREVER (1<<DNS_RRL_TS_BITS)
|
||||
#define DNS_RRL_MAX_TS (DNS_RRL_FOREVER - 1)
|
||||
|
||||
#define DNS_RRL_MAX_RESPONSES ((1<<(DNS_RRL_RESPONSE_BITS-1))-1)
|
||||
#define DNS_RRL_MAX_WINDOW 3600
|
||||
#if DNS_RRL_MAX_WINDOW >= DNS_RRL_MAX_TS
|
||||
#error "DNS_RRL_MAX_WINDOW is too large"
|
||||
#endif
|
||||
#define DNS_RRL_MAX_RATE 1000
|
||||
#if DNS_RRL_MAX_RATE >= (DNS_RRL_MAX_RESPONSES / DNS_RRL_MAX_WINDOW)
|
||||
#error "DNS_RRL_MAX_rate is too large"
|
||||
#endif
|
||||
|
||||
#if (1<<DNS_RRL_LOG_BITS) >= DNS_RRL_FOREVER
|
||||
#error DNS_RRL_LOG_BITS is too big
|
||||
#endif
|
||||
#define DNS_RRL_MAX_LOG_SECS 1800
|
||||
#if DNS_RRL_MAX_LOG_SECS >= (1<<DNS_RRL_LOG_BITS)
|
||||
#error "DNS_RRL_MAX_LOG_SECS is too large"
|
||||
#endif
|
||||
#define DNS_RRL_STOP_LOG_SECS 60
|
||||
#if DNS_RRL_STOP_LOG_SECS >= (1<<DNS_RRL_LOG_BITS)
|
||||
#error "DNS_RRL_STOP_LOG_SECS is too large"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* A hash table of rate-limit entries.
|
||||
*/
|
||||
struct dns_rrl_hash {
|
||||
isc_stdtime_t check_time;
|
||||
unsigned int gen :DNS_RRL_HASH_GEN_BITS;
|
||||
int length;
|
||||
dns_rrl_bin_t bins[1];
|
||||
};
|
||||
|
||||
/*
|
||||
* A block of rate-limit entries.
|
||||
*/
|
||||
typedef struct dns_rrl_block dns_rrl_block_t;
|
||||
struct dns_rrl_block {
|
||||
ISC_LINK(dns_rrl_block_t) link;
|
||||
int size;
|
||||
dns_rrl_entry_t entries[1];
|
||||
};
|
||||
|
||||
/*
|
||||
* A rate limited qname buffer.
|
||||
*/
|
||||
typedef struct dns_rrl_qname_buf dns_rrl_qname_buf_t;
|
||||
struct dns_rrl_qname_buf {
|
||||
ISC_LINK(dns_rrl_qname_buf_t) link;
|
||||
const dns_rrl_entry_t *e;
|
||||
unsigned int index;
|
||||
dns_fixedname_t qname;
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-view query rate limit parameters and a pointer to database.
|
||||
*/
|
||||
typedef struct dns_rrl dns_rrl_t;
|
||||
struct dns_rrl {
|
||||
isc_mutex_t lock;
|
||||
isc_mem_t *mctx;
|
||||
|
||||
isc_boolean_t log_only;
|
||||
int responses_per_second;
|
||||
int errors_per_second;
|
||||
int nxdomains_per_second;
|
||||
int all_per_second;
|
||||
int window;
|
||||
int slip;
|
||||
double qps_scale;
|
||||
int max_entries;
|
||||
|
||||
dns_acl_t *exempt;
|
||||
|
||||
int num_entries;
|
||||
|
||||
int qps_responses;
|
||||
isc_stdtime_t qps_time;
|
||||
double qps;
|
||||
int scaled_responses_per_second;
|
||||
int scaled_errors_per_second;
|
||||
int scaled_nxdomains_per_second;
|
||||
int scaled_all_per_second;
|
||||
int scaled_slip;
|
||||
|
||||
unsigned int probes;
|
||||
unsigned int searches;
|
||||
|
||||
ISC_LIST(dns_rrl_block_t) blocks;
|
||||
ISC_LIST(dns_rrl_entry_t) lru;
|
||||
|
||||
dns_rrl_hash_t *hash;
|
||||
dns_rrl_hash_t *old_hash;
|
||||
unsigned int hash_gen;
|
||||
|
||||
unsigned int ts_gen;
|
||||
# define DNS_RRL_TS_BASES (1<<DNS_RRL_TS_GEN_BITS)
|
||||
isc_stdtime_t ts_bases[DNS_RRL_TS_BASES];
|
||||
|
||||
int ipv4_prefixlen;
|
||||
isc_uint32_t ipv4_mask;
|
||||
int ipv6_prefixlen;
|
||||
isc_uint32_t ipv6_mask[4];
|
||||
|
||||
isc_stdtime_t log_stops_time;
|
||||
dns_rrl_entry_t *last_logged;
|
||||
int num_logged;
|
||||
int num_qnames;
|
||||
ISC_LIST(dns_rrl_qname_buf_t) qname_free;
|
||||
# define DNS_RRL_QNAMES (1<<DNS_RRL_QNAMES_BITS)
|
||||
dns_rrl_qname_buf_t *qnames[DNS_RRL_QNAMES];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
DNS_RRL_RESULT_OK,
|
||||
DNS_RRL_RESULT_DROP,
|
||||
DNS_RRL_RESULT_SLIP,
|
||||
} dns_rrl_result_t;
|
||||
|
||||
dns_rrl_result_t
|
||||
dns_rrl(dns_view_t *view,
|
||||
const isc_sockaddr_t *client_addr, isc_boolean_t is_tcp,
|
||||
dns_rdataclass_t rdclass, dns_rdatatype_t qtype,
|
||||
dns_name_t *qname, isc_result_t resp_result, isc_stdtime_t now,
|
||||
isc_boolean_t wouldlog, char *log_buf, unsigned int log_buf_len);
|
||||
|
||||
void
|
||||
dns_rrl_view_destroy(dns_view_t *view);
|
||||
|
||||
isc_result_t
|
||||
dns_rrl_init(dns_rrl_t **rrlp, dns_view_t *view, int min_entries);
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* DNS_RRL_H */
|
@ -74,6 +74,7 @@
|
||||
#include <dns/acl.h>
|
||||
#include <dns/clientinfo.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/rrl.h>
|
||||
#include <dns/rdatastruct.h>
|
||||
#include <dns/rpz.h>
|
||||
#include <dns/types.h>
|
||||
@ -143,6 +144,7 @@ struct dns_view {
|
||||
dns_rbt_t * answeracl_exclude;
|
||||
dns_rbt_t * denyanswernames;
|
||||
dns_rbt_t * answernames_exclude;
|
||||
dns_rrl_t * rrl;
|
||||
isc_boolean_t provideixfr;
|
||||
isc_boolean_t requestnsid;
|
||||
dns_ttl_t maxcachettl;
|
||||
|
@ -45,6 +45,7 @@ LIBDNS_EXTERNAL_DATA isc_logcategory_t dns_categories[] = {
|
||||
{ "delegation-only", 0 },
|
||||
{ "edns-disabled", 0 },
|
||||
{ "rpz", 0 },
|
||||
{ "rate-limit", 0 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
|
1328
lib/dns/rrl.c
Normal file
1328
lib/dns/rrl.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -49,6 +49,7 @@
|
||||
#include <dns/masterdump.h>
|
||||
#include <dns/order.h>
|
||||
#include <dns/peer.h>
|
||||
#include <dns/rrl.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/rdataset.h>
|
||||
#include <dns/request.h>
|
||||
@ -184,6 +185,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
||||
view->answeracl_exclude = NULL;
|
||||
view->denyanswernames = NULL;
|
||||
view->answernames_exclude = NULL;
|
||||
view->rrl = NULL;
|
||||
view->provideixfr = ISC_TRUE;
|
||||
view->maxcachettl = 7 * 24 * 3600;
|
||||
view->maxncachettl = 3 * 3600;
|
||||
@ -336,6 +338,8 @@ destroy(dns_view_t *view) {
|
||||
dns_acache_detach(&view->acache);
|
||||
}
|
||||
dns_rpz_view_destroy(view);
|
||||
dns_rrl_view_destroy(view);
|
||||
|
||||
for (dlzdb = ISC_LIST_HEAD(view->dlz_searched);
|
||||
dlzdb != NULL;
|
||||
dlzdb = ISC_LIST_HEAD(view->dlz_searched)) {
|
||||
@ -353,6 +357,7 @@ destroy(dns_view_t *view) {
|
||||
INSIST(ISC_LIST_EMPTY(view->rpz_zones));
|
||||
INSIST(ISC_LIST_EMPTY(view->dlz_searched));
|
||||
INSIST(ISC_LIST_EMPTY(view->dlz_unsearched));
|
||||
INSIST(view->rrl == NULL);
|
||||
#endif
|
||||
if (view->requestmgr != NULL)
|
||||
dns_requestmgr_detach(&view->requestmgr);
|
||||
|
@ -667,6 +667,9 @@ dns_rriterator_init
|
||||
dns_rriterator_next
|
||||
dns_rriterator_nextrrset
|
||||
dns_rriterator_pause
|
||||
dns_rrl
|
||||
dns_rrl_init
|
||||
dns_rrl_view_destroy
|
||||
dns_sdb_putnamedrr
|
||||
dns_sdb_putrdata
|
||||
dns_sdb_putrr
|
||||
|
@ -346,6 +346,10 @@ SOURCE=..\include\dns\rpz.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\dns\rrl.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\include\dns\rriterator.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -650,6 +654,10 @@ SOURCE=..\rpz.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\rrl.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\rriterator.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -184,6 +184,7 @@ CLEAN :
|
||||
-@erase "$(INTDIR)\result.obj"
|
||||
-@erase "$(INTDIR)\rootns.obj"
|
||||
-@erase "$(INTDIR)\rpz.obj"
|
||||
-@erase "$(INTDIR)\rrl.obj"
|
||||
-@erase "$(INTDIR)\sdb.obj"
|
||||
-@erase "$(INTDIR)\sdlz.obj"
|
||||
-@erase "$(INTDIR)\soa.obj"
|
||||
@ -309,6 +310,7 @@ LINK32_OBJS= \
|
||||
"$(INTDIR)\result.obj" \
|
||||
"$(INTDIR)\rootns.obj" \
|
||||
"$(INTDIR)\rpz.obj" \
|
||||
"$(INTDIR)\rrl.obj" \
|
||||
"$(INTDIR)\rriterator.obj" \
|
||||
"$(INTDIR)\sdb.obj" \
|
||||
"$(INTDIR)\sdlz.obj" \
|
||||
@ -505,6 +507,8 @@ CLEAN :
|
||||
-@erase "$(INTDIR)\rootns.sbr"
|
||||
-@erase "$(INTDIR)\rpz.obj"
|
||||
-@erase "$(INTDIR)\rpz.sbr"
|
||||
-@erase "$(INTDIR)\rrl.obj"
|
||||
-@erase "$(INTDIR)\rrl.sbr"
|
||||
-@erase "$(INTDIR)\rriterator.obj"
|
||||
-@erase "$(INTDIR)\rriterator.sbr"
|
||||
-@erase "$(INTDIR)\sdb.obj"
|
||||
@ -651,6 +655,7 @@ BSC32_SBRS= \
|
||||
"$(INTDIR)\result.sbr" \
|
||||
"$(INTDIR)\rootns.sbr" \
|
||||
"$(INTDIR)\rpz.sbr" \
|
||||
"$(INTDIR)\rrl.sbr" \
|
||||
"$(INTDIR)\rriterator.sbr" \
|
||||
"$(INTDIR)\sdb.sbr" \
|
||||
"$(INTDIR)\sdlz.sbr" \
|
||||
@ -748,6 +753,7 @@ LINK32_OBJS= \
|
||||
"$(INTDIR)\result.obj" \
|
||||
"$(INTDIR)\rootns.obj" \
|
||||
"$(INTDIR)\rpz.obj" \
|
||||
"$(INTDIR)\rrl.obj" \
|
||||
"$(INTDIR)\rriterator.obj" \
|
||||
"$(INTDIR)\sdb.obj" \
|
||||
"$(INTDIR)\sdlz.obj" \
|
||||
@ -1724,6 +1730,24 @@ SOURCE=..\rpz.c
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
!ENDIF
|
||||
|
||||
SOURCE=..\rrl.c
|
||||
|
||||
!IF "$(CFG)" == "libdns - Win32 Release"
|
||||
|
||||
|
||||
"$(INTDIR)\rrl.obj" : $(SOURCE) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "libdns - Win32 Debug"
|
||||
|
||||
|
||||
"$(INTDIR)\rrl.obj" "$(INTDIR)\rrl.sbr" : $(SOURCE) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
!ENDIF
|
||||
|
||||
SOURCE=..\rriterator.c
|
||||
|
@ -1259,6 +1259,39 @@ static cfg_type_t cfg_type_rpz = {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* rate-limit
|
||||
*/
|
||||
static cfg_clausedef_t rrl_clauses[] = {
|
||||
{ "responses-per-second", &cfg_type_uint32, 0 },
|
||||
{ "errors-per-second", &cfg_type_uint32, 0 },
|
||||
{ "nxdomains-per-second", &cfg_type_uint32, 0 },
|
||||
{ "responses-per-second", &cfg_type_uint32, 0 },
|
||||
{ "all-per-second", &cfg_type_uint32, 0 },
|
||||
{ "slip", &cfg_type_uint32, 0 },
|
||||
{ "window", &cfg_type_uint32, 0 },
|
||||
{ "log-only", &cfg_type_boolean, 0 },
|
||||
{ "qps-scale", &cfg_type_uint32, 0 },
|
||||
{ "IPv4-prefix-length", &cfg_type_uint32, 0 },
|
||||
{ "IPv6-prefix-length", &cfg_type_uint32, 0 },
|
||||
{ "exempt-clients", &cfg_type_bracketed_aml, 0 },
|
||||
{ "max-table-size", &cfg_type_uint32, 0 },
|
||||
{ "min-table-size", &cfg_type_uint32, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static cfg_clausedef_t *rrl_clausesets[] = {
|
||||
rrl_clauses,
|
||||
NULL
|
||||
};
|
||||
|
||||
static cfg_type_t cfg_type_rrl = {
|
||||
"rate-limit", cfg_parse_map, cfg_print_map, cfg_doc_map,
|
||||
&cfg_rep_map, rrl_clausesets
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*%
|
||||
* dnssec-lookaside
|
||||
*/
|
||||
@ -1417,6 +1450,7 @@ view_clauses[] = {
|
||||
CFG_CLAUSEFLAG_NOTCONFIGURED },
|
||||
#endif
|
||||
{ "response-policy", &cfg_type_rpz, 0 },
|
||||
{ "rate-limit", &cfg_type_rrl, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user