2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 18:19:42 +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:
Evan Hunt 2013-02-25 10:49:30 -08:00
parent 261ef37955
commit 55e5c51e66
34 changed files with 2874 additions and 8 deletions

View File

@ -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, 3493. [contrib] Added BDBHPT dynamically-lodable DLZ module,
contributed by Mark Goldfinch. [RT #32549] contributed by Mark Goldfinch. [RT #32549]

View File

@ -1000,6 +1000,11 @@ client_send(ns_client_t *client) {
} }
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto done; 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, result = dns_message_rendersection(client->message,
DNS_SECTION_ANSWER, DNS_SECTION_ANSWER,
DNS_MESSAGERENDER_PARTIAL | DNS_MESSAGERENDER_PARTIAL |
@ -1205,6 +1210,49 @@ ns_client_error(ns_client_t *client, isc_result_t result) {
} }
#endif #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 * 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 * with, in which case QR will be set. We need to clear QR before

View File

@ -227,6 +227,13 @@ view \"_bind\" chaos {\n\
recursion no;\n\ recursion no;\n\
notify no;\n\ notify no;\n\
allow-new-zones 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\ \n\
zone \"version.bind\" chaos {\n\ zone \"version.bind\" chaos {\n\
type master;\n\ type master;\n\

View File

@ -85,6 +85,7 @@ struct ns_query {
#define NS_QUERYATTR_CACHEACLOK 0x2000 #define NS_QUERYATTR_CACHEACLOK 0x2000
#define NS_QUERYATTR_DNS64 0x4000 #define NS_QUERYATTR_DNS64 0x4000
#define NS_QUERYATTR_DNS64EXCLUDE 0x8000 #define NS_QUERYATTR_DNS64EXCLUDE 0x8000
#define NS_QUERYATTR_RRL_CHECKED 0x10000
isc_result_t isc_result_t

View File

@ -169,7 +169,10 @@ enum {
dns_nsstatscounter_dns64 = 37, dns_nsstatscounter_dns64 = 37,
dns_nsstatscounter_max = 38 dns_nsstatscounter_ratedropped = 38,
dns_nsstatscounter_rateslipped = 39,
dns_nsstatscounter_max = 40
}; };
void void

View File

