mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 03:59:59 -04:00
[master] fixed several RRL issues
3554. [bug] RRL failed to correctly rate-limit upward referrals and failed to count dropped error responses in the statistics. [RT #33225]
This commit is contained in:
parent
330f98fe3b
commit
a6d43d18b1
13 changed files with 365 additions and 323 deletions
4
CHANGES
4
CHANGES
|
|
@ -1,3 +1,7 @@
|
|||
3554. [bug] RRL failed to correctly rate-limit upward
|
||||
referrals and failed to count dropped error
|
||||
responses in the statistics. [RT #33225]
|
||||
|
||||
3553. [bug] Address suspected double free in acache. [RT #33252]
|
||||
|
||||
3552. [bug] Wrong getopt option string for 'nsupdate -r'.
|
||||
|
|
|
|||
|
|
@ -1257,11 +1257,13 @@ ns_client_error(ns_client_t *client, isc_result_t result) {
|
|||
}
|
||||
/*
|
||||
* Some error responses cannot be 'slipped',
|
||||
* so don't try.
|
||||
* This will counted with dropped queries in the
|
||||
* QryDropped counter.
|
||||
* 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ inc_stats(ns_client_t *client, isc_statscounter_t counter) {
|
|||
|
||||
/* 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) {
|
||||
|
|
@ -6246,7 +6246,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
|
|||
* Rate limit these responses to this client.
|
||||
*/
|
||||
if (client->view->rrl != NULL &&
|
||||
fname != NULL && dns_name_isabsolute(fname) &&
|
||||
((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;
|
||||
|
|
@ -6289,8 +6290,19 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1835,7 +1835,7 @@ configure_rpz(dns_view_t *view, const cfg_obj_t *rpz_obj,
|
|||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
#define CHECK_RRL(obj, cond, pat, val1, val2) \
|
||||
#define CHECK_RRL(cond, pat, val1, val2) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, \
|
||||
|
|
@ -1845,6 +1845,22 @@ configure_rpz(dns_view_t *view, const cfg_obj_t *rpz_obj,
|
|||
} \
|
||||
} 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;
|
||||
|
|
@ -1875,86 +1891,39 @@ configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
|
|||
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,
|
||||
CHECK_RRL(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;
|
||||
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");
|
||||
|
||||
/*
|
||||
* 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;
|
||||
CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE,
|
||||
"all-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;
|
||||
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(obj, i >= 1 && i <= DNS_RRL_MAX_WINDOW,
|
||||
CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
|
||||
"window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
|
||||
}
|
||||
rrl->window = i;
|
||||
|
|
@ -1964,18 +1933,18 @@ configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
|
|||
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, "");
|
||||
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);
|
||||
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, "");
|
||||
CHECK_RRL(i >= 8 && i <= 32,
|
||||
"invalid 'ipv4-prefix-length %d'%s", i, "");
|
||||
}
|
||||
rrl->ipv4_prefixlen = i;
|
||||
if (i == 32)
|
||||
|
|
@ -1985,11 +1954,11 @@ configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
|
|||
|
||||
i = 56;
|
||||
obj = NULL;
|
||||
result = cfg_map_get(map, "IPv6-prefix-length", &obj);
|
||||
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",
|
||||
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;
|
||||
|
|
@ -2010,7 +1979,7 @@ configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
|
|||
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,
|
||||
CHECK_RRL(result == ISC_R_SUCCESS,
|
||||
"invalid %s%s", "address match list", "");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,5 +17,5 @@
|
|||
# Clean up after rrl tests.
|
||||
|
||||
rm -f dig.out*
|
||||
rm -f */named.memstats */named.run */named.stats */log */session.key
|
||||
rm -f */named.memstats */named.run */named.stats */log-* */session.key
|
||||
rm -f ns3/bl*.db */*.jnl */*.core */*.pid
|
||||
|
|
|
|||
|
|
@ -32,15 +32,14 @@ options {
|
|||
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;
|
||||
|
||||
// small enough to force a table expansion
|
||||
min-table-size 75;
|
||||
};
|
||||
|
||||
additional-from-cache no;
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
|
|
|
|||
|
|
@ -22,8 +22,10 @@ $TTL 120
|
|||
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
|
||||
|
|
@ -38,5 +40,8 @@ a6 A 192.0.2.6
|
|||
|
||||
; a7 for SERVFAIL
|
||||
|
||||
; a8 for all-per-second limit
|
||||
$GENERATE 101-180 all$.a8 A 192.0.2.8
|
||||
; 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
|
||||
|
|
|
|||
|
|
@ -27,6 +27,22 @@ options {
|
|||
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"; };
|
||||
|
|
|
|||
|
|
@ -64,15 +64,20 @@ sec_start () {
|
|||
}
|
||||
|
||||
|
||||
# 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="+noadd +noauth +nosearch +time=1 +tries=1 +ignore $* -p 5300 $DIG_DOM @$ns2"
|
||||
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 's/^[^;].* \([^ ]\{1,\}\)$/\1/p' \
|
||||
| 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' \
|
||||
|
|
@ -117,7 +122,7 @@ ck_result() {
|
|||
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"
|
||||
setret "I:$ADDRS instead of $3 '$2' responses for $1"
|
||||
BAD=yes
|
||||
fi
|
||||
if test $TC -ne "$4"; then
|
||||
|
|
@ -142,26 +147,47 @@ ck_result() {
|
|||
}
|
||||
|
||||
|
||||
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 wild card
|
||||
# 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
|
||||
# check for 24 results
|
||||
# including the 1 second delay
|
||||
# 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
|
||||
|
|
@ -178,6 +204,10 @@ 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
|
||||
|
|
@ -185,6 +215,9 @@ 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
|
||||
|
|
@ -196,6 +229,13 @@ ck_result a6.tld2 192.0.2.6 20 0 0 0 0
|
|||
# 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
|
||||
|
|
@ -203,23 +243,14 @@ 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.0.2.8 70 0 10 0 0
|
||||
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 () {
|
||||
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
|
||||
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
|
||||
exit $ret
|
||||
|
|
|
|||
|
|
@ -5449,7 +5449,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
|
|||
<optional> filter-aaaa-on-v4 ( <replaceable>yes_or_no</replaceable> | <replaceable>break-dnssec</replaceable> ); </optional>
|
||||
<optional> filter-aaaa-on-v6 ( <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>
|
||||
|
|
@ -5487,14 +5487,16 @@ badresp:1,adberr:0,findfail:0,valfail:0]
|
|||
<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> 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> 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>
|
||||
|
|
@ -10089,61 +10091,95 @@ ns.domain.com.rpz-nsdname CNAME .
|
|||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Rate Limiting</title>
|
||||
<title>Response Rate Limiting</title>
|
||||
<para>
|
||||
Excessive essentially identical UDP <emphasis>responses</emphasis>
|
||||
can be discarded by configuring a
|
||||
Excessive almost identical UDP <emphasis>responses</emphasis>
|
||||
can be controlled 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.
|
||||
<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>
|
||||
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.
|
||||
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>
|
||||
<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.
|
||||
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 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.
|
||||
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
|
||||
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.
|
||||
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
|
||||
|
|
@ -10152,33 +10188,6 @@ ns.domain.com.rpz-nsdname CNAME .
|
|||
<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.
|
||||
|
|
@ -10188,14 +10197,15 @@ ns.domain.com.rpz-nsdname CNAME .
|
|||
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
|
||||
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>
|
||||
|
|
@ -10225,8 +10235,8 @@ ns.domain.com.rpz-nsdname CNAME .
|
|||
<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>
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -71,7 +71,8 @@ typedef struct dns_rrl_hash dns_rrl_hash_t;
|
|||
typedef enum {
|
||||
DNS_RRL_RTYPE_FREE = 0,
|
||||
DNS_RRL_RTYPE_QUERY,
|
||||
DNS_RRL_RTYPE_DELEGATION,
|
||||
DNS_RRL_RTYPE_REFERRAL,
|
||||
DNS_RRL_RTYPE_NODATA,
|
||||
DNS_RRL_RTYPE_NXDOMAIN,
|
||||
DNS_RRL_RTYPE_ERROR,
|
||||
DNS_RRL_RTYPE_ALL,
|
||||
|
|
@ -190,6 +191,13 @@ struct dns_rrl_qname_buf {
|
|||
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.
|
||||
*/
|
||||
|
|
@ -199,12 +207,14 @@ struct dns_rrl {
|
|||
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;
|
||||
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;
|
||||
int slip;
|
||||
double qps_scale;
|
||||
int max_entries;
|
||||
|
||||
|
|
@ -215,11 +225,6 @@ struct dns_rrl {
|
|||
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;
|
||||
|
|
|
|||
214
lib/dns/rrl.c
214
lib/dns/rrl.c
|
|
@ -167,11 +167,11 @@ set_age(dns_rrl_t *rrl, dns_rrl_entry_t *e, isc_stdtime_t now) {
|
|||
if (ts >= DNS_RRL_MAX_TS) {
|
||||
ts_gen = (ts_gen + 1) % DNS_RRL_TS_BASES;
|
||||
for (e_old = ISC_LIST_TAIL(rrl->lru), i = 0;
|
||||
e_old != NULL && e_old->ts_gen == ts_gen;
|
||||
e_old != NULL && (e_old->ts_gen == ts_gen ||
|
||||
!ISC_LINK_LINKED(e_old, hlink));
|
||||
e_old = ISC_LIST_PREV(e_old, lru), ++i)
|
||||
{
|
||||
if (e_old->ts_valid)
|
||||
e_old->ts_valid = ISC_FALSE;
|
||||
e_old->ts_valid = ISC_FALSE;
|
||||
}
|
||||
if (i != 0)
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
|
||||
|
|
@ -403,9 +403,16 @@ make_key(const dns_rrl_t *rrl, dns_rrl_key_t *key,
|
|||
memset(key, 0, sizeof(*key));
|
||||
|
||||
key->s.rtype = rtype;
|
||||
if (rtype == DNS_RRL_RTYPE_QUERY || rtype == DNS_RRL_RTYPE_DELEGATION) {
|
||||
key->s.qclass = qclass & 0xff;
|
||||
if (rtype == DNS_RRL_RTYPE_QUERY) {
|
||||
key->s.qtype = qtype;
|
||||
key->s.qclass = qclass & 0xff;
|
||||
} else if (rtype == DNS_RRL_RTYPE_REFERRAL ||
|
||||
rtype == DNS_RRL_RTYPE_NODATA) {
|
||||
/*
|
||||
* Because there is no qtype in the empty answer sections of
|
||||
* referral and NODATA responses, count them as the same.
|
||||
*/
|
||||
key->s.qclass = qclass & 0xff;
|
||||
}
|
||||
|
||||
if (qname != NULL && qname->labels != 0) {
|
||||
|
|
@ -440,33 +447,40 @@ make_key(const dns_rrl_t *rrl, dns_rrl_key_t *key,
|
|||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
response_balance(const dns_rrl_t *rrl, const dns_rrl_entry_t *e, int age) {
|
||||
int balance, rate = 0;
|
||||
|
||||
balance = e->responses;
|
||||
if (balance < 0)
|
||||
switch (e->key.s.rtype) {
|
||||
case DNS_RRL_RTYPE_QUERY:
|
||||
case DNS_RRL_RTYPE_DELEGATION:
|
||||
rate = rrl->scaled_responses_per_second;
|
||||
break;
|
||||
case DNS_RRL_RTYPE_NXDOMAIN:
|
||||
rate = rrl->scaled_nxdomains_per_second;
|
||||
break;
|
||||
case DNS_RRL_RTYPE_ERROR:
|
||||
rate = rrl->scaled_errors_per_second;
|
||||
break;
|
||||
case DNS_RRL_RTYPE_ALL:
|
||||
rate = rrl->scaled_all_per_second;
|
||||
break;
|
||||
case DNS_RRL_RTYPE_TCP:
|
||||
rate = 1;
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
static inline dns_rrl_rate_t *
|
||||
get_rate(dns_rrl_t *rrl, dns_rrl_rtype_t rtype) {
|
||||
switch (rtype) {
|
||||
case DNS_RRL_RTYPE_QUERY:
|
||||
return (&rrl->responses_per_second);
|
||||
case DNS_RRL_RTYPE_REFERRAL:
|
||||
return (&rrl->referrals_per_second);
|
||||
case DNS_RRL_RTYPE_NODATA:
|
||||
return (&rrl->nodata_per_second);
|
||||
case DNS_RRL_RTYPE_NXDOMAIN:
|
||||
return (&rrl->nxdomains_per_second);
|
||||
case DNS_RRL_RTYPE_ERROR:
|
||||
return (&rrl->errors_per_second);
|
||||
case DNS_RRL_RTYPE_ALL:
|
||||
return (&rrl->all_per_second);
|
||||
default:
|
||||
INSIST(0);
|
||||
}
|
||||
balance += age * rate;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
response_balance(dns_rrl_t *rrl, const dns_rrl_entry_t *e, int age) {
|
||||
dns_rrl_rate_t *ratep;
|
||||
int balance, rate;
|
||||
|
||||
if (e->key.s.rtype == DNS_RRL_RTYPE_TCP) {
|
||||
rate = 1;
|
||||
} else {
|
||||
ratep = get_rate(rrl, e->key.s.rtype);
|
||||
rate = ratep->scaled;
|
||||
}
|
||||
|
||||
balance = e->responses + age * rate;
|
||||
if (balance > rate)
|
||||
balance = rate;
|
||||
return (balance);
|
||||
|
|
@ -551,7 +565,7 @@ get_entry(dns_rrl_t *rrl, const isc_sockaddr_t *client_addr,
|
|||
e = NULL;
|
||||
break;
|
||||
}
|
||||
if (!e->logged && response_balance(rrl, e, age) >= 0)
|
||||
if (!e->logged && response_balance(rrl, e, age) > 0)
|
||||
break;
|
||||
}
|
||||
if (e == NULL) {
|
||||
|
|
@ -598,35 +612,16 @@ debit_rrl_entry(dns_rrl_t *rrl, dns_rrl_entry_t *e, double qps, double scale,
|
|||
const isc_sockaddr_t *client_addr, isc_stdtime_t now,
|
||||
char *log_buf, unsigned int log_buf_len)
|
||||
{
|
||||
int rate, new_rate, *ratep, slip, new_slip, age, log_secs, min;
|
||||
const char *rate_str = NULL;
|
||||
int rate, new_rate, slip, new_slip, age, log_secs, min;
|
||||
dns_rrl_rate_t *ratep;
|
||||
dns_rrl_entry_t const *credit_e;
|
||||
|
||||
/*
|
||||
* Pick the rate counter.
|
||||
* Optionally adjust the rate by the estimated query/second rate.
|
||||
*/
|
||||
switch (e->key.s.rtype) {
|
||||
case DNS_RRL_RTYPE_QUERY:
|
||||
case DNS_RRL_RTYPE_DELEGATION:
|
||||
rate = rrl->responses_per_second;
|
||||
ratep = &rrl->scaled_responses_per_second;
|
||||
break;
|
||||
case DNS_RRL_RTYPE_NXDOMAIN:
|
||||
rate = rrl->nxdomains_per_second;
|
||||
ratep = &rrl->scaled_nxdomains_per_second;
|
||||
break;
|
||||
case DNS_RRL_RTYPE_ERROR:
|
||||
rate = rrl->errors_per_second;
|
||||
ratep = &rrl->scaled_errors_per_second;
|
||||
break;
|
||||
case DNS_RRL_RTYPE_ALL:
|
||||
rate = rrl->all_per_second;
|
||||
ratep = &rrl->scaled_all_per_second;
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
}
|
||||
ratep = get_rate(rrl, e->key.s.rtype);
|
||||
rate = ratep->r;
|
||||
if (rate == 0)
|
||||
return (DNS_RRL_RESULT_OK);
|
||||
|
||||
|
|
@ -648,36 +643,16 @@ debit_rrl_entry(dns_rrl_t *rrl, dns_rrl_entry_t *e, double qps, double scale,
|
|||
new_rate = (int) (rate * scale);
|
||||
if (new_rate < 1)
|
||||
new_rate = 1;
|
||||
if (*ratep != new_rate) {
|
||||
if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG1)) {
|
||||
switch (e->key.s.rtype) {
|
||||
case DNS_RRL_RTYPE_QUERY:
|
||||
case DNS_RRL_RTYPE_DELEGATION:
|
||||
rate_str = "responses-per-second";
|
||||
break;
|
||||
case DNS_RRL_RTYPE_NXDOMAIN:
|
||||
rate_str = "nxdomains-per-second";
|
||||
break;
|
||||
case DNS_RRL_RTYPE_ERROR:
|
||||
rate_str = "errors-per-second";
|
||||
break;
|
||||
case DNS_RRL_RTYPE_ALL:
|
||||
rate_str = "all-per-second";
|
||||
break;
|
||||
case DNS_RRL_RTYPE_FREE:
|
||||
case DNS_RRL_RTYPE_TCP:
|
||||
INSIST(0);
|
||||
}
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
|
||||
DNS_LOGMODULE_REQUEST,
|
||||
DNS_RRL_LOG_DEBUG1,
|
||||
"%d qps scaled %s by %.2f"
|
||||
" from %d to %d",
|
||||
(int)qps, rate_str, scale,
|
||||
rate, new_rate);
|
||||
}
|
||||
if (ratep->scaled != new_rate) {
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
|
||||
DNS_LOGMODULE_REQUEST,
|
||||
DNS_RRL_LOG_DEBUG1,
|
||||
"%d qps scaled %s by %.2f"
|
||||
" from %d to %d",
|
||||
(int)qps, ratep->str, scale,
|
||||
rate, new_rate);
|
||||
rate = new_rate;
|
||||
*ratep = rate;
|
||||
ratep->scaled = rate;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -736,22 +711,21 @@ debit_rrl_entry(dns_rrl_t *rrl, dns_rrl_entry_t *e, double qps, double scale,
|
|||
/*
|
||||
* Drop this response unless it should slip or leak.
|
||||
*/
|
||||
slip = rrl->slip;
|
||||
slip = rrl->slip.r;
|
||||
if (slip > 2 && scale < 1.0) {
|
||||
new_slip = (int) (slip * scale);
|
||||
if (new_slip < 2)
|
||||
new_slip = 2;
|
||||
if (rrl->scaled_slip != new_slip) {
|
||||
if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG1))
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
|
||||
DNS_LOGMODULE_REQUEST,
|
||||
DNS_RRL_LOG_DEBUG1,
|
||||
"%d qps scaled slip"
|
||||
" by %.2f from %d to %d",
|
||||
(int)qps, scale,
|
||||
slip, new_slip);
|
||||
if (rrl->slip.scaled != new_slip) {
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL,
|
||||
DNS_LOGMODULE_REQUEST,
|
||||
DNS_RRL_LOG_DEBUG1,
|
||||
"%d qps scaled slip"
|
||||
" by %.2f from %d to %d",
|
||||
(int)qps, scale,
|
||||
slip, new_slip);
|
||||
slip = new_slip;
|
||||
rrl->scaled_slip = slip;
|
||||
rrl->slip.scaled = slip;
|
||||
}
|
||||
}
|
||||
if (slip != 0 && e->key.s.rtype != DNS_RRL_RTYPE_ALL) {
|
||||
|
|
@ -853,34 +827,36 @@ make_log_buf(dns_rrl_t *rrl, dns_rrl_entry_t *e,
|
|||
|
||||
switch (e->key.s.rtype) {
|
||||
case DNS_RRL_RTYPE_QUERY:
|
||||
ADD_LOG_CSTR(&lb, "response");
|
||||
break;
|
||||
case DNS_RRL_RTYPE_DELEGATION:
|
||||
ADD_LOG_CSTR(&lb, "referral");
|
||||
case DNS_RRL_RTYPE_REFERRAL:
|
||||
ADD_LOG_CSTR(&lb, "referral ");
|
||||
break;
|
||||
case DNS_RRL_RTYPE_NODATA:
|
||||
ADD_LOG_CSTR(&lb, "NODATA ");
|
||||
break;
|
||||
case DNS_RRL_RTYPE_NXDOMAIN:
|
||||
ADD_LOG_CSTR(&lb, "NXDOMAIN response");
|
||||
ADD_LOG_CSTR(&lb, "NXDOMAIN ");
|
||||
break;
|
||||
case DNS_RRL_RTYPE_ERROR:
|
||||
if (resp_result == ISC_R_SUCCESS) {
|
||||
ADD_LOG_CSTR(&lb, "error response");
|
||||
ADD_LOG_CSTR(&lb, "error ");
|
||||
} else {
|
||||
rstr = isc_result_totext(resp_result);
|
||||
add_log_str(&lb, rstr, strlen(rstr));
|
||||
ADD_LOG_CSTR(&lb, " response");
|
||||
ADD_LOG_CSTR(&lb, " error ");
|
||||
}
|
||||
break;
|
||||
case DNS_RRL_RTYPE_ALL:
|
||||
ADD_LOG_CSTR(&lb, "all response");
|
||||
ADD_LOG_CSTR(&lb, "all ");
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
}
|
||||
|
||||
if (plural)
|
||||
ADD_LOG_CSTR(&lb, "s to ");
|
||||
ADD_LOG_CSTR(&lb, "responses to ");
|
||||
else
|
||||
ADD_LOG_CSTR(&lb, " to ");
|
||||
ADD_LOG_CSTR(&lb, "response to ");
|
||||
|
||||
memset(&cidr, 0, sizeof(cidr));
|
||||
if (e->key.s.ipv6) {
|
||||
|
|
@ -899,7 +875,8 @@ make_log_buf(dns_rrl_t *rrl, dns_rrl_entry_t *e,
|
|||
add_log_str(&lb, strbuf, strlen(strbuf));
|
||||
|
||||
if (e->key.s.rtype == DNS_RRL_RTYPE_QUERY ||
|
||||
e->key.s.rtype == DNS_RRL_RTYPE_DELEGATION ||
|
||||
e->key.s.rtype == DNS_RRL_RTYPE_REFERRAL ||
|
||||
e->key.s.rtype == DNS_RRL_RTYPE_NODATA ||
|
||||
e->key.s.rtype == DNS_RRL_RTYPE_NXDOMAIN) {
|
||||
qbuf = get_qname(rrl, e);
|
||||
if (save_qname && qbuf == NULL &&
|
||||
|
|
@ -947,8 +924,10 @@ make_log_buf(dns_rrl_t *rrl, dns_rrl_entry_t *e,
|
|||
if (e->key.s.rtype != DNS_RRL_RTYPE_NXDOMAIN) {
|
||||
ADD_LOG_CSTR(&lb, " ");
|
||||
(void)dns_rdataclass_totext(e->key.s.qclass, &lb);
|
||||
ADD_LOG_CSTR(&lb, " ");
|
||||
(void)dns_rdatatype_totext(e->key.s.qtype, &lb);
|
||||
if (e->key.s.rtype == DNS_RRL_RTYPE_QUERY) {
|
||||
ADD_LOG_CSTR(&lb, " ");
|
||||
(void)dns_rdatatype_totext(e->key.s.qtype, &lb);
|
||||
}
|
||||
}
|
||||
snprintf(strbuf, sizeof(strbuf), " (%08x)",
|
||||
e->key.s.qname_hash);
|
||||
|
|
@ -1117,14 +1096,23 @@ dns_rrl(dns_view_t *view,
|
|||
* Find the right kind of entry, creating it if necessary.
|
||||
* If that is impossible, then nothing more can be done
|
||||
*/
|
||||
if (resp_result == ISC_R_SUCCESS)
|
||||
switch (resp_result) {
|
||||
case ISC_R_SUCCESS:
|
||||
rtype = DNS_RRL_RTYPE_QUERY;
|
||||
else if (resp_result == DNS_R_DELEGATION)
|
||||
rtype = DNS_RRL_RTYPE_DELEGATION;
|
||||
else if (resp_result == DNS_R_NXDOMAIN)
|
||||
break;
|
||||
case DNS_R_DELEGATION:
|
||||
rtype = DNS_RRL_RTYPE_REFERRAL;
|
||||
break;
|
||||
case DNS_R_NXRRSET:
|
||||
rtype = DNS_RRL_RTYPE_NODATA;
|
||||
break;
|
||||
case DNS_R_NXDOMAIN:
|
||||
rtype = DNS_RRL_RTYPE_NXDOMAIN;
|
||||
else
|
||||
break;
|
||||
default:
|
||||
rtype = DNS_RRL_RTYPE_ERROR;
|
||||
break;
|
||||
}
|
||||
e = get_entry(rrl, client_addr, qclass, qtype, qname, rtype,
|
||||
now, ISC_TRUE, log_buf, log_buf_len);
|
||||
if (e == NULL) {
|
||||
|
|
@ -1148,7 +1136,7 @@ dns_rrl(dns_view_t *view,
|
|||
rrl_result = debit_rrl_entry(rrl, e, qps, scale, client_addr, now,
|
||||
log_buf, log_buf_len);
|
||||
|
||||
if (rrl->all_per_second != 0) {
|
||||
if (rrl->all_per_second.r != 0) {
|
||||
/*
|
||||
* We must debit the all-per-second token bucket if we have
|
||||
* an all-per-second limit for the IP address.
|
||||
|
|
|
|||
|
|
@ -1324,16 +1324,17 @@ static cfg_type_t cfg_type_rpz = {
|
|||
*/
|
||||
static cfg_clausedef_t rrl_clauses[] = {
|
||||
{ "responses-per-second", &cfg_type_uint32, 0 },
|
||||
{ "errors-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 },
|
||||
{ "responses-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 },
|
||||
{ "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 },
|
||||
|
|
|
|||
Loading…
Reference in a new issue