[v9_9] backport RRL to 9.9.x

This incorporates the following changes, plus a new configure
option "--enable-rrl" to turn them on:

3575.	[func]		Changed the logging category for RRL events from
			'queries' to 'query-errors'. [RT #33540]

3554.	[bug]		RRL failed to correctly rate-limit upward
			referrals and failed to count dropped error
			responses in the statistics. [RT #33225]

3545.	[bug]		RRL slip behavior was incorrect when set to 1.
			[RT #33111]

3518.	[bug]		Increase the size of dns_rrl_key.s.rtype by one bit
			so that all dns_rrl_rtype_t enum values fit regardless
			of whether it is teated as signed or unsigned by
			the compiler. [RT #32792]

3494.	[func]		DNS RRL: Blunt the impact of DNS reflection and
			amplification attacks by rate-limiting substantially-
			identical responses. To enable, use "configure
			--enable-rrl". [RT #28130]
This commit is contained in:
Evan Hunt 2013-06-07 12:47:11 -07:00
parent 63de57ef64
commit 6260eef2be
41 changed files with 3155 additions and 18 deletions

20
CHANGES
View file

@ -28,6 +28,9 @@
3576. [bug] Address a shutdown race when validating. [RT #33573]
3575. [func] Changed the logging category for RRL events from
'queries' to 'query-errors'. [RT #33540]
3574. [doc] The 'hostname' keyword was missing from server-id
description in the named.conf man page. [RT #33476]
@ -40,6 +43,23 @@
3566. [func] Log when forwarding updates to master. [RT #33240]
3554. [bug] RRL failed to correctly rate-limit upward
referrals and failed to count dropped error
responses in the statistics. [RT #33225]
3545. [bug] RRL slip behavior was incorrect when set to 1.
[RT #33111]
3518. [bug] Increase the size of dns_rrl_key.s.rtype by one bit
so that all dns_rrl_rtype_t enum values fit regardless
of whether it is teated as signed or unsigned by
the compiler. [RT #32792]
3494. [func] DNS RRL: Blunt the impact of DNS reflection and
amplification attacks by rate-limiting substantially-
identical responses. To enable, use "configure
--enable-rrl". [RT #28130]
--- 9.9.3 released ---
3568. [cleanup] Add a product description line to the version file,

View file

@ -994,6 +994,13 @@ ns_client_send(ns_client_t *client) {
}
if (result != ISC_R_SUCCESS)
goto done;
#ifdef USE_RRL
/*
* Stop after the question if TC was set for rate limiting.
*/
if ((client->message->flags & DNS_MESSAGEFLAG_TC) != 0)
goto renderend;
#endif /* USE_RRL */
result = dns_message_rendersection(client->message,
DNS_SECTION_ANSWER,
DNS_MESSAGERENDER_PARTIAL |
@ -1133,6 +1140,53 @@ ns_client_error(ns_client_t *client, isc_result_t result) {
}
#endif
#ifdef USE_RRL
/*
* 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 = 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_QUERY_EERRORS,
NS_LOGMODULE_CLIENT,
DNS_RRL_LOG_DROP,
"%s", log_buf);
}
/*
* Some error responses cannot be 'slipped',
* so don't try to slip any error responses.
*/
if (!client->view->rrl->log_only) {
isc_stats_increment(ns_g_server->nsstats,
dns_nsstatscounter_ratedropped);
isc_stats_increment(ns_g_server->nsstats,
dns_nsstatscounter_dropped);
ns_client_next(client, DNS_R_DROP);
return;
}
}
}
#endif /* USE_RRL */
/*
* 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

View file

@ -227,8 +227,17 @@ view \"_bind\" chaos {\n\
recursion no;\n\
notify no;\n\
allow-new-zones no;\n\
\n\
zone \"version.bind\" chaos {\n\
"
#ifdef USE_RRL
" # 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\
"
#endif /* USE_RRL */
" zone \"version.bind\" chaos {\n\
type master;\n\
database \"_builtin version\";\n\
};\n\

View file

@ -86,6 +86,10 @@ struct ns_query {
#define NS_QUERYATTR_DNS64 0x4000
#define NS_QUERYATTR_DNS64EXCLUDE 0x8000
#ifdef USE_RRL
#define NS_QUERYATTR_RRL_CHECKED 0x10000
#endif /* USE_RRL */
isc_result_t
ns_query_init(ns_client_t *client);

View file

@ -167,7 +167,14 @@ enum {
dns_nsstatscounter_rpz_rewrites = 36,
#ifdef USE_RRL
dns_nsstatscounter_ratedropped = 37,
dns_nsstatscounter_rateslipped = 38,
dns_nsstatscounter_max = 39
#else /* USE_RRL */
dns_nsstatscounter_max = 37
#endif /* USE_RRL */
};
void

View file

@ -193,7 +193,7 @@ inc_stats(ns_client_t *client, isc_statscounter_t counter) {
#ifdef NEWSTATS
/* Do query type statistics
*
* We only increment per-type if we're using the authoriative
* We only increment per-type if we're using the authoritative
* answer counter, preventing double-counting.
*/
if (counter == dns_nsstatscounter_authans) {
@ -5865,6 +5865,120 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
resume:
CTRACE("query_find: resume");
#ifdef USE_RRL
/*
* Rate limit these responses to this client.
*/
if (client->view->rrl != NULL &&
((fname != NULL && dns_name_isabsolute(fname)) ||
(result == ISC_R_NOTFOUND && !RECURSIONOK(client))) &&
(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_NXRRSET ||
result == DNS_R_EMPTYNAME) {
rrl_result = DNS_R_NXRRSET;
} else if (result == DNS_R_DELEGATION) {
rrl_result = result;
} else if (result == ISC_R_NOTFOUND) {
/*
* Handle referral to ".", including when recursion
* is off or not requested and the hints have not
* been loaded or we have "additional-from-cache no".
*/
tname = dns_rootname;
rrl_result = DNS_R_DELEGATION;
} 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_client_log(client,
NS_LOGCATEGORY_QUERY_EERRORS,
NS_LOGMODULE_QUERY,
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;
}
}
}
#endif /* USE_RRL */
if (!ISC_LIST_EMPTY(client->view->rpz_zones) &&
(RECURSIONOK(client) || !client->view->rpz_recursive_only) &&
rpz_ck_dnssec(client, result, rdataset, sigrdataset) &&
@ -7317,13 +7431,21 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
goto restart;
}
#ifdef USE_RRL
if (eresult != ISC_R_SUCCESS &&
(!PARTIALANSWER(client) || WANTRECURSION(client))) {
(!PARTIALANSWER(client) || WANTRECURSION(client)
|| eresult == DNS_R_DROP))
#else /* USE_RRL */
if (eresult != ISC_R_SUCCESS &&
(!PARTIALANSWER(client) || WANTRECURSION(client)))
#endif /* USE_RRL */
{
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 {

View file

@ -1639,6 +1639,170 @@ configure_rpz(dns_view_t *view, const cfg_listelt_t *element,
return (ISC_R_SUCCESS);
}
#ifdef USE_RRL
#define CHECK_RRL(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)
#define CHECK_RRL_RATE(rate, def, max_rate, name) \
do { \
obj = NULL; \
rrl->rate.str = name; \
result = cfg_map_get(map, name, &obj); \
if (result == ISC_R_SUCCESS) { \
rrl->rate.r = cfg_obj_asuint32(obj); \
CHECK_RRL(rrl->rate.r <= max_rate, \
name" %d > %d", \
rrl->rate.r, max_rate); \
} else { \
rrl->rate.r = def; \
} \
rrl->rate.scaled = rrl->rate.r; \
} 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(i >= min_entries,
"max-table-size %d < min-table-size %d",
i, min_entries);
}
rrl->max_entries = i;
CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
"responses-per-second");
CHECK_RRL_RATE(referrals_per_second,
rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
"referrals-per-second");
CHECK_RRL_RATE(nodata_per_second,
rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
"nodata-per-second");
CHECK_RRL_RATE(nxdomains_per_second,
rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
"nxdomains-per-second");
CHECK_RRL_RATE(errors_per_second,
rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
"errors-per-second");
CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE,
"all-per-second");
CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP,
"slip");
i = 15;
obj = NULL;
result = cfg_map_get(map, "window", &obj);
if (result == ISC_R_SUCCESS) {
i = cfg_obj_asuint32(obj);
CHECK_RRL(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(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(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(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(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);
}
#endif /* USE_RRL */
/*
* Configure 'view' according to 'vconfig', taking defaults from 'config'
* where values are missing in 'vconfig'.
@ -3043,6 +3207,16 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
}
}
#ifdef USE_RRL
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;
}
#endif /* USE_RRL */
result = ISC_R_SUCCESS;
cleanup:

View file

@ -208,6 +208,12 @@ init_desc(void) {
"UpdateBadPrereq");
SET_NSSTATDESC(rpz_rewrites, "response policy zone rewrites",
"RPZRewrites");
#ifdef USE_RRL
SET_NSSTATDESC(ratedropped, "responses dropped for rate limits",
"RateDropped");
SET_NSSTATDESC(rateslipped, "responses truncated for rate limits",
"RateSlipped");
#endif /* USE_RRL */
INSIST(i == dns_nsstatscounter_max);
/* Initialize resolver statistics */

View file

@ -21,7 +21,8 @@ top_srcdir = @top_srcdir@
@BIND9_MAKE_INCLUDES@
SUBDIRS = dlzexternal filter-aaaa lwresd rpz rsabigexponent tkey tsiggss
SUBDIRS = dlzexternal filter-aaaa lwresd rpz rrl \
rsabigexponent tkey tsiggss
TARGETS =
@BIND9_MAKE_RULES@

View file

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

View file

@ -62,7 +62,7 @@ SUBDIRS="acl additional allow_query addzone autosign builtin
database dlv dlvauto dlz dlzexternal dname dns64 dnssec ecdsa
formerr forward glue gost ixfr inline limits logfileconfig
lwresd masterfile masterformat metadata notify nsupdate pending
pkcs11 redirect resolver rndc rpz rrsetorder rsabigexponent
pkcs11 redirect resolver rndc rpz rrl rrsetorder rsabigexponent
smartsign sortlist spf staticstub stub tkey tsig tsiggss unknown
upforwd verify views wildcard xfer xferquota zero zonechecks"

1
bin/tests/system/rrl/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
flood

View file

@ -0,0 +1,53 @@
# Copyright (C) 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.
srcdir = @srcdir@
VPATH = @srcdir@
top_srcdir = @top_srcdir@
@BIND9_VERSION@
@BIND9_MAKE_INCLUDES@
CINCLUDES = ${ISC_INCLUDES}
CDEFINES =
CWARNINGS =
DNSLIBS =
ISCLIBS = .
DNSDEPLIBS =
ISCDEPLIBS =
DEPLIBS =
LIBS = @LIBS@
TARGETS = rrl@EXEEXT@
FILTEROBJS = rrl.@O@
SRCS = rrl.c
@BIND9_MAKE_RULES@
all: rrl@EXEEXT@
rrl@EXEEXT@: ${FILTEROBJS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${FILTEROBJS} ${LIBS}
clean distclean::
rm -f ${TARGETS}

View 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

View 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";};

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

View 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

View file

@ -0,0 +1,71 @@
/*
* 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;
slip 3;
exempt-clients { 10.53.0.7; };
// small enough to force a table expansion
min-table-size 75;
};
additional-from-cache no;
};
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"; };

View file

@ -0,0 +1,47 @@
; 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
; basic rate limiting
a1 A 192.0.2.1
; wildcards
*.a2 A 192.0.2.2
; a3 is in tld3
; a4 does not exist to give NXDOMAIN
; a5 for TCP requests
a5 A 192.0.2.5
; a6 for whitelisted clients
a6 A 192.0.2.6
; a7 for SERVFAIL
; a8 for NODATA
a8 A 192.0.2.8
; a9 for all-per-second limit
$GENERATE 101-180 all$.a9 A 192.0.2.8

View 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

View file

@ -0,0 +1,50 @@
/*
* 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;
// check that all of the options are parsed without limiting anything
rate-limit {
responses-per-second 200;
referrals-per-second 220;
nodata-per-second 230;
nxdomains-per-second 240;
errors-per-second 250;
all-per-second 700;
ipv4-prefix-length 24;
ipv6-prefix-length 64;
qps-scale 10;
window 1;
max-table-size 1000;
};
};
zone "." { type hint; file "hints"; };
zone "tld3."{ type master; file "tld3.db"; };

View 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.0.3.3

View file

@ -0,0 +1,23 @@
#!/bin/sh
#
# Copyright (C) 2010, 2012 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.
if ./rrl
then
:
else
echo "I:This test requires --enable-rrl at compile time." >&2
exit 1
fi

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 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.
*/
#include <config.h>
#include <isc/util.h>
int
main(int argc, char **argv) {
UNUSED(argc);
UNUSED(argv);
#ifdef USE_RRL
return (0);
#else
return (1);
#endif
}

View 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

View file

@ -0,0 +1,258 @@
# 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
}
# turn off ${HOME}/.digrc
HOME=/dev/null; export HOME
# $1=result name $2=domain name $3=dig options
digcmd () {
OFILE=$1; shift
DIG_DOM=$1; shift
ARGS="+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 '/^;; AUTHORITY/,/^$/d' \
-e '/^;; ADDITIONAL/,/^$/d' \
-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
}
ckstats () {
LABEL="$1"; shift
TYPE="$1"; shift
EXPECTED="$1"; shift
CNT=`sed -n -e "s/[ ]*\([0-9]*\).responses $TYPE for rate limits.*/\1/p" \
ns2/named.stats | tail -1`
CNT=`expr 0$CNT + 0`
if test "$CNT" -ne $EXPECTED; then
setret "I:wrong $LABEL $TYPE statistics of $CNT instead of $EXPECTED"
fi
}
#########
sec_start
# Tests of referrals to "." must be done before the hints are loaded
# or with "additional-from-cache no"
burst 5 a1.tld3 +norec
# 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 wildcard.
burst 30 'x$CNT.a2.tld2'
# These should be counted and limited but are not. See RT33138.
burst 10 'y.x$CNT.a2.tld2'
# IP TC drop NXDOMAIN SERVFAIL
# referrals to "."
ck_result a1.tld3 '' 2 1 2 0 0
# check 24 results including 1 second delay that allows an additional response
ck_result a1.tld2 192.0.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.0.2.2 2 10 18 0 0
# These should be limited but are not. See RT33138.
ck_result 'y.x*.a2.tld2' 192.0.2.2 10 0 0 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.0.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
$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats
ckstats first dropped 58
ckstats first truncated 30
#########
sec_start
burst 20 a5.tld2 +tcp
burst 20 a6.tld2 -b $ns7
burst 20 a7.tld4
burst 2 a8.tld2 AAAA
burst 2 a8.tld2 TXT
burst 2 a8.tld2 SPF
# TCP responses are not rate limited
ck_result a5.tld2 192.0.2.5 20 0 0 0 0
# whitelisted client is not rate limited
ck_result a6.tld2 192.0.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.0.2.1 0 6 12 0 2
# NODATA responses are counted as the same regardless of qtype.
ck_result a8.tld2 '' 2 2 2 0 0
$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats
ckstats second dropped 72
ckstats second truncated 38
#########
sec_start
# all-per-second
# The qnames are all unique but the client IP address is constant.
CNT=101
burst 80 'all$CNT.a9.tld2'
ck_result 'a*.a9.tld2' 192.0.2.8 70 0 10 0 0
$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats
ckstats final dropped 82
ckstats final truncated 38
echo "I:exit status: $ret"
# exit $ret
[ $ret -ne 0 ] && echo "I:test failure overridden"
exit 0

View file

@ -428,6 +428,9 @@ int sigwait(const unsigned int *set, int *sig);
non-blocking. */
#undef USE_FIONBIO_IOCTL
/* Enable DNS Response Rate Limiting */
#undef USE_RRL
/* define if idnkit support is to be included. */
#undef WITH_IDN

34
configure vendored
View file

@ -1331,6 +1331,8 @@ ISC_PLATFORM_NEEDSYSSELECTH
ISC_PLATFORM_HAVEDEVPOLL
ISC_PLATFORM_HAVEEPOLL
ISC_PLATFORM_HAVEKQUEUE
RRLLINKSRCS
RRLLINKOBJS
ISC_PLATFORM_HAVELIFCONF
ISC_PLATFORM_NORETURN_POST
ISC_PLATFORM_NORETURN_PRE
@ -1452,6 +1454,7 @@ enable_libbind
enable_developer
with_python
enable_newstats
enable_rrl
enable_kqueue
enable_epoll
enable_devpoll
@ -2129,7 +2132,8 @@ Optional Features:
--disable-libtool-lock avoid locking (might break parallel builds)
--enable-libbind deprecated
--enable-developer enable developer build settings
--enable-newstats use the new statistics
--enable-newstats use the new statistics
--enable-rrl use DNS Response Rate Limiting
--enable-kqueue use BSD kqueue when available [default=yes]
--enable-epoll use Linux epoll when available [default=auto]
--enable-devpoll use /dev/poll when available [default=yes]
@ -11865,6 +11869,7 @@ yes)
test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes
test "${with_atf+set}" = set || with_atf=yes
test "${enable_filter_aaaa+set}" = set || enable_filter_aaaa=yes
test "${enable_rrl+set}" = set || enable_rrl=yes
test "${with_dlz_filesystem+set}" = set || with_dlz_filesystem=yes
case "$host" in
*-darwin*)
@ -13544,6 +13549,30 @@ $as_echo "#define NEWSTATS 1" >>confdefs.h
;;
esac
#
# check if we want DNS RRL
#
# Check whether --enable-rrl was given.
if test "${enable_rrl+set}" = set; then :
enableval=$enable_rrl;
fi
case "$enable_rrl" in
yes)
$as_echo "#define USE_RRL 1" >>confdefs.h
RRLLINKOBJS='${RRLOBJS}'
RRLLINKSRCS='${RRLSRCS}'
;;
*)
RRLLINKOBJS=""
RRLLINKSRCS=""
;;
esac
#
# check if we have kqueue
#
@ -20526,7 +20555,7 @@ ac_config_commands="$ac_config_commands chmod"
# elsewhere if there's a good reason for doing so.
#
ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/rndc/Makefile bin/tests/Makefile bin/tests/atomic/Makefile bin/tests/db/Makefile bin/tests/dst/Makefile bin/tests/dst/Kdh.+002+18602.key bin/tests/dst/Kdh.+002+18602.private bin/tests/dst/Kdh.+002+48957.key bin/tests/dst/Kdh.+002+48957.private bin/tests/dst/Ktest.+001+00002.key bin/tests/dst/Ktest.+001+54622.key bin/tests/dst/Ktest.+001+54622.private bin/tests/dst/Ktest.+003+23616.key bin/tests/dst/Ktest.+003+23616.private bin/tests/dst/Ktest.+003+49667.key bin/tests/dst/dst_2_data bin/tests/dst/t2_data_1 bin/tests/dst/t2_data_2 bin/tests/dst/t2_dsasig bin/tests/dst/t2_rsasig bin/tests/hashes/Makefile bin/tests/headerdep_test.sh bin/tests/master/Makefile bin/tests/mem/Makefile bin/tests/names/Makefile bin/tests/net/Makefile bin/tests/rbt/Makefile bin/tests/resolver/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf bin/tests/system/ecdsa/prereq.sh bin/tests/system/filter-aaaa/Makefile bin/tests/system/gost/prereq.sh bin/tests/system/lwresd/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/system/tsiggss/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/check-secure-delegation.pl contrib/zone-edit.sh doc/Makefile doc/arm/Makefile doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-docbook-latex.xsl doc/xsl/isc-manpage.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/export/Makefile lib/export/dns/Makefile lib/export/dns/include/Makefile lib/export/dns/include/dns/Makefile lib/export/dns/include/dst/Makefile lib/export/irs/Makefile lib/export/irs/include/Makefile lib/export/irs/include/irs/Makefile lib/export/isc/$thread_dir/Makefile lib/export/isc/$thread_dir/include/Makefile lib/export/isc/$thread_dir/include/isc/Makefile lib/export/isc/Makefile lib/export/isc/include/Makefile lib/export/isc/include/isc/Makefile lib/export/isc/nls/Makefile lib/export/isc/unix/Makefile lib/export/isc/unix/include/Makefile lib/export/isc/unix/include/isc/Makefile lib/export/isccfg/Makefile lib/export/isccfg/include/Makefile lib/export/isccfg/include/isccfg/Makefile lib/export/samples/Makefile lib/export/samples/Makefile-postinstall lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile unit/Makefile unit/unittest.sh"
ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/rndc/Makefile bin/tests/Makefile bin/tests/atomic/Makefile bin/tests/db/Makefile bin/tests/dst/Makefile bin/tests/dst/Kdh.+002+18602.key bin/tests/dst/Kdh.+002+18602.private bin/tests/dst/Kdh.+002+48957.key bin/tests/dst/Kdh.+002+48957.private bin/tests/dst/Ktest.+001+00002.key bin/tests/dst/Ktest.+001+54622.key bin/tests/dst/Ktest.+001+54622.private bin/tests/dst/Ktest.+003+23616.key bin/tests/dst/Ktest.+003+23616.private bin/tests/dst/Ktest.+003+49667.key bin/tests/dst/dst_2_data bin/tests/dst/t2_data_1 bin/tests/dst/t2_data_2 bin/tests/dst/t2_dsasig bin/tests/dst/t2_rsasig bin/tests/hashes/Makefile bin/tests/headerdep_test.sh bin/tests/master/Makefile bin/tests/mem/Makefile bin/tests/names/Makefile bin/tests/net/Makefile bin/tests/rbt/Makefile bin/tests/resolver/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf bin/tests/system/ecdsa/prereq.sh bin/tests/system/filter-aaaa/Makefile bin/tests/system/gost/prereq.sh bin/tests/system/lwresd/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rrl/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/system/tsiggss/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/check-secure-delegation.pl contrib/zone-edit.sh doc/Makefile doc/arm/Makefile doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-docbook-latex.xsl doc/xsl/isc-manpage.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/export/Makefile lib/export/dns/Makefile lib/export/dns/include/Makefile lib/export/dns/include/dns/Makefile lib/export/dns/include/dst/Makefile lib/export/irs/Makefile lib/export/irs/include/Makefile lib/export/irs/include/irs/Makefile lib/export/isc/$thread_dir/Makefile lib/export/isc/$thread_dir/include/Makefile lib/export/isc/$thread_dir/include/isc/Makefile lib/export/isc/Makefile lib/export/isc/include/Makefile lib/export/isc/include/isc/Makefile lib/export/isc/nls/Makefile lib/export/isc/unix/Makefile lib/export/isc/unix/include/Makefile lib/export/isc/unix/include/isc/Makefile lib/export/isccfg/Makefile lib/export/isccfg/include/Makefile lib/export/isccfg/include/isccfg/Makefile lib/export/samples/Makefile lib/export/samples/Makefile-postinstall lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile unit/Makefile unit/unittest.sh"
#
@ -21574,6 +21603,7 @@ do
"bin/tests/system/gost/prereq.sh") CONFIG_FILES="$CONFIG_FILES bin/tests/system/gost/prereq.sh" ;;
"bin/tests/system/lwresd/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/lwresd/Makefile" ;;
"bin/tests/system/rpz/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rpz/Makefile" ;;
"bin/tests/system/rrl/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rrl/Makefile" ;;
"bin/tests/system/rsabigexponent/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rsabigexponent/Makefile" ;;
"bin/tests/system/tkey/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/tkey/Makefile" ;;
"bin/tests/system/tsiggss/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/tsiggss/Makefile" ;;

View file

@ -70,6 +70,7 @@ yes)
test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes
test "${with_atf+set}" = set || with_atf=yes
test "${enable_filter_aaaa+set}" = set || enable_filter_aaaa=yes
test "${enable_rrl+set}" = set || enable_rrl=yes
test "${with_dlz_filesystem+set}" = set || with_dlz_filesystem=yes
case "$host" in
*-darwin*)
@ -469,7 +470,7 @@ AC_SUBST(ISC_PLATFORM_HAVELIFCONF)
# check if we want the new statistics
#
AC_ARG_ENABLE(newstats,
[ --enable-newstats use the new statistics])
[ --enable-newstats use the new statistics])
case "$enable_newstats" in
yes)
AC_DEFINE(NEWSTATS, 1, [Use the new XML schema for statistics])
@ -478,6 +479,25 @@ yes)
;;
esac
#
# check if we want DNS RRL
#
AC_ARG_ENABLE(rrl,
[ --enable-rrl use DNS Response Rate Limiting])
case "$enable_rrl" in
yes)
AC_DEFINE(USE_RRL, 1, [Enable DNS Response Rate Limiting])
RRLLINKOBJS='${RRLOBJS}'
RRLLINKSRCS='${RRLSRCS}'
;;
*)
RRLLINKOBJS=""
RRLLINKSRCS=""
;;
esac
AC_SUBST(RRLLINKOBJS)
AC_SUBST(RRLLINKSRCS)
#
# check if we have kqueue
#
@ -3690,6 +3710,7 @@ AC_CONFIG_FILES([
bin/tests/system/gost/prereq.sh
bin/tests/system/lwresd/Makefile
bin/tests/system/rpz/Makefile
bin/tests/system/rrl/Makefile
bin/tests/system/rsabigexponent/Makefile
bin/tests/system/tkey/Makefile
bin/tests/system/tsiggss/Makefile

View file

@ -4818,6 +4818,37 @@ category notify { null; };
</para>
</entry>
</row>
<row rowsep="0">
<entry colname="1">
<para><command>rate-limit</command></para>
</entry>
<entry colname="2">
<para>
(Only available when <acronym>BIND</acronym> 9 is
configured with the <userinput>--enable-rrl</userinput>
option at compile time.)
</para>
<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>query-errors</command> category.
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
@ -5318,7 +5349,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<optional> match-mapped-addresses <replaceable>yes_or_no</replaceable>; </optional>
<optional> filter-aaaa-on-v4 ( <replaceable>yes_or_no</replaceable> | <replaceable>break-dnssec</replaceable> ); </optional>
<optional> filter-aaaa { <replaceable>address_match_list</replaceable> }; </optional>
<optional> dns64 <replaceable>IPv6-prefix</replaceable> {
<optional> dns64 <replaceable>ipv6-prefix</replaceable> {
<optional> clients { <replaceable>address_match_list</replaceable> }; </optional>
<optional> mapped { <replaceable>address_match_list</replaceable> }; </optional>
<optional> exclude { <replaceable>address_match_list</replaceable> }; </optional>
@ -5351,6 +5382,23 @@ 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> referrals-per-second <replaceable>number</replaceable> ; </optional>
<optional> nodata-per-second <replaceable>number</replaceable> ; </optional>
<optional> nxdomains-per-second <replaceable>number</replaceable> ; </optional>
<optional> errors-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 +9946,228 @@ ns.domain.com.rpz-nsdname CNAME .
<command>RPZRewrites</command> statistics.
</para>
</sect3>
<sect3>
<title>Response Rate Limiting</title>
<para>
This feature is only available when <acronym>BIND</acronym> 9
is compiled with the <userinput>--enable-rrl</userinput>
option on the "configure" command line.
</para>
<para>
Excessive almost identical UDP <emphasis>responses</emphasis>
can be controlled by configuring a
<command>rate-limit</command> clause in an
<command>options</command> or <command>view</command> statement.
This mechanism keeps authoritative BIND 9 from being used
in amplifying reflection denial of service (DoS) attacks.
Short truncated (TC=1) responses can be sent to provide
rate-limited responses to legitimate clients within
a range of forged, attacked IP addresses.
Legitimate clients react to dropped or truncated response
by retrying with UDP or with TCP respectively.
</para>
<para>
This mechanism is intended for authoritative DNS servers.
It can be used on recursive servers but can slow
applications such as SMTP servers (mail receivers) and
HTTP clients (web browsers) that repeatedly request the
same domains.
When possible, closing "open" recursive servers is better.
</para>
<para>
Response rate limiting uses a "credit" or "token bucket" scheme.
Each combination of identical response and client
has a conceptual account that earns a specified number
of credits every second.
A prospective response debits its account by one.
Responses are dropped or truncated
while the account is negative.
Responses are tracked within a rolling window of time
which defaults to 15 seconds, but can be configured with
the <command>window</command> option to any value from
1 to 3600 seconds (1 hour).
The account cannot become more positive than
the per-second limit
or more negative than <command>window</command>
times the per-second limit.
When the specified number of credits for a class of
responses is set to 0, those responses are not rate limited.
</para>
<para>
The notions of "identical response" and "DNS client"
for rate limiting are not simplistic.
All responses to an address block are counted as if to a
single client.
The prefix lengths of addresses blocks are
specified with <command>ipv4-prefix-length</command> (default 24)
and <command>ipv6-prefix-length</command> (default 56).
</para>
<para>
All non-empty responses for a valid domain name (qname)
and record type (qtype) are identical and have a limit specified
with <command>responses-per-second</command>
(default 0 or no limit).
All empty (NODATA) responses for a valid domain,
regardless of query type, are identical.
Responses in the NODATA class are limited by
<command>nodata-per-second</command>
(default <command>responses-per-second</command>).
Requests for any and all undefined subdomains of a given
valid domain result in NXDOMAIN errors, and are identical
regardless of query type.
They are limited by <command>nxdomain-per-second</command>
(default <command>responses-per-second</command>).
This controls some attacks using random names, but
can be relaxed or turned off (set to 0)
on servers that expect many legitimate
NXDOMAIN responses, such as from anti-spam blacklists.
Referrals or delegations to the server of a given
domain are identical and are limited by
<command>referrals-per-second</command>
(default <command>responses-per-second</command>).
</para>
<para>
Responses generated from local wildcards are counted and limited
as if they were for the parent domain name.
This controls flooding using random.wild.example.com.
</para>
<para>
All requests that result in DNS errors other
than NXDOMAIN, such as SERVFAIL and FORMERR, are identical
regardless of requested name (qname) or record type (qtype).
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>
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 truncated (TC=1)
response.
The small size and reduced frequency, and so lack of
amplification, of "slipped" responses make them unattractive
for reflection DoS attacks.
<command>slip</command> must be between 0 and 10.
A value of 0 does not "slip";
no truncated responses are sent due to rate limiting.
Some error responses including 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,
rather than supplementing, 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 &lt;IMG&gt; 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">
@ -14650,6 +14920,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>

View file

@ -55,6 +55,8 @@ DSTOBJS = @DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ \
dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \
gssapi_link.@O@ gssapictx.@O@ hmac_link.@O@ key.@O@
RRLOBJS = rrl.@O@
# Alphabetically
DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
cache.@O@ callbacks.@O@ clientinfo.@O@ compress.@O@ \
@ -67,14 +69,14 @@ 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@ 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@ \
version.@O@ view.@O@ xfrin.@O@ zone.@O@ zonekey.@O@ zt.@O@
OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS}
OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} @RRLLINKOBJS@
# Alphabetically
OPENSSLGOSTLINKSRCS = opensslgost_link.c
@ -101,7 +103,9 @@ DNSSRCS = acache.c acl.c adb.c byaddr.c \
tsec.c tsig.c ttl.c update.c validator.c \
version.c view.c xfrin.c zone.c zonekey.c zt.c ${OTHERSRCS}
SRCS = ${DSTSRCS} ${DNSSRCS}
RRLSRCS = rrl.c
SRCS = ${DSTSRCS} ${DNSSRCS} @RRLLINKSRCS@
SUBDIRS = include
TARGETS = include/dns/enumtype.h include/dns/enumclass.h \

View file

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

278
lib/dns/include/dns/rrl.h Normal file
View file

@ -0,0 +1,278 @@
/*
* Copyright (C) 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_REFERRAL,
DNS_RRL_RTYPE_NODATA,
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 :4; /* 3 bits + sign bit */
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;
};
typedef struct dns_rrl_rate dns_rrl_rate_t;
struct dns_rrl_rate {
int r;
int scaled;
const char *str;
};
/*
* 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;
dns_rrl_rate_t responses_per_second;
dns_rrl_rate_t referrals_per_second;
dns_rrl_rate_t nodata_per_second;
dns_rrl_rate_t nxdomains_per_second;
dns_rrl_rate_t errors_per_second;
dns_rrl_rate_t all_per_second;
dns_rrl_rate_t slip;
int window;
double qps_scale;
int max_entries;
dns_acl_t *exempt;
int num_entries;
int qps_responses;
isc_stdtime_t qps_time;
double qps;
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 */

View file

@ -73,6 +73,7 @@
#include <dns/acl.h>
#include <dns/fixedname.h>
#include <dns/rrl.h>
#include <dns/rdatastruct.h>
#include <dns/rpz.h>
#include <dns/types.h>
@ -142,6 +143,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;

View file

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

1324
lib/dns/rrl.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -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;
@ -335,10 +337,16 @@ destroy(dns_view_t *view) {
dns_acache_detach(&view->acache);
}
dns_rpz_view_destroy(view);
#else
#ifdef USE_RRL
dns_rrl_view_destroy(view);
#else /* USE_RRL */
INSIST(view->rrl == NULL);
#endif /* USE_RRL */
#else /* BIND9 */
INSIST(view->acache == NULL);
INSIST(ISC_LIST_EMPTY(view->rpz_zones));
#endif
INSIST(view->rrl == NULL);
#endif /* BIND9 */
if (view->requestmgr != NULL)
dns_requestmgr_detach(&view->requestmgr);
if (view->task != NULL)

View file

@ -657,6 +657,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

View file

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

View 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

View file

@ -1269,6 +1269,39 @@ static cfg_type_t cfg_type_rpz = {
rpz_fields
};
#ifdef USE_RRL
/*
* rate-limit
*/
static cfg_clausedef_t rrl_clauses[] = {
{ "responses-per-second", &cfg_type_uint32, 0 },
{ "referrals-per-second", &cfg_type_uint32, 0 },
{ "nodata-per-second", &cfg_type_uint32, 0 },
{ "nxdomains-per-second", &cfg_type_uint32, 0 },
{ "errors-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
};
#endif /* USE_RRL */
/*%
* dnssec-lookaside
@ -1423,6 +1456,9 @@ view_clauses[] = {
CFG_CLAUSEFLAG_NOTCONFIGURED },
#endif
{ "response-policy", &cfg_type_rpz, 0 },
#ifdef USE_RRL
{ "rate-limit", &cfg_type_rrl, 0 },
#endif /* USE_RRL */
{ NULL, NULL, 0 }
};