@ -5857,6 +5857,105 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
resume: resume:
CTRACE("query_find: 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) && if (!ISC_LIST_EMPTY(client->view->rpz_zones) &&
(RECURSIONOK(client) || !client->view->rpz_recursive_only) && (RECURSIONOK(client) || !client->view->rpz_recursive_only) &&
rpz_ck_dnssec(client, result, rdataset, sigrdataset) && 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 && 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) { if (eresult == DNS_R_DUPLICATE || eresult == DNS_R_DROP) {
/* /*
* This was a duplicate query that we are * This was a duplicate query that we are
* recursing on. Don't send a response now. * recursing on or the result of rate limiting.
* The original query will still cause a response. * Don't send a response now for a duplicate query,
* because the original will still cause a response.
*/ */
query_next(client, eresult); query_next(client, eresult);
} else { } else {

View File

@ -1678,6 +1678,199 @@ configure_rpz(dns_view_t *view, const cfg_listelt_t *element,
return (result); 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' * Configure 'view' according to 'vconfig', taking defaults from 'config'
* where values are missing in 'vconfig'. * 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; result = ISC_R_SUCCESS;
cleanup: cleanup:

View File

@ -207,6 +207,10 @@ init_desc(void) {
SET_NSSTATDESC(recursclients, "recursing clients", SET_NSSTATDESC(recursclients, "recursing clients",
"RecursClients"); "RecursClients");
SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64"); 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); INSIST(i == dns_nsstatscounter_max);
/* Initialize resolver statistics */ /* Initialize resolver statistics */

View File

@ -17,6 +17,7 @@ involving a different DNS setup. They are:
nsupdate/ Dynamic update and IXFR tests nsupdate/ Dynamic update and IXFR tests
resolver/ Regression tests for resolver bugs that have been fixed resolver/ Regression tests for resolver bugs that have been fixed
(not a complete resolver test suite) (not a complete resolver test suite)
rrl/ query rate limiting
rpz/ Tests of response policy zone (RPZ) rewriting rpz/ Tests of response policy zone (RPZ) rewriting
stub/ Tests of stub zone functionality stub/ Tests of stub zone functionality
unknown/ Unknown type and class tests unknown/ Unknown type and class tests

View File

@ -61,7 +61,7 @@ SUBDIRS="acl additional allow_query addzone autosign builtin
dsdigest ecdsa formerr forward glue gost ixfr inline limits dsdigest ecdsa formerr forward glue gost ixfr inline limits
logfileconfig lwresd masterfile masterformat metadata logfileconfig lwresd masterfile masterformat metadata
notify nsupdate pending pkcs11 redirect resolver rndc rpz 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 statistics stub tkey tsig tsiggss unknown upforwd verify
views wildcard xfer xferquota zonechecks" views wildcard xfer xferquota zonechecks"

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

@ -0,0 +1 @@
flood

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

View 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

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

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

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

View File

@ -4826,6 +4826,34 @@ category notify { null; };
</para> </para>
</entry> </entry>
</row> </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> </tbody>
</tgroup> </tgroup>
</informaltable> </informaltable>
@ -5361,6 +5389,21 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<optional> resolver-query-timeout <replaceable>number</replaceable> ; </optional> <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-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> 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> response-policy { <replaceable>zone_name</replaceable>
<optional> policy given | disabled | passthru | nxdomain | nodata | cname <replaceable>domain</replaceable> </optional> <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> ; <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. have a maximum QPS rate about 50% lower.
</para> </para>
</sect3> </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 &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>
<sect2 id="server_statement_grammar"> <sect2 id="server_statement_grammar">
@ -14577,6 +14829,32 @@ HOST-127.EXAMPLE. MX 0 .
</para> </para>
</entry> </entry>
</row> </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> </tbody>
</tgroup> </tgroup>
</informaltable> </informaltable>

View File

@ -70,8 +70,8 @@ DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
portlist.@O@ private.@O@ \ portlist.@O@ private.@O@ \
rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \ rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \
rdatalist.@O@ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ \ rdatalist.@O@ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ \
request.@O@ resolver.@O@ result.@O@ rootns.@O@ rpz.@O@ \ request.@O@ resolver.@O@ result.@O@ rootns.@O@ \
rriterator.@O@ sdb.@O@ \ rpz.@O@ rrl.@O@ rriterator.@O@ sdb.@O@ \
sdlz.@O@ soa.@O@ ssu.@O@ ssu_external.@O@ \ sdlz.@O@ soa.@O@ ssu.@O@ ssu_external.@O@ \
stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \ stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \
tsec.@O@ tsig.@O@ ttl.@O@ update.@O@ validator.@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 \ 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 \ rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c rdatalist.c \
rdataset.c rdatasetiter.c rdataslab.c request.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 \ sdb.c sdlz.c soa.c ssu.c ssu_external.c \
stats.c tcpmsg.c time.c timer.c tkey.c \ stats.c tcpmsg.c time.c timer.c tkey.c \
tsec.c tsig.c ttl.c update.c validator.c \ tsec.c tsig.c ttl.c update.c validator.c \

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_DELEGATION_ONLY (&dns_categories[10])
#define DNS_LOGCATEGORY_EDNS_DISABLED (&dns_categories[11]) #define DNS_LOGCATEGORY_EDNS_DISABLED (&dns_categories[11])
#define DNS_LOGCATEGORY_RPZ (&dns_categories[12]) #define DNS_LOGCATEGORY_RPZ (&dns_categories[12])
#define DNS_LOGCATEGORY_RRL (&dns_categories[13])
/* Backwards compatibility. */ /* Backwards compatibility. */
#define DNS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL #define DNS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL

273
lib/dns/include/dns/rrl.h Normal file
View 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 */

View File

@ -74,6 +74,7 @@
#include <dns/acl.h> #include <dns/acl.h>
#include <dns/clientinfo.h> #include <dns/clientinfo.h>
#include <dns/fixedname.h> #include <dns/fixedname.h>
#include <dns/rrl.h>
#include <dns/rdatastruct.h> #include <dns/rdatastruct.h>
#include <dns/rpz.h> #include <dns/rpz.h>
#include <dns/types.h> #include <dns/types.h>
@ -143,6 +144,7 @@ struct dns_view {
dns_rbt_t * answeracl_exclude; dns_rbt_t * answeracl_exclude;
dns_rbt_t * denyanswernames; dns_rbt_t * denyanswernames;
dns_rbt_t * answernames_exclude; dns_rbt_t * answernames_exclude;
dns_rrl_t * rrl;
isc_boolean_t provideixfr; isc_boolean_t provideixfr;
isc_boolean_t requestnsid; isc_boolean_t requestnsid;
dns_ttl_t maxcachettl; dns_ttl_t maxcachettl;

View File

@ -45,6 +45,7 @@ LIBDNS_EXTERNAL_DATA isc_logcategory_t dns_categories[] = {
{ "delegation-only", 0 }, { "delegation-only", 0 },
{ "edns-disabled", 0 }, { "edns-disabled", 0 },
{ "rpz", 0 }, { "rpz", 0 },
{ "rate-limit", 0 },
{ NULL, 0 } { NULL, 0 }
}; };

1328
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/masterdump.h>
#include <dns/order.h> #include <dns/order.h>
#include <dns/peer.h> #include <dns/peer.h>
#include <dns/rrl.h>
#include <dns/rbt.h> #include <dns/rbt.h>
#include <dns/rdataset.h> #include <dns/rdataset.h>
#include <dns/request.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->answeracl_exclude = NULL;
view->denyanswernames = NULL; view->denyanswernames = NULL;
view->answernames_exclude = NULL; view->answernames_exclude = NULL;
view->rrl = NULL;
view->provideixfr = ISC_TRUE; view->provideixfr = ISC_TRUE;
view->maxcachettl = 7 * 24 * 3600; view->maxcachettl = 7 * 24 * 3600;
view->maxncachettl = 3 * 3600; view->maxncachettl = 3 * 3600;
@ -336,6 +338,8 @@ destroy(dns_view_t *view) {
dns_acache_detach(&view->acache); dns_acache_detach(&view->acache);
} }
dns_rpz_view_destroy(view); dns_rpz_view_destroy(view);
dns_rrl_view_destroy(view);
for (dlzdb = ISC_LIST_HEAD(view->dlz_searched); for (dlzdb = ISC_LIST_HEAD(view->dlz_searched);
dlzdb != NULL; dlzdb != NULL;
dlzdb = ISC_LIST_HEAD(view->dlz_searched)) { 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->rpz_zones));
INSIST(ISC_LIST_EMPTY(view->dlz_searched)); INSIST(ISC_LIST_EMPTY(view->dlz_searched));
INSIST(ISC_LIST_EMPTY(view->dlz_unsearched)); INSIST(ISC_LIST_EMPTY(view->dlz_unsearched));
INSIST(view->rrl == NULL);
#endif #endif
if (view->requestmgr != NULL) if (view->requestmgr != NULL)
dns_requestmgr_detach(&view->requestmgr); dns_requestmgr_detach(&view->requestmgr);

View File

@ -667,6 +667,9 @@ dns_rriterator_init
dns_rriterator_next dns_rriterator_next
dns_rriterator_nextrrset dns_rriterator_nextrrset
dns_rriterator_pause dns_rriterator_pause
dns_rrl
dns_rrl_init
dns_rrl_view_destroy
dns_sdb_putnamedrr dns_sdb_putnamedrr
dns_sdb_putrdata dns_sdb_putrdata
dns_sdb_putrr dns_sdb_putrr

View File

@ -346,6 +346,10 @@ SOURCE=..\include\dns\rpz.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\include\dns\rrl.h
# End Source File
# Begin Source File
SOURCE=..\include\dns\rriterator.h SOURCE=..\include\dns\rriterator.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -650,6 +654,10 @@ SOURCE=..\rpz.c
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\rrl.c
# End Source File
# Begin Source File
SOURCE=..\rriterator.c SOURCE=..\rriterator.c
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -184,6 +184,7 @@ CLEAN :
-@erase "$(INTDIR)\result.obj" -@erase "$(INTDIR)\result.obj"
-@erase "$(INTDIR)\rootns.obj" -@erase "$(INTDIR)\rootns.obj"
-@erase "$(INTDIR)\rpz.obj" -@erase "$(INTDIR)\rpz.obj"
-@erase "$(INTDIR)\rrl.obj"
-@erase "$(INTDIR)\sdb.obj" -@erase "$(INTDIR)\sdb.obj"
-@erase "$(INTDIR)\sdlz.obj" -@erase "$(INTDIR)\sdlz.obj"
-@erase "$(INTDIR)\soa.obj" -@erase "$(INTDIR)\soa.obj"
@ -309,6 +310,7 @@ LINK32_OBJS= \
"$(INTDIR)\result.obj" \ "$(INTDIR)\result.obj" \
"$(INTDIR)\rootns.obj" \ "$(INTDIR)\rootns.obj" \
"$(INTDIR)\rpz.obj" \ "$(INTDIR)\rpz.obj" \
"$(INTDIR)\rrl.obj" \
"$(INTDIR)\rriterator.obj" \ "$(INTDIR)\rriterator.obj" \
"$(INTDIR)\sdb.obj" \ "$(INTDIR)\sdb.obj" \
"$(INTDIR)\sdlz.obj" \ "$(INTDIR)\sdlz.obj" \
@ -505,6 +507,8 @@ CLEAN :
-@erase "$(INTDIR)\rootns.sbr" -@erase "$(INTDIR)\rootns.sbr"
-@erase "$(INTDIR)\rpz.obj" -@erase "$(INTDIR)\rpz.obj"
-@erase "$(INTDIR)\rpz.sbr" -@erase "$(INTDIR)\rpz.sbr"
-@erase "$(INTDIR)\rrl.obj"
-@erase "$(INTDIR)\rrl.sbr"
-@erase "$(INTDIR)\rriterator.obj" -@erase "$(INTDIR)\rriterator.obj"
-@erase "$(INTDIR)\rriterator.sbr" -@erase "$(INTDIR)\rriterator.sbr"
-@erase "$(INTDIR)\sdb.obj" -@erase "$(INTDIR)\sdb.obj"
@ -651,6 +655,7 @@ BSC32_SBRS= \
"$(INTDIR)\result.sbr" \ "$(INTDIR)\result.sbr" \
"$(INTDIR)\rootns.sbr" \ "$(INTDIR)\rootns.sbr" \
"$(INTDIR)\rpz.sbr" \ "$(INTDIR)\rpz.sbr" \
"$(INTDIR)\rrl.sbr" \
"$(INTDIR)\rriterator.sbr" \ "$(INTDIR)\rriterator.sbr" \
"$(INTDIR)\sdb.sbr" \ "$(INTDIR)\sdb.sbr" \
"$(INTDIR)\sdlz.sbr" \ "$(INTDIR)\sdlz.sbr" \
@ -748,6 +753,7 @@ LINK32_OBJS= \
"$(INTDIR)\result.obj" \ "$(INTDIR)\result.obj" \
"$(INTDIR)\rootns.obj" \ "$(INTDIR)\rootns.obj" \
"$(INTDIR)\rpz.obj" \ "$(INTDIR)\rpz.obj" \
"$(INTDIR)\rrl.obj" \
"$(INTDIR)\rriterator.obj" \ "$(INTDIR)\rriterator.obj" \
"$(INTDIR)\sdb.obj" \ "$(INTDIR)\sdb.obj" \
"$(INTDIR)\sdlz.obj" \ "$(INTDIR)\sdlz.obj" \
@ -1724,6 +1730,24 @@ SOURCE=..\rpz.c
$(CPP) $(CPP_PROJ) $(SOURCE) $(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 !ENDIF
SOURCE=..\rriterator.c SOURCE=..\rriterator.c

View File

@ -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 * dnssec-lookaside
*/ */
@ -1417,6 +1450,7 @@ view_clauses[] = {
CFG_CLAUSEFLAG_NOTCONFIGURED }, CFG_CLAUSEFLAG_NOTCONFIGURED },
#endif #endif
{ "response-policy", &cfg_type_rpz, 0 }, { "response-policy", &cfg_type_rpz, 0 },
{ "rate-limit", &cfg_type_rrl, 0 },
{ NULL, NULL, 0 } { NULL, NULL, 0 }
}; };