2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-29 13:38:26 +00:00

Merge branch '3405-security-limit-the-number-of-resource-records-in-rrset' into 'v9.20.0-release'

Limit the number of RRs in RRSets

See merge request isc-private/bind9!694
This commit is contained in:
Nicki Křížek 2024-06-10 15:01:48 +00:00
commit 24e8cc7b38
54 changed files with 4002 additions and 53 deletions

16
CHANGES
View File

@ -1,3 +1,19 @@
6401. [security] An excessively large number of rrtypes per owner can
slow down database query processing, so a limit has been
placed on the number of rrtypes that can be stored per
owner (node) in a cache or zone database. This is
configured with the new "max-rrtypes-per-name" option,
and defaults to 100. (CVE-2024-1737)
[GL #3403] [GL #4548]
6400. [security] Excessively large rdatasets can slow down database
query processing, so a limit has been placed on the
number of records that can be stored per rdataset
in a cache or zone database. This is configured
with the new "max-records-per-type" option, and
defaults to 100. (CVE-2024-1737)
[GL #497] [GL #3405]
6399. [security] Malicious DNS client that sends many queries over
TCP but never reads responses can cause server to
respond slowly or not respond at all for other

View File

@ -222,8 +222,10 @@ options {\n\
ixfr-from-differences false;\n\
max-journal-size default;\n\
max-records 0;\n\
max-records-per-type 100;\n\
max-refresh-time 2419200; /* 4 weeks */\n\
max-retry-time 1209600; /* 2 weeks */\n\
max-types-per-name 100;\n\
max-transfer-idle-in 60;\n\
max-transfer-idle-out 60;\n\
max-transfer-time-in 120;\n\

View File

@ -5454,6 +5454,24 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
dns_resolver_setclientsperquery(view->resolver, cfg_obj_asuint32(obj),
max_clients_per_query);
/*
* This is used for the cache and also as a default value
* for zone databases.
*/
obj = NULL;
result = named_config_get(maps, "max-records-per-type", &obj);
INSIST(result == ISC_R_SUCCESS);
dns_view_setmaxrrperset(view, cfg_obj_asuint32(obj));
/*
* This is used for the cache and also as a default value
* for zone databases.
*/
obj = NULL;
result = named_config_get(maps, "max-types-per-name", &obj);
INSIST(result == ISC_R_SUCCESS);
dns_view_setmaxtypepername(view, cfg_obj_asuint32(obj));
obj = NULL;
result = named_config_get(maps, "max-recursion-depth", &obj);
INSIST(result == ISC_R_SUCCESS);

View File

@ -1074,6 +1074,22 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
dns_zone_setmaxrecords(zone, 0);
}
obj = NULL;
result = named_config_get(maps, "max-records-per-type", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setmaxrrperset(mayberaw, cfg_obj_asuint32(obj));
if (zone != mayberaw) {
dns_zone_setmaxrrperset(zone, 0);
}
obj = NULL;
result = named_config_get(maps, "max-types-per-name", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setmaxtypepername(mayberaw, cfg_obj_asuint32(obj));
if (zone != mayberaw) {
dns_zone_setmaxtypepername(zone, 0);
}
if (raw != NULL && filename != NULL) {
#define SIGNED ".signed"
size_t signedlen = strlen(filename) + sizeof(SIGNED);

View File

@ -98,6 +98,7 @@ options {
tcp-initial-timeout 1200;
transfers-in 100;
transfers-out 100;
max-records-per-type 0;
};
trust-anchors { };

View File

@ -52,6 +52,7 @@ options {
ixfr-from-differences yes;
check-integrity no;
dnssec-validation yes;
max-records-per-type 0;
transfers-in 100;
transfers-out 100;
};

View File

@ -44,6 +44,7 @@ options {
ixfr-from-differences yes;
check-integrity no;
dnssec-validation yes;
max-records-per-type 0;
};
trust-anchors { };

View File

@ -52,6 +52,7 @@ options {
ixfr-from-differences yes;
check-integrity no;
dnssec-validation yes;
max-records-per-type 0;
};
trust-anchors { };

View File

@ -40,6 +40,7 @@ options {
ixfr-from-differences yes;
check-integrity no;
dnssec-validation yes;
max-records-per-type 0;
};
trust-anchors { };

View File

@ -23,6 +23,7 @@ options {
notify yes;
minimal-responses no;
dnssec-validation no;
max-records-per-type 0;
};
zone "." {

View File

@ -26,7 +26,12 @@ $CHECKZONE -D -F raw=0 -o example.db.compat example-compat \
example.db >/dev/null 2>&1
$CHECKZONE -D -F raw -L 3333 -o example.db.serial.raw example \
example.db >/dev/null 2>&1
$CHECKZONE -D -F raw -o large.db.raw large large.db >/dev/null 2>&1
$CHECKZONE -D -F raw -o under-limit.db.raw under-limit under-limit.db >/dev/null 2>&1
$CHECKZONE -D -F raw -o under-limit-kasp.db.raw under-limit-kasp under-limit-kasp.db >/dev/null 2>&1
$CHECKZONE -D -F raw -o on-limit.db.raw on-limit on-limit.db >/dev/null 2>&1
$CHECKZONE -D -F raw -o on-limit-kasp.db.raw on-limit-kasp on-limit-kasp.db >/dev/null 2>&1
$CHECKZONE -D -F raw -o over-limit.db.raw over-limit over-limit.db >/dev/null 2>&1
$CHECKZONE -D -F raw -o 255types.db.raw 255types 255types.db >/dev/null 2>&1
$KEYGEN -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK signed >/dev/null 2>&1
$KEYGEN -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" signed >/dev/null 2>&1

View File

@ -23,6 +23,8 @@ options {
session-keyfile "session.key";
servfail-ttl 0;
dnssec-validation no;
max-records-per-type 2050;
max-types-per-name 500;
};
key rndc_key {
@ -78,9 +80,48 @@ zone "transfer4" {
};
zone "large" {
zone "under-limit" {
type primary;
file "large.db.raw";
file "under-limit.db.raw";
masterfile-format raw;
allow-transfer { any; };
};
zone "under-limit-kasp" {
type primary;
file "under-limit-kasp.db.raw";
masterfile-format raw;
dnssec-policy masterformat;
allow-transfer { any; };
};
zone "on-limit" {
type primary;
file "on-limit.db.raw";
masterfile-format raw;
allow-transfer { any; };
};
zone "on-limit-kasp" {
type primary;
file "on-limit-kasp.db.raw";
masterfile-format raw;
dnssec-policy masterformat;
inline-signing no;
allow-update { any; };
allow-transfer { any; };
};
zone "over-limit" {
type primary;
file "over-limit.db.raw";
masterfile-format raw;
allow-transfer { any; };
};
zone "255types" {
type primary;
file "255types.db.raw";
masterfile-format raw;
allow-transfer { any; };
};

View File

@ -22,6 +22,8 @@ options {
notify no;
servfail-ttl 0;
dnssec-validation no;
max-records-per-type 2000;
max-types-per-name 200;
};
zone "example" {
@ -56,9 +58,37 @@ zone "transfer4" {
file "transfer.db.full";
};
zone "large" {
zone "under-limit" {
type secondary;
primaries { 10.53.0.1; };
masterfile-format raw;
file "large.bk";
file "under-limit.bk";
};
zone "under-limit-kasp" {
type secondary;
primaries { 10.53.0.1; };
masterfile-format raw;
file "under-limit-kasp.bk";
};
zone "on-limit" {
type secondary;
primaries { 10.53.0.1; };
masterfile-format raw;
file "on-limit.bk";
};
zone "on-limit-kasp" {
type secondary;
primaries { 10.53.0.1; };
masterfile-format raw;
file "on-limit-kasp.bk";
};
zone "255types" {
type secondary;
primaries { 10.53.0.1; };
masterfile-format raw;
file "255types.bk";
};

View File

@ -0,0 +1,21 @@
#!/bin/sh
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# SPDX-License-Identifier: MPL-2.0
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# shellcheck source=conf.sh
. ../../conf.sh
for zone in kasp-max-records-per-type \
kasp-max-records-per-type-dnskey \
kasp-max-types-per-name; do
$CHECKZONE -D -F raw -o $zone.db.raw $zone template.db >/dev/null 2>&1
done

View File

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 1D
@ IN SOA ns hostmaster (
1
3600
1800
1814400
3
)
NS ns
ns A 10.53.0.1
mx MX 10 mail
a A 10.53.0.1
aaaa AAAA 2001:db8::53
cname CNAME cname-target
dname DNAME dname-target
txt TXT "this is text"

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// NS4
options {
pid-file "named.pid";
listen-on port @PORT@ { 10.53.0.4; };
port @PORT@;
listen-on-v6 { none; };
recursion no;
notify no;
session-keyfile "session.key";
servfail-ttl 0;
dnssec-validation no;
/* Ridicously low on purpose */
max-records-per-type 1;
max-types-per-name 11;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
dnssec-policy "masterformat" {
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
};
};
/*
* This one should be okay, since the default policy only introduces one DNSKEY
* and each signature covering a different type is considered a separate RRset.
*/
zone "kasp-max-records-per-type" {
type primary;
file "kasp-max-records-per-type.db.raw";
masterfile-format raw;
dnssec-policy "default";
inline-signing no;
allow-update { any; };
allow-transfer { any; };
};
/*
* This one uses a ZSK / KSK, so that is two records in one RRset,
* thus it should fail to sign.
*/
zone "kasp-max-records-per-type-dnskey" {
type primary;
file "kasp-max-records-per-type-dnskey.db.raw";
masterfile-format raw;
dnssec-policy "masterformat";
inline-signing no;
allow-update { any; };
allow-transfer { any; };
};
/*
* The template zone is fine and should be possible to sign, but when
* adding an extra type to the apex the max-types-per-name will be exceeded,
* meaning the update should fail.
*/
zone "kasp-max-types-per-name" {
type primary;
file "kasp-max-types-per-name.db.raw";
masterfile-format raw;
dnssec-policy "default";
inline-signing no;
allow-update { any; };
allow-transfer { any; };
};

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// NS4
options {
pid-file "named.pid";
listen-on port @PORT@ { 10.53.0.4; };
port @PORT@;
listen-on-v6 { none; };
recursion no;
notify no;
session-keyfile "session.key";
servfail-ttl 0;
dnssec-validation no;
/* Ridicously low on purpose */
max-records-per-type 1;
max-types-per-name 9;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
/*
* The template zone is fine, but when adding the DNSSEC records to the apex,
* the max-types-per-name will be exceeded, meaning signing should fail.
*/
zone "kasp-max-types-per-name" {
type primary;
file "kasp-max-types-per-name.db.raw";
masterfile-format raw;
dnssec-policy "default";
inline-signing no;
allow-update { any; };
allow-transfer { any; };
};

View File

@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 1D
@ IN SOA ns hostmaster (
1
3600
1800
1814400
3
)
NS ns
ns A 10.53.0.1
mx MX 10 mail
a A 10.53.0.1
aaaa AAAA 2001:db8::53
cname CNAME cname-target
dname DNAME dname-target
txt TXT "this is text"

View File

@ -19,13 +19,44 @@ $SHELL clean.sh
copy_setports ns1/named.conf.in ns1/named.conf
copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns4/named1.conf.in ns4/named.conf
cp ns1/example.db ns2/
cp ns2/formerly-text.db.in ns2/formerly-text.db
cp ns1/large.db.in ns1/large.db
cp ns1/empty.db.in ns1/under-limit.db
# counts are set with respect to these limits in named.conf:
# max-records-per-type 2050;
# max-types-per-name 500;
awk 'END {
for (i = 0; i < 512; i++ ) { print "a TXT", i; }
for (i = 0; i < 1024; i++ ) { print "b TXT", i; }
for (i = 0; i < 2000; i++ ) { print "c TXT", i; }
}' </dev/null >>ns1/large.db
cd ns1 && $SHELL compile.sh
for (i = 0; i < 500; i++ ) { print "500-txt TXT", i; }
for (i = 0; i < 1000; i++ ) { print "1000-txt TXT", i; }
for (i = 0; i < 2000; i++ ) { print "2000-txt TXT", i; }
}' </dev/null >>ns1/under-limit.db
cp ns1/under-limit.db ns1/under-limit-kasp.db
cp ns1/empty.db.in ns1/on-limit.db
awk 'END {
for (i = 0; i < 500; i++ ) { print "500-txt TXT", i; }
for (i = 0; i < 1000; i++ ) { print "1000-txt TXT", i; }
for (i = 0; i < 2000; i++ ) { print "2000-txt TXT", i; }
for (i = 0; i < 2050; i++ ) { print "2050-txt TXT", i; }
}' </dev/null >>ns1/on-limit.db
cp ns1/on-limit.db ns1/on-limit-kasp.db
cp ns1/empty.db.in ns1/over-limit.db
awk 'END {
for (i = 0; i < 500; i++ ) { print "500-txt TXT", i; }
for (i = 0; i < 1000; i++ ) { print "1000-txt TXT", i; }
for (i = 0; i < 2000; i++ ) { print "2000-txt TXT", i; }
for (i = 0; i < 2050; i++ ) { print "2050-txt TXT", i; }
for (i = 0; i < 2100; i++ ) { print "2100-txt TXT", i; }
}' </dev/null >>ns1/over-limit.db
cp ns1/empty.db.in ns1/255types.db
for ntype in $(seq 65280 65534); do
echo "m TYPE${ntype} \# 0"
done >>ns1/255types.db
echo "m TXT bunny" >>ns1/255types.db
(cd ns1 && $SHELL compile.sh)
(cd ns4 && $SHELL compile.sh)

View File

@ -134,7 +134,7 @@ n=$((n + 1))
status=$((status + ret))
echo_i "waiting for transfers to complete"
for i in 0 1 2 3 4 5 6 7 8 9; do
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
test -f ns2/transfer.db.raw -a -f ns2/transfer.db.txt && break
sleep 1
done
@ -162,7 +162,7 @@ n=$((n + 1))
status=$((status + ret))
echo_i "checking that secondary formerly in text format is now raw ($n)"
for i in 0 1 2 3 4 5 6 7 8 9; do
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
israw ns2/formerly-text.db >/dev/null 2>&1 || ret=1
[ "$(rawversion ns2/formerly-text.db)" -eq 1 ] || ret=1
@ -173,12 +173,12 @@ n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that large rdatasets loaded ($n)"
for i in 0 1 2 3 4 5 6 7 8 9; do
echo_i "checking that under-limit rdatasets loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for a in a b c; do
$DIG +tcp txt "${a}.large" @10.53.0.2 -p "${PORT}" >"dig.out.ns2.test$n"
grep "status: NOERROR" "dig.out.ns2.test$n" >/dev/null || ret=1
for rrcount in 500-txt 1000-txt 2000-txt; do
$DIG +tcp txt "${rrcount}.under-limit" @10.53.0.1 -p "${PORT}" >"dig.out.ns1.$rrcount.test$n"
grep "status: NOERROR" "dig.out.ns1.$rrcount.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
@ -187,6 +187,253 @@ n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that under-limit rdatasets transfered ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrcount in 500-txt 1000-txt 2000-txt; do
$DIG +tcp txt "${rrcount}.under-limit" @10.53.0.2 -p "${PORT}" >"dig.out.ns2.$rrcount.test$n"
grep "status: NOERROR" "dig.out.ns2.$rrcount.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that under-limit-kasp dnskeys loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
$DIG +tcp +dnssec dnskey "under-limit-kasp" @10.53.0.1 -p "${PORT}" >"dig.out.ns1.dnskey.test$n"
grep "status: NOERROR" "dig.out.ns1.dnskey.test$n" >/dev/null || ret=1
grep "RRSIG" "dig.out.ns1.dnskey.test$n" >/dev/null || ret=1
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that under-limit-kasp rdatasets loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrcount in 500-txt 1000-txt 2000-txt; do
$DIG +tcp +dnssec txt "${rrcount}.under-limit-kasp" @10.53.0.1 -p "${PORT}" >"dig.out.ns1.$rrcount.test$n"
grep "status: NOERROR" "dig.out.ns1.$rrcount.test$n" >/dev/null || ret=1
grep "RRSIG" "dig.out.ns1.$rrcount.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that under-limit-kasp rdatasets transfered ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrcount in 500-txt 1000-txt 2000-txt; do
$DIG +tcp +dnssec txt "${rrcount}.under-limit-kasp" @10.53.0.2 -p "${PORT}" >"dig.out.ns2.$rrcount.test$n"
grep "status: NOERROR" "dig.out.ns2.$rrcount.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that on-limit rdatasets loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrcount in 500-txt 1000-txt 2000-txt 2050-txt; do
$DIG +tcp txt "${rrcount}.on-limit" @10.53.0.1 -p "${PORT}" >"dig.out.ns1.$rrcount.test$n"
grep "status: NOERROR" "dig.out.ns1.$rrcount.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that on-limit rdatasets not transfered ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrcount in 500-txt 1000-txt 2000-txt 2050-txt; do
$DIG +tcp txt "${rrcount}.on-limit" @10.53.0.2 -p "${PORT}" >"dig.out.ns2.$rrcount.test$n"
grep "status: SERVFAIL" "dig.out.ns2.$rrcount.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that on-limit-kasp rdatasets loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrcount in 500-txt 1000-txt 2000-txt 2050-txt; do
$DIG +tcp +dnssec txt "${rrcount}.on-limit-kasp" @10.53.0.1 -p "${PORT}" >"dig.out.ns1.$rrcount.test$n"
grep "status: NOERROR" "dig.out.ns1.$rrcount.test$n" >/dev/null || ret=1
grep "RRSIG" "dig.out.ns1.$rrcount.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that on-limit-kasp rdatasets not transfered ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrcount in 500-txt 1000-txt 2000-txt 2050-txt; do
$DIG +tcp +dnssec txt "${rrcount}.on-limit-kasp" @10.53.0.2 -p "${PORT}" >"dig.out.ns2.$rrcount.test$n"
grep "status: SERVFAIL" "dig.out.ns2.$rrcount.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that over-limit rdatasets not loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrcount in 500-txt 1000-txt 2000-txt 2050-txt 2100-txt; do
$DIG +tcp txt "${rrcount}.over-limit" @10.53.0.1 -p "${PORT}" >"dig.out.ns1.$rrcount.test$n"
grep "status: SERVFAIL" "dig.out.ns1.$rrcount.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that kasp-max-records-per-type rdatasets loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrtype in soa dnskey ns; do
$DIG +tcp +dnssec $rrtype "kasp-max-records-per-type" @10.53.0.4 -p "${PORT}" >"dig.out.ns4.$rrtype.test$n"
grep "status: NOERROR" "dig.out.ns4.$rrtype.test$n" >/dev/null || ret=1
grep "RRSIG" "dig.out.ns4.$rrtype.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that kasp-max-records-per-type-dnskey rdatasets not signed ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrtype in soa dnskey ns; do
$DIG +tcp +dnssec $rrtype "kasp-max-records-per-type-dnskey" @10.53.0.4 -p "${PORT}" >"dig.out.ns4.$rrtype.test$n"
grep "status: NOERROR" "dig.out.ns4.$rrtype.test$n" >/dev/null || ret=1
grep "RRSIG" "dig.out.ns4.$rrtype.test$n" >/dev/null && ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that kasp-max-types-per-name rdatasets loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrtype in soa dnskey ns; do
$DIG +tcp +dnssec $rrtype "kasp-max-types-per-name" @10.53.0.4 -p "${PORT}" >"dig.out.ns4.$rrtype.test$n"
grep "status: NOERROR" "dig.out.ns4.$rrtype.test$n" >/dev/null || ret=1
grep "RRSIG" "dig.out.ns4.$rrtype.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
# Update zone with nsupdate.
n=$((n + 1))
echo_i "add new type to zone and check that it fails ($n)"
ret=0
(
echo zone kasp-max-types-per-name.
echo server 10.53.0.4 "$PORT"
echo update add kasp-max-types-per-name. 300 TXT KAPUTT
echo send
) | $NSUPDATE && ret=1
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that kasp-max-types-per-name rdatasets loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrtype in soa dnskey ns txt; do
$DIG +tcp +dnssec $rrtype "kasp-max-types-per-name" @10.53.0.4 -p "${PORT}" >"dig.out.ns4.$rrtype.test$n"
grep "status: NOERROR" "dig.out.ns4.$rrtype.test$n" >/dev/null || ret=1
grep "KAPUTT" "dig.out.ns4.$rrtype.test$n" >/dev/null && ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
# Reconfigure ns4
echo_i "reconfigure ns4"
stop_server ns4
copy_setports ns4/named2.conf.in ns4/named.conf
# Recompile zone
$CHECKZONE -D -F raw -o ns4/kasp.db.raw kasp-max-types-per-name ns4/template.db >/dev/null 2>&1
start_server --noclean --restart --port "${PORT}" ns4
echo_i "checking that kasp-max-types-per-name rdatasets not loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrtype in soa dnskey ns; do
$DIG +tcp +dnssec $rrtype "kasp-max-types-per-name" @10.53.0.4 -p "${PORT}" >"dig.out.ns4.$rrtype.test$n"
grep "status: SERVFAIL" "dig.out.ns4.$rrtype.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that 255 types are loaded ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
$DIG +tcp TXT "m.255types" @10.53.0.1 -p "${PORT}" >"dig.out.ns1.test$n"
grep "status: NOERROR" "dig.out.ns1.test$n" >/dev/null || ret=1
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that 255 types types are not transfered ($n)"
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
$DIG +tcp TXT "m.255types" @10.53.0.2 -p "${PORT}" >"dig.out.ns2.test$n"
grep "status: SERVFAIL" "dig.out.ns2.test$n" >/dev/null || ret=1
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking format transitions: text->raw->text ($n)"
ret=0
$CHECKZONE -D -f text -F text -o baseline.txt example.nil ns1/example.db >/dev/null
@ -240,7 +487,7 @@ stop_server --use-rndc --port ${CONTROLPORT} ns3
rm ns3/*.jnl
restart
#shellcheck disable=SC2034
for i in 0 1 2 3 4 5 6 7 8 9; do
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
lret=0
dig_with_opts +comm @10.53.0.3 moretext.dynamic txt >"dig.out.dynamic2.ns3.test$n"
grep "more text" "dig.out.dynamic2.ns3.test$n" >/dev/null 2>&1 || lret=1
@ -273,5 +520,24 @@ n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "checking that on-limit-kasp rdatasets loaded after re-sign and re-start ($n)"
ret=0
stop_server ns1
start_server --noclean --restart --port "${PORT}" ns1
for _attempt in 0 1 2 3 4 5 6 7 8 9; do
ret=0
for rrcount in 500-txt 1000-txt 2000-txt 2050-txt; do
$DIG +tcp +dnssec txt "${rrcount}.on-limit-kasp" @10.53.0.1 -p "${PORT}" >"dig.out.ns1.$rrcount.test$n"
grep "status: NOERROR" "dig.out.ns1.$rrcount.test$n" >/dev/null || ret=1
grep "RRSIG" "dig.out.ns1.$rrcount.test$n" >/dev/null || ret=1
done
[ $ret -eq 0 ] && break
sleep 1
done
n=$((n + 1))
[ $ret -eq 0 ] || echo_i "failed"
status=$((status + ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,13 @@ options {
listen-on-v6 { none; };
recursion no;
dnssec-validation no;
max-records-per-type 0;
max-types-per-name 0;
};
zone "." { type primary; file "root.db"; };
zone "big." {
type primary;
file "big.db";
};

View File

@ -19,3 +19,6 @@ example.net. 60 IN NS direct.example.net.
direct.example.net. 60 IN A 10.53.0.2
example.com. 60 IN NS direct.example.com.
direct.example.com. 60 IN A 10.53.0.4
big. in NS ns.big.
ns.big. 60 IN A 10.53.0.1

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
directory ".";
query-source address 10.53.0.3;
notify-source 10.53.0.3;
transfer-source 10.53.0.3;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
servfail-ttl 0;
qname-minimization disabled;
max-recursion-depth 12;
recursion yes;
dnssec-validation yes;
max-records-per-type 0;
max-types-per-name 10;
};
trust-anchors { };
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." { type hint; file "hints.db"; };

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
directory ".";
query-source address 10.53.0.3;
notify-source 10.53.0.3;
transfer-source 10.53.0.3;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
servfail-ttl 0;
qname-minimization disabled;
max-recursion-depth 12;
recursion yes;
dnssec-validation yes;
max-records-per-type 0;
max-types-per-name 0;
};
trust-anchors { };
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." { type hint; file "hints.db"; };

View File

@ -222,6 +222,50 @@ eval count=$(cat dig.out.3.test$n)
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
#grep "duplicate query" ns3/named.run
n=$((n + 1))
echo_i "checking RRset that exceeds max-records-per-type ($n)"
ret=0
$DIG $DIGOPTS @10.53.0.3 biganswer.big >dig.out.1.test$n || ret=1
grep 'status: SERVFAIL' dig.out.1.test$n >/dev/null || ret=1
ns3_reset ns3/named5.conf.in
$DIG $DIGOPTS @10.53.0.3 biganswer.big >dig.out.2.test$n || ret=1
grep 'status: NOERROR' dig.out.2.test$n >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
check_manytypes() (
i=$1
type=$2
expected=$3
$DIG $DIGOPTS @10.53.0.3 IN $type manytypes.big >dig.out.$i.$type.test$n || exit 1
grep 'status: '"${expected}"'' dig.out.$i.$type.test$n >/dev/null || exit 1
exit 0
)
n=$((n + 1))
echo_i "checking name that exceeds max-types-per-name ($n)"
ret=0
# Limited to 10 types - these should be fine
for ntype in $(seq 65280 65289); do
check_manytypes 1 "TYPE${ntype}" NOERROR || ret=1
done
# Everything on top of that should SERVFAIL
for ntype in $(seq 65290 65534); do
check_manytypes 1 "TYPE${ntype}" SERVFAIL || ret=1
done
# Lift the limit
ns3_reset ns3/named6.conf.in
for ntype in $(seq 65280 65534); do
check_manytypes 2 "TYPE${ntype}" NOERROR || ret=1
done
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View File

@ -3681,6 +3681,36 @@ system.
This sets the maximum number of records permitted in a zone. The default is
zero, which means the maximum is unlimited.
.. namedconf:statement:: max-records-per-type
:tags: server
:short: Sets the maximum number of records that can be stored in an RRset
This sets the maximum number of resource records that can be stored
in an RRset in a database. When configured in :namedconf:ref:`options`
or :namedconf:ref:`view`, it controls the cache database; it also sets
the default value for zone databases, which can be overridden by setting
it at the :namedconf:ref:`zone` level.
If set to a positive value, any attempt to cache or to add to a zone
an RRset with more than the specified number of records will result in
a failure. If set to 0, there is no cap on RRset size. The default is
100.
.. namedconf:statement:: max-types-per-name
:tags: server
:short: Sets the maximum number of RR types that can be stored for an owner name
This sets the maximum number of resource record types that can be stored
for a single owner name in a database. When configured in :namedconf:ref:`options`
or :namedconf:ref:`view`, it controls the cache database, and also sets
the default value for zone databases, which can be overridden by setting
it at the :namedconf:ref:`zone` level
If set to a positive value, any attempt to cache or to add to a zone an owner
name with more than the specified number of resource record types will result
in a failure. If set to 0, there is no cap on RR types number. The default is
100.
.. namedconf:statement:: recursive-clients
:tags: query
:short: Specifies the maximum number of concurrent recursive queries the server can perform.

View File

@ -16,12 +16,14 @@ zone <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;

View File

@ -183,6 +183,7 @@ options {
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-records <integer>;
max-records-per-type <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
max-refresh-time <integer>;
@ -193,6 +194,7 @@ options {
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
max-udp-size <integer>;
max-validation-failures-per-fetch <integer>; // experimental
max-validations-per-fetch <integer>; // experimental
@ -468,6 +470,7 @@ view <string> [ <class> ] {
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-records <integer>;
max-records-per-type <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
max-refresh-time <integer>;
@ -477,6 +480,7 @@ view <string> [ <class> ] {
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
max-udp-size <integer>;
max-validation-failures-per-fetch <integer>; // experimental
max-validations-per-fetch <integer>; // experimental

View File

@ -37,8 +37,10 @@ zone <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-records-per-type <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> ); // deprecated
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;

View File

@ -7,6 +7,8 @@ zone <string> [ <class> ] {
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-records <integer>;
max-records-per-type <integer>;
max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> ); // deprecated
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
zone-statistics ( full | terse | none | <boolean> );

View File

@ -28,12 +28,14 @@ zone <string> [ <class> ] {
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;

View File

@ -5,6 +5,8 @@ zone <string> [ <class> ] {
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
max-records <integer>;
max-records-per-type <integer>;
max-types-per-name <integer>;
server-addresses { ( <ipv4_address> | <ipv6_address> ); ... };
server-names { <string>; ... };
zone-statistics ( full | terse | none | <boolean> );

View File

@ -11,10 +11,12 @@ zone <string> [ <class> ] {
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-records <integer>;
max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-time-in <integer>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;

View File

@ -19,6 +19,21 @@ Security Fixes
responses can cause server to respond slowly or not respond at all for other
clients. :cve:`2024-0760` :gl:`#4481`
- Excessively large resource record sets can be crafted to slow down
database processing. This has been addressed by adding a configurable
limit to the number of records that can be stored per name and type in
a cache or zone database. The default is 100, but it can be tuned with
the new ``max-records-per-type`` option. :gl:`#497` :gl:`#3405`
An excessively large number of resource record types for a single owner name can
be crafted to slow down database processing. This has been addressed by adding
a configurable limit to the number of records that can be stored per name and
type in a cache or zone database. The default is 100, and can be tuned with
the new ``max-rrtypes-per-name`` option. :cve:`2024-1737` :gl:`#3403`
ISC would like to thank Toshifumi Sakaguchi who independently discovered
and responsibly reported the issue to ISC. :gl:`#4548`
New Features
~~~~~~~~~~~~

View File

@ -80,6 +80,8 @@ struct dns_cache {
dns_ttl_t serve_stale_ttl;
dns_ttl_t serve_stale_refresh;
isc_stats_t *stats;
uint32_t maxrrperset;
uint32_t maxtypepername;
};
/***
@ -128,6 +130,8 @@ cache_create_db(dns_cache_t *cache, dns_db_t **dbp, isc_mem_t **tmctxp,
dns_db_setservestalettl(db, cache->serve_stale_ttl);
dns_db_setservestalerefresh(db, cache->serve_stale_refresh);
dns_db_setmaxrrperset(db, cache->maxrrperset);
dns_db_setmaxtypepername(db, cache->maxtypepername);
/*
* XXX this is only used by the RBT cache, and can
@ -546,6 +550,26 @@ dns_cache_updatestats(dns_cache_t *cache, isc_result_t result) {
}
}
void
dns_cache_setmaxrrperset(dns_cache_t *cache, uint32_t value) {
REQUIRE(VALID_CACHE(cache));
cache->maxrrperset = value;
if (cache->db != NULL) {
dns_db_setmaxrrperset(cache->db, value);
}
}
void
dns_cache_setmaxtypepername(dns_cache_t *cache, uint32_t value) {
REQUIRE(VALID_CACHE(cache));
cache->maxtypepername = value;
if (cache->db != NULL) {
dns_db_setmaxtypepername(cache->db, value);
}
}
/*
* XXX: Much of the following code has been copied in from statschannel.c.
* We should refactor this into a generic function in stats.c that can be

View File

@ -1170,3 +1170,21 @@ dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) {
}
return (ISC_R_NOTIMPLEMENTED);
}
void
dns_db_setmaxrrperset(dns_db_t *db, uint32_t value) {
REQUIRE(DNS_DB_VALID(db));
if (db->methods->setmaxrrperset != NULL) {
(db->methods->setmaxrrperset)(db, value);
}
}
void
dns_db_setmaxtypepername(dns_db_t *db, uint32_t value) {
REQUIRE(DNS_DB_VALID(db));
if (db->methods->setmaxtypepername != NULL) {
(db->methods->setmaxtypepername)(db, value);
}
}

View File

@ -246,6 +246,18 @@ dns_cache_updatestats(dns_cache_t *cache, isc_result_t result);
* Update cache statistics based on result code in 'result'
*/
void
dns_cache_setmaxrrperset(dns_cache_t *cache, uint32_t value);
/*%<
* Set the maximum resource records per RRSet that can be cached.
*/
void
dns_cache_setmaxtypepername(dns_cache_t *cache, uint32_t value);
/*%<
* Set the maximum resource record types per owner name that can be cached.
*/
#ifdef HAVE_LIBXML2
int
dns_cache_renderxml(dns_cache_t *cache, void *writer0);

View File

@ -183,6 +183,8 @@ typedef struct dns_dbmethods {
void (*deletedata)(dns_db_t *db, dns_dbnode_t *node, void *data);
isc_result_t (*nodefullname)(dns_db_t *db, dns_dbnode_t *node,
dns_name_t *name);
void (*setmaxrrperset)(dns_db_t *db, uint32_t value);
void (*setmaxtypepername)(dns_db_t *db, uint32_t value);
} dns_dbmethods_t;
typedef isc_result_t (*dns_dbcreatefunc_t)(isc_mem_t *mctx,
@ -1800,4 +1802,23 @@ dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name);
* \li 'db' is a valid database
* \li 'node' and 'name' are not NULL
*/
void
dns_db_setmaxrrperset(dns_db_t *db, uint32_t value);
/*%<
* Set the maximum permissible number of RRs per RRset.
*
* If 'value' is nonzero, then any subsequent attempt to add an rdataset
* with more than 'value' RRs will return ISC_R_TOOMANYRECORDS.
*/
void
dns_db_setmaxtypepername(dns_db_t *db, uint32_t value);
/*%<
* Set the maximum permissible number of RR types per owner name.
*
* If 'value' is nonzero, and if there are already 'value' RR types
* stored at a given node, then any subsequent attempt to add an rdataset
* with a new RR type will return ISC_R_TOOMANYRECORDS.
*/
ISC_LANG_ENDDECLS

View File

@ -169,7 +169,8 @@ extern dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods;
isc_result_t
dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
isc_region_t *region, unsigned int reservelen);
isc_region_t *region, unsigned int reservelen,
uint32_t limit);
/*%<
* Slabify a rdataset. The slab area will be allocated and returned
* in 'region'.
@ -225,7 +226,8 @@ isc_result_t
dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
unsigned int reservelen, isc_mem_t *mctx,
dns_rdataclass_t rdclass, dns_rdatatype_t type,
unsigned int flags, unsigned char **tslabp);
unsigned int flags, uint32_t maxrrperset,
unsigned char **tslabp);
/*%<
* Merge 'oslab' and 'nslab'.
*/

View File

@ -183,6 +183,8 @@ struct dns_view {
uint32_t fail_ttl;
dns_badcache_t *failcache;
unsigned int udpsize;
uint32_t maxrrperset;
uint32_t maxtypepername;
/*
* Configurable data for server use only,
@ -1242,6 +1244,18 @@ dns_view_getresolver(dns_view_t *view, dns_resolver_t **resolverp);
* Return the resolver associated with the view.
*/
void
dns_view_setmaxrrperset(dns_view_t *view, uint32_t value);
/*%<
* Set the maximum resource records per RRSet that can be cached.
*/
void
dns_view_setmaxtypepername(dns_view_t *view, uint32_t value);
/*%<
* Set the maximum resource record types per owner name that can be cached.
*/
void
dns_view_setudpsize(dns_view_t *view, uint16_t udpsize);
/*%<

View File

@ -366,6 +366,32 @@ dns_zone_getmaxrecords(dns_zone_t *zone);
*\li uint32_t maxrecords.
*/
void
dns_zone_setmaxrrperset(dns_zone_t *zone, uint32_t maxrrperset);
/*%<
* Sets the maximum number of records per rrset permitted in a zone.
* 0 implies unlimited.
*
* Requires:
*\li 'zone' to be valid initialised zone.
*
* Returns:
*\li void
*/
void
dns_zone_setmaxtypepername(dns_zone_t *zone, uint32_t maxtypepername);
/*%<
* Sets the maximum number of resource record types per owner name
* permitted in a zone. 0 implies unlimited.
*
* Requires:
*\li 'zone' to be valid initialised zone.
*
* Returns:
*\li void
*/
void
dns_zone_setmaxttl(dns_zone_t *zone, uint32_t maxttl);
/*%<

View File

@ -217,6 +217,9 @@ struct qpcache {
/* Locked by lock. */
unsigned int active;
uint32_t maxrrperset; /* Maximum RRs per RRset */
uint32_t maxtypepername; /* Maximum number of RR types per owner */
/*
* The time after a failed lookup, where stale answers from cache
* may be used directly in a DNS response without attempting a
@ -2883,6 +2886,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
dns_typepair_t negtype = 0, sigtype;
dns_trust_t trust;
int idx;
uint32_t ntypes;
if ((options & DNS_DBADD_FORCE) != 0) {
trust = dns_trust_ultimate;
@ -2915,6 +2919,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
{
mark_ancient(topheader);
}
ntypes = 0; /* Always add the negative entry */
goto find_header;
}
/*
@ -2938,9 +2943,11 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* check for an extant non-ancient NODATA ncache
* entry which covers the same type as the RRSIG.
*/
ntypes = 0;
for (topheader = qpnode->data; topheader != NULL;
topheader = topheader->next)
{
++ntypes;
if ((topheader->type == RDATATYPE_NCACHEANY) ||
(newheader->type == sigtype &&
topheader->type ==
@ -2983,9 +2990,12 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
}
}
ntypes = 0;
for (topheader = qpnode->data; topheader != NULL;
topheader = topheader->next)
{
++ntypes;
if (prio_type(topheader->type)) {
prioheader = topheader;
}
@ -3253,6 +3263,14 @@ find_header:
/*
* No rdatasets of the given type exist at the node.
*/
if (trust != dns_trust_ultimate &&
qpdb->maxtypepername > 0 &&
ntypes >= qpdb->maxtypepername)
{
dns_slabheader_destroy(&newheader);
return (DNS_R_TOOMANYRECORDS);
}
INSIST(newheader->down == NULL);
if (prio_type(newheader->type)) {
@ -3280,7 +3298,7 @@ find_header:
}
static isc_result_t
addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader,
addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
dns_rdataset_t *rdataset) {
isc_result_t result;
dns_slabheader_proof_t *noqname = NULL;
@ -3291,12 +3309,12 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader,
result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0);
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0);
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@ -3319,7 +3337,7 @@ cleanup:
}
static isc_result_t
addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader,
addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
dns_rdataset_t *rdataset) {
isc_result_t result;
dns_slabheader_proof_t *closest = NULL;
@ -3330,12 +3348,12 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader,
result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0);
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0);
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@ -3386,7 +3404,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
}
result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
&region, sizeof(dns_slabheader_t));
&region, sizeof(dns_slabheader_t),
qpdb->maxrrperset);
if (result != ISC_R_SUCCESS) {
return (result);
}
@ -3423,14 +3442,16 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_OPTOUT);
}
if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
result = addnoqname(qpdb->common.mctx, newheader, rdataset);
result = addnoqname(qpdb->common.mctx, newheader,
qpdb->maxrrperset, rdataset);
if (result != ISC_R_SUCCESS) {
dns_slabheader_destroy(&newheader);
return (result);
}
}
if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) {
result = addclosest(qpdb->common.mctx, newheader, rdataset);
result = addclosest(qpdb->common.mctx, newheader,
qpdb->maxrrperset, rdataset);
if (result != ISC_R_SUCCESS) {
dns_slabheader_destroy(&newheader);
return (result);
@ -4330,6 +4351,24 @@ expire_ttl_headers(qpcache_t *qpdb, unsigned int locknum,
}
}
static void
setmaxrrperset(dns_db_t *db, uint32_t value) {
qpcache_t *qpdb = (qpcache_t *)db;
REQUIRE(VALID_QPDB(qpdb));
qpdb->maxrrperset = value;
}
static void
setmaxtypepername(dns_db_t *db, uint32_t value) {
qpcache_t *qpdb = (qpcache_t *)db;
REQUIRE(VALID_QPDB(qpdb));
qpdb->maxtypepername = value;
}
static dns_dbmethods_t qpdb_cachemethods = {
.destroy = qpdb_destroy,
.findnode = findnode,
@ -4354,6 +4393,8 @@ static dns_dbmethods_t qpdb_cachemethods = {
.unlocknode = unlocknode,
.expiredata = expiredata,
.deletedata = deletedata,
.setmaxrrperset = setmaxrrperset,
.setmaxtypepername = setmaxtypepername,
};
static void

View File

@ -178,6 +178,8 @@ struct qpzonedb {
uint32_t current_serial;
uint32_t least_serial;
uint32_t next_serial;
uint32_t maxrrperset; /* Maximum RRs per RRset */
uint32_t maxtypepername; /* Maximum number of RR types per owner */
qpz_version_t *current_version;
qpz_version_t *future_version;
qpz_versionlist_t open_versions;
@ -1833,6 +1835,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
unsigned char *merged = NULL;
isc_result_t result;
bool merge = false;
uint32_t ntypes;
if ((options & DNS_DBADD_MERGE) != 0) {
REQUIRE(version != NULL);
@ -1848,9 +1851,11 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
changed = add_changed(newheader, version DNS__DB_FLARG_PASS);
}
ntypes = 0;
for (topheader = node->data; topheader != NULL;
topheader = topheader->next)
{
++ntypes;
if (prio_type(topheader->type)) {
prioheader = topheader;
}
@ -1898,7 +1903,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
(unsigned int)(sizeof(*newheader)),
qpdb->common.mctx, qpdb->common.rdclass,
(dns_rdatatype_t)header->type, flags,
&merged);
qpdb->maxrrperset, &merged);
}
if (result == ISC_R_SUCCESS) {
/*
@ -2017,6 +2022,14 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
/*
* No rdatasets of the given type exist at the node.
*/
if (qpdb->maxtypepername > 0 &&
ntypes >= qpdb->maxtypepername)
{
dns_slabheader_destroy(&newheader);
return (DNS_R_TOOMANYRECORDS);
}
INSIST(newheader->down == NULL);
if (prio_type(newheader->type)) {
@ -2147,7 +2160,8 @@ loading_addrdataset(void *arg, const dns_name_t *name,
loading_addnode(loadctx, name, rdataset->type, rdataset->covers, &node);
result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
&region, sizeof(dns_slabheader_t));
&region, sizeof(dns_slabheader_t),
qpdb->maxrrperset);
if (result != ISC_R_SUCCESS) {
return (result);
}
@ -4648,7 +4662,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
rdataset->covers != dns_rdatatype_nsec3)));
result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
&region, sizeof(dns_slabheader_t));
&region, sizeof(dns_slabheader_t),
qpdb->maxrrperset);
if (result != ISC_R_SUCCESS) {
return (result);
}
@ -4767,7 +4782,8 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
dns_name_copy(&node->name, nodename);
result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
&region, sizeof(dns_slabheader_t));
&region, sizeof(dns_slabheader_t),
0);
if (result != ISC_R_SUCCESS) {
return (result);
}
@ -5277,6 +5293,24 @@ addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
return (ISC_R_SUCCESS);
}
static void
setmaxrrperset(dns_db_t *db, uint32_t value) {
qpzonedb_t *qpdb = (qpzonedb_t *)db;
REQUIRE(VALID_QPZONE(qpdb));
qpdb->maxrrperset = value;
}
static void
setmaxtypepername(dns_db_t *db, uint32_t value) {
qpzonedb_t *qpdb = (qpzonedb_t *)db;
REQUIRE(VALID_QPZONE(qpdb));
qpdb->maxtypepername = value;
}
static dns_dbmethods_t qpdb_zonemethods = {
.destroy = qpdb_destroy,
.beginload = beginload,
@ -5310,6 +5344,8 @@ static dns_dbmethods_t qpdb_zonemethods = {
.addglue = addglue,
.deletedata = deletedata,
.nodefullname = nodefullname,
.setmaxrrperset = setmaxrrperset,
.setmaxtypepername = setmaxtypepername,
};
static void

View File

@ -1582,6 +1582,8 @@ dns_dbmethods_t dns__rbtdb_cachemethods = {
.unlocknode = dns__rbtdb_unlocknode,
.expiredata = expiredata,
.deletedata = dns__rbtdb_deletedata,
.setmaxrrperset = dns__rbtdb_setmaxrrperset,
.setmaxtypepername = dns__rbtdb_setmaxtypepername,
};
/*

View File

@ -1749,7 +1749,8 @@ loading_addrdataset(void *arg, const dns_name_t *name,
}
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
&region, sizeof(dns_slabheader_t));
&region, sizeof(dns_slabheader_t),
rbtdb->maxrrperset);
if (result != ISC_R_SUCCESS) {
return (result);
}
@ -2418,6 +2419,8 @@ dns_dbmethods_t dns__rbtdb_zonemethods = {
.addglue = addglue,
.deletedata = dns__rbtdb_deletedata,
.nodefullname = dns__rbtdb_nodefullname,
.setmaxrrperset = dns__rbtdb_setmaxrrperset,
.setmaxtypepername = dns__rbtdb_setmaxtypepername,
};
void

View File

@ -2566,6 +2566,7 @@ dns__rbtdb_add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
dns_typepair_t negtype = 0, sigtype;
dns_trust_t trust;
int idx;
uint32_t ntypes = 0;
if ((options & DNS_DBADD_MERGE) != 0) {
REQUIRE(rbtversion != NULL);
@ -2618,6 +2619,7 @@ dns__rbtdb_add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
{
mark_ancient(topheader);
}
ntypes = 0; /* Always add the negative entry */
goto find_header;
}
/*
@ -2641,9 +2643,11 @@ dns__rbtdb_add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
* check for an extant non-ancient NODATA ncache
* entry which covers the same type as the RRSIG.
*/
ntypes = 0;
for (topheader = rbtnode->data; topheader != NULL;
topheader = topheader->next)
{
++ntypes;
if ((topheader->type == RDATATYPE_NCACHEANY) ||
(newheader->type == sigtype &&
topheader->type ==
@ -2686,9 +2690,11 @@ dns__rbtdb_add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
}
}
ntypes = 0;
for (topheader = rbtnode->data; topheader != NULL;
topheader = topheader->next)
{
++ntypes;
if (prio_type(topheader->type)) {
prioheader = topheader;
}
@ -2780,7 +2786,7 @@ find_header:
rbtdb->common.mctx,
rbtdb->common.rdclass,
(dns_rdatatype_t)header->type, flags,
&merged);
rbtdb->maxrrperset, &merged);
}
if (result == ISC_R_SUCCESS) {
/*
@ -3082,6 +3088,14 @@ find_header:
/*
* No rdatasets of the given type exist at the node.
*/
if (rbtdb->maxtypepername > 0 &&
ntypes >= rbtdb->maxtypepername)
{
dns_slabheader_destroy(&newheader);
return (DNS_R_TOOMANYRECORDS);
}
INSIST(newheader->down == NULL);
if (prio_type(newheader->type)) {
@ -3141,7 +3155,7 @@ delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, dns_typepair_t type) {
}
static isc_result_t
addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader,
addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
dns_rdataset_t *rdataset) {
isc_result_t result;
dns_slabheader_proof_t *noqname = NULL;
@ -3152,12 +3166,12 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader,
result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0);
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0);
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@ -3180,7 +3194,7 @@ cleanup:
}
static isc_result_t
addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader,
addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
dns_rdataset_t *rdataset) {
isc_result_t result;
dns_slabheader_proof_t *closest = NULL;
@ -3191,12 +3205,12 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader,
result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0);
result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0);
result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@ -3272,7 +3286,8 @@ dns__rbtdb_addrdataset(dns_db_t *db, dns_dbnode_t *node,
}
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
&region, sizeof(dns_slabheader_t));
&region, sizeof(dns_slabheader_t),
rbtdb->maxrrperset);
if (result != ISC_R_SUCCESS) {
return (result);
}
@ -3329,7 +3344,7 @@ dns__rbtdb_addrdataset(dns_db_t *db, dns_dbnode_t *node,
}
if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
result = addnoqname(rbtdb->common.mctx, newheader,
rdataset);
rbtdb->maxrrperset, rdataset);
if (result != ISC_R_SUCCESS) {
dns_slabheader_destroy(&newheader);
return (result);
@ -3337,7 +3352,7 @@ dns__rbtdb_addrdataset(dns_db_t *db, dns_dbnode_t *node,
}
if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) {
result = addclosest(rbtdb->common.mctx, newheader,
rdataset);
rbtdb->maxrrperset, rdataset);
if (result != ISC_R_SUCCESS) {
dns_slabheader_destroy(&newheader);
return (result);
@ -3487,7 +3502,8 @@ dns__rbtdb_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
dns__rbtdb_nodefullname(db, node, nodename);
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
&region, sizeof(dns_slabheader_t));
&region, sizeof(dns_slabheader_t),
0);
if (result != ISC_R_SUCCESS) {
return (result);
}
@ -4957,3 +4973,21 @@ expire_ttl_headers(dns_rbtdb_t *rbtdb, unsigned int locknum,
dns_expire_ttl DNS__DB_FLARG_PASS);
}
}
void
dns__rbtdb_setmaxrrperset(dns_db_t *db, uint32_t value) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
REQUIRE(VALID_RBTDB(rbtdb));
rbtdb->maxrrperset = value;
}
void
dns__rbtdb_setmaxtypepername(dns_db_t *db, uint32_t maxtypepername) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
REQUIRE(VALID_RBTDB(rbtdb));
rbtdb->maxtypepername = maxtypepername;
}

View File

@ -114,6 +114,8 @@ struct dns_rbtdb {
uint32_t current_serial;
uint32_t least_serial;
uint32_t next_serial;
uint32_t maxrrperset;
uint32_t maxtypepername;
dns_rbtdb_version_t *current_version;
dns_rbtdb_version_t *future_version;
rbtdb_versionlist_t open_versions;
@ -427,6 +429,18 @@ dns__rbtdb_setttl(dns_slabheader_t *header, dns_ttl_t newttl);
* also update the TTL heap accordingly.
*/
void
dns__rbtdb_setmaxrrperset(dns_db_t *db, uint32_t maxrrperset);
/*%<
* Set the max RRs per RRset limit.
*/
void
dns__rbtdb_setmaxtypepername(dns_db_t *db, uint32_t maxtypepername);
/*%<
* Set the max RRs per RRset limit.
*/
/*
* Functions specific to zone databases that are also called from rbtdb.c.
*/

View File

@ -168,7 +168,8 @@ fillin_offsets(unsigned char *offsetbase, unsigned int *offsettable,
isc_result_t
dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
isc_region_t *region, unsigned int reservelen) {
isc_region_t *region, unsigned int reservelen,
uint32_t maxrrperset) {
/*
* Use &removed as a sentinel pointer for duplicate
* rdata as rdata.data == NULL is valid.
@ -208,6 +209,10 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
return (ISC_R_SUCCESS);
}
if (maxrrperset > 0 && nitems > maxrrperset) {
return (DNS_R_TOOMANYRECORDS);
}
if (nitems > 0xffff) {
return (ISC_R_NOSPACE);
}
@ -515,7 +520,8 @@ isc_result_t
dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
unsigned int reservelen, isc_mem_t *mctx,
dns_rdataclass_t rdclass, dns_rdatatype_t type,
unsigned int flags, unsigned char **tslabp) {
unsigned int flags, uint32_t maxrrperset,
unsigned char **tslabp) {
unsigned char *ocurrent = NULL, *ostart = NULL, *ncurrent = NULL;
unsigned char *tstart = NULL, *tcurrent = NULL, *data = NULL;
unsigned int ocount, ncount, count, olength, tlength, tcount, length;
@ -554,6 +560,10 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
#endif /* if DNS_RDATASET_FIXED */
INSIST(ocount > 0 && ncount > 0);
if (maxrrperset > 0 && ocount + ncount > maxrrperset) {
return (DNS_R_TOOMANYRECORDS);
}
#if DNS_RDATASET_FIXED
oncount = ncount;
#endif /* if DNS_RDATASET_FIXED */

View File

@ -643,6 +643,9 @@ dns_view_setcache(dns_view_t *view, dns_cache_t *cache, bool shared) {
dns_cache_attach(cache, &view->cache);
dns_cache_attachdb(cache, &view->cachedb);
INSIST(DNS_DB_VALID(view->cachedb));
dns_cache_setmaxrrperset(view->cache, view->maxrrperset);
dns_cache_setmaxtypepername(view->cache, view->maxtypepername);
}
bool
@ -2336,6 +2339,24 @@ dns_view_getresolver(dns_view_t *view, dns_resolver_t **resolverp) {
return (result);
}
void
dns_view_setmaxrrperset(dns_view_t *view, uint32_t value) {
REQUIRE(DNS_VIEW_VALID(view));
view->maxrrperset = value;
if (view->cache != NULL) {
dns_cache_setmaxrrperset(view->cache, value);
}
}
void
dns_view_setmaxtypepername(dns_view_t *view, uint32_t value) {
REQUIRE(DNS_VIEW_VALID(view));
view->maxtypepername = value;
if (view->cache != NULL) {
dns_cache_setmaxtypepername(view->cache, value);
}
}
void
dns_view_setudpsize(dns_view_t *view, uint16_t udpsize) {
REQUIRE(DNS_VIEW_VALID(view));

View File

@ -318,6 +318,8 @@ struct dns_zone {
uint32_t minretry;
uint32_t maxrecords;
uint32_t maxrrperset;
uint32_t maxtypepername;
dns_remote_t primaries;
@ -9741,6 +9743,7 @@ cleanup:
}
dns_diff_clear(&_sig_diff);
dns_diff_clear(&post_diff);
for (i = 0; i < nkeys; i++) {
dst_key_free(&zone_keys[i]);
@ -12057,6 +12060,26 @@ dns_zone_setmaxrecords(dns_zone_t *zone, uint32_t val) {
zone->maxrecords = val;
}
void
dns_zone_setmaxrrperset(dns_zone_t *zone, uint32_t val) {
REQUIRE(DNS_ZONE_VALID(zone));
zone->maxrrperset = val;
if (zone->db != NULL) {
dns_db_setmaxrrperset(zone->db, val);
}
}
void
dns_zone_setmaxtypepername(dns_zone_t *zone, uint32_t val) {
REQUIRE(DNS_ZONE_VALID(zone));
zone->maxtypepername = val;
if (zone->db != NULL) {
dns_db_setmaxtypepername(zone->db, val);
}
}
static bool
notify_isqueued(dns_zone_t *zone, unsigned int flags, dns_name_t *name,
isc_sockaddr_t *addr, dns_tsigkey_t *key,
@ -14458,6 +14481,9 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
goto cleanup;
}
dns_db_setloop(stub->db, zone->loop);
dns_db_setmaxrrperset(stub->db, zone->maxrrperset);
dns_db_setmaxtypepername(stub->db,
zone->maxtypepername);
}
result = dns_db_newversion(stub->db, &stub->version);
@ -17514,6 +17540,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) {
}
zone_attachdb(zone, db);
dns_db_setloop(zone->db, zone->loop);
dns_db_setmaxrrperset(zone->db, zone->maxrrperset);
dns_db_setmaxtypepername(zone->db, zone->maxtypepername);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED | DNS_ZONEFLG_NEEDNOTIFY);
return (ISC_R_SUCCESS);
@ -22470,7 +22498,11 @@ failure:
* Something went wrong; try again in ten minutes or
* after a key refresh interval, whichever is shorter.
*/
dnssec_log(zone, ISC_LOG_DEBUG(3),
int loglevel = ISC_LOG_DEBUG(3);
if (result != DNS_R_NOTLOADED) {
loglevel = ISC_LOG_ERROR;
}
dnssec_log(zone, loglevel,
"zone_rekey failure: %s (retry in %u seconds)",
isc_result_totext(result),
ISC_MIN(zone->refreshkeyinterval, 600));
@ -24153,6 +24185,8 @@ dns_zone_makedb(dns_zone_t *zone, dns_db_t **dbp) {
}
dns_db_setloop(db, zone->loop);
dns_db_setmaxrrperset(db, zone->maxrrperset);
dns_db_setmaxtypepername(db, zone->maxtypepername);
*dbp = db;

View File

@ -2372,6 +2372,12 @@ static cfg_clausedef_t zone_clauses[] = {
{ "max-records", &cfg_type_uint32,
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR |
CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT },
{ "max-records-per-type", &cfg_type_uint32,
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR |
CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT },
{ "max-types-per-name", &cfg_type_uint32,
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR |
CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT },
{ "max-refresh-time", &cfg_type_uint32,
CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
{ "max-retry-time", &cfg_type_uint32,

View File

@ -3160,9 +3160,18 @@ update_action(void *arg) {
dns_diff_clear(&ctx.add_diff);
goto failure;
}
CHECK(update_one_rr(db, ver, &diff,
DNS_DIFFOP_ADD,
name, ttl, &rdata));
result = update_one_rr(
db, ver, &diff, DNS_DIFFOP_ADD,
name, ttl, &rdata);
if (result != ISC_R_SUCCESS) {
update_log(client, zone,
LOGLEVEL_PROTOCOL,
"adding an RR "
"failed: %s",
isc_result_totext(
result));
goto failure;
}
}
}
} else if (update_class == dns_rdataclass_any) {