Merge branch '2349-backport-max-ixfr-ration-v9_16' into 'v9_16'

Backport max-ixfr-ratio to BIND 9.16

See merge request isc-projects/bind9!4598
This commit is contained in:
Ondřej Surý
2021-01-26 12:10:22 +00:00
42 changed files with 569 additions and 404 deletions
+7
View File
@@ -2,6 +2,13 @@
BIND 9 version number, in an effort to tightly couple
internal libraries with a specific release. [GL #2387]
5562. [func] Limit the size of IXFR responses so that AXFR will
be used instead if it would be smaller. This is
controlled by the "max-ixfr-ratio" option, which
is a percentage representing the ratio of IXFR size
to the size of the entire zone. This value cannot
exceed 100%, which is the default. [GL #1515]
5561. [bug] KASP incorrectly set signature validity to the value
of the DNSKEY signature validity. This is now fixed.
[GL #2383]
Vendored
+1 -1
View File
@@ -1,4 +1,4 @@
# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
# generated automatically by aclocal 1.16.3 -*- Autoconf -*-
# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+1
View File
@@ -81,6 +81,7 @@ options {\n\
listen-on-v6 {any;};\n\
# lock-file \"" NAMED_LOCALSTATEDIR "/run/named/named.lock\";\n\
match-mapped-addresses no;\n\
max-ixfr-ratio 100%;\n\
max-rsa-exponent-size 0; /* no limit */\n\
max-udp-size 1232;\n\
memstatistics-file \"named.memstats\";\n\
+9
View File
@@ -1398,6 +1398,15 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
ixfrdiff);
}
obj = NULL;
result = named_config_get(maps, "max-ixfr-ratio", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
if (cfg_obj_isstring(obj)) {
dns_zone_setixfrratio(zone, 0);
} else {
dns_zone_setixfrratio(zone, cfg_obj_aspercentage(obj));
}
obj = NULL;
result = named_config_get(maps, "request-expire", &obj);
INSIST(result == ISC_R_SUCCESS);
@@ -0,0 +1,17 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
zone example {
type master;
masterfile-format map;
file "example.db";
max-ixfr-ratio 0.9;
};
@@ -0,0 +1,17 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
zone example {
type master;
masterfile-format map;
file "example.db";
max-ixfr-ratio 0%;
};
@@ -0,0 +1,17 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
zone example {
type master;
masterfile-format map;
file "example.db";
max-ixfr-ratio 50%;
};
@@ -0,0 +1,17 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
zone example {
type master;
masterfile-format map;
file "example.db";
max-ixfr-ratio unlimited;
};
+3
View File
@@ -81,6 +81,7 @@ options {
"corp";
};
dnssec-policy "test";
max-ixfr-ratio 90%;
transfer-source 0.0.0.0 dscp 63;
zone-statistics none;
};
@@ -92,11 +93,13 @@ view "first" {
type master;
file "xxx";
update-policy local;
max-ixfr-ratio 20%;
notify-source 10.10.10.10 port 53 dscp 55;
};
zone "clone" {
type master;
file "yyy";
max-ixfr-ratio unlimited;
};
dnssec-validation auto;
zone-statistics terse;
+8 -1
View File
@@ -559,9 +559,16 @@ awk 'BEGIN { ok = 0; } /cut here/ { ok = 1; getline } ok == 1 { print }' good-ka
[ -s good-kasp.conf.in ] || ret=1
$CHECKCONF -p good-kasp.conf.in | grep -v '^good-kasp.conf.in:' > good-kasp.conf.out 2>&1 || ret=1
cmp good-kasp.conf.in good-kasp.conf.out || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "check that max-ixfr-ratio 100% generates a warning ($n)"
ret=0
$CHECKCONF warn-maxratio1.conf > checkconf.out$n 2>/dev/null || ret=1
grep "exceeds 100%" < checkconf.out$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; ret=1; fi
status=`expr $status + $ret`
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1
@@ -0,0 +1,17 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
zone example {
type master;
masterfile-format map;
file "example.db";
max-ixfr-ratio 101%;
};
+2 -2
View File
@@ -11,12 +11,12 @@
rm -f stats.*
rm -f ns1/*.db ns1/*.jnl
rm -f ns3/*.jnl ns3/mytest.db ns3/subtest.db
rm -f ns3/*.jnl ns3/mytest*.db ns3/subtest*.db
rm -f ns4/*.jnl ns4/*.db
rm -f ns5/*.jnl ns5/*.db
rm -f */named.memstats
rm -f */named.conf
rm -f */named.run
rm -f */named.run */named.run.prev
rm -f */ans.run
rm -f dig.out.test* dig.out1.test* dig.out2.test* dig.out3.test*
rm -f ns3/large.db
+2 -2
View File
@@ -1,3 +1,3 @@
messages=1
records=6
bytes=219
records=5
bytes=204
-1
View File
@@ -1 +0,0 @@
named.conf
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* 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 http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
query-source address 10.53.0.1;
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion no;
notify yes;
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
-26
View File
@@ -1,26 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$ORIGIN test.
$TTL 15
test. 15 IN SOA ns1.test. hostmaster.test. (
1 ; serial
3H ; refresh
15 ; retry
1w ; expire
3h ; minimum
)
IN NS ns1.test.
IN NS ns2.test.
IN NS ns5.test.
ns1 IN A 10.53.0.3
ns2 IN A 10.53.0.4
ns5 IN A 10.53.0.5
host1 IN A 192.168.10.3
host2 IN A 192.168.10.4
-26
View File
@@ -1,26 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$ORIGIN test.
$TTL 15
test. 15 IN SOA ns1.test. hostmaster.test. (
2 ; serial
3H ; refresh
15 ; retry
1w ; expire
3h ; minimum
)
IN NS ns1.test.
IN NS ns2.test.
IN NS ns5.test.
ns1 IN A 10.53.0.3
ns2 IN A 10.53.0.4
ns5 IN A 10.53.0.5
host1 IN A 192.168.10.13
host2 IN A 192.168.10.4
-26
View File
@@ -1,26 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$ORIGIN test.
$TTL 15
test. 15 IN SOA ns1.test. hostmaster.test. (
3 ; serial
3H ; refresh
15 ; retry
1w ; expire
3h ; minimum
)
IN NS ns1.test.
IN NS ns2.test.
IN NS ns5.test.
ns1 IN A 10.53.0.3
ns2 IN A 10.53.0.4
ns5 IN A 10.53.0.5
host1 IN A 192.168.10.13
host2 IN A 192.168.10.14
+1
View File
@@ -37,6 +37,7 @@ view "primary" {
zone "test" IN {
type primary;
file "mytest.db";
max-ixfr-ratio 75%;
};
zone "sub.test" IN {
type primary;
-22
View File
@@ -1,22 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$ORIGIN sub.test.
$TTL 15
sub.test. 15 IN SOA ns1.test. hostmaster.test. (
1 ; serial
3H ; refresh
15 ; retry
1w ; expire
3h ; minimum
)
IN NS ns1.test.
IN NS ns2.test.
host3 IN A 192.168.10.23
host4 IN A 192.168.10.24
-22
View File
@@ -1,22 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; 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 http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$ORIGIN sub.test.
$TTL 15
sub.test. 15 IN SOA ns1.test. hostmaster.test. (
3 ; serial
3H ; refresh
15 ; retry
1w ; expire
3h ; minimum
)
IN NS ns1.test.
IN NS ns2.test.
host3 IN A 192.168.10.123
host4 IN A 192.168.10.24
+1
View File
@@ -37,6 +37,7 @@ view "primary" {
type secondary;
file "mytest.db";
primaries { 10.53.0.3; };
max-ixfr-ratio unlimited;
};
zone "sub.test" IN {
type secondary;
+47 -26
View File
@@ -12,35 +12,56 @@
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
cat <<EOF >ns1/named.conf
options {
query-source address 10.53.0.1;
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
port ${PORT};
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion no;
notify yes;
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.1 port ${CONTROLPORT} allow { any; } keys { rndc_key; };
};
EOF
$SHELL clean.sh
copy_setports ns1/named.conf.in ns1/named.conf
copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns4/named.conf.in ns4/named.conf
copy_setports ns5/named.conf.in ns5/named.conf
# Setup initial db files for ns3
cp ns3/mytest0.db ns3/mytest.db
cp ns3/subtest0.db ns3/subtest.db
# Set up db files for zone "test" - this is a series of four
# versions of the zone, the second and third having small changes
# and the fourth having a large one.
testdb () {
cat << EOF
\$ORIGIN $1
\$TTL 15
@ 15 IN SOA ns1.test. hostmaster.test. (
$2 ; serial
3H ; refresh
15 ; retry
1w ; expire
3h ; minimum
)
IN NS ns1.test.
IN NS ns2.test.
IN NS ns5.test.
ns1 IN A 10.53.0.3
ns2 IN A 10.53.0.4
ns5 IN A 10.53.0.5
EOF
i=0
while [ $i -lt $3 ]; do
echo "host$i IN A 192.0.2.$i"
i=$((i+1))
done
}
testdb test. 1 60 > ns3/mytest.db
testdb test. 2 61 > ns3/mytest1.db
testdb test. 3 62 > ns3/mytest2.db
testdb test. 4 0 > ns3/mytest3.db
# Set up similar db files for sub.test, which will have IXFR disabled
testdb sub.test. 1 60 > ns3/subtest.db
testdb sub.test. 3 61 > ns3/subtest1.db
# Set up a large zone
i=0
$SHELL ../genzone.sh 3 > ns3/large.db
awk 'END { for (i = 0; i < 10000; i++) printf("record%d 10 IN TXT this is record %d\n", i, i) }' < /dev/null >> ns3/large.db
while [ $i -lt 10000 ]; do
echo "record$i 10 IN TXT this is record %i" >> ns3/large.db
i=$((i+1))
done
+122 -197
View File
@@ -18,6 +18,12 @@
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
wait_for_serial() (
$DIG $DIGOPTS "@$1" "$2" SOA > "$4"
serial=$(awk '$4 == "SOA" { print $7 }' "$4")
[ "$3" -eq "${serial:--1}" ]
)
status=0
n=0
@@ -27,6 +33,7 @@ RNDCCMD="$RNDC -p ${CONTROLPORT} -c ../common/rndc.conf -s"
n=$((n+1))
echo_i "testing initial AXFR ($n)"
ret=0
$SENDCMD <<EOF
/SOA/
@@ -58,20 +65,15 @@ EOF
rndc_reload ns1 10.53.0.1
for i in 0 1 2 3 4 5 6 7 8 9
do
$DIG $DIGOPTS @10.53.0.1 nil. SOA > dig.out.test$n
grep "SOA" dig.out.test$n > /dev/null && break
sleep 1
done
retry_quiet 10 wait_for_serial 10.53.0.1 nil. 1 dig.out.test$n || ret=1
$DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'initial AXFR' >/dev/null || {
echo_i "failed"
status=1
}
$DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'initial AXFR' >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "testing successful IXFR ($n)"
ret=0
# We change the IP address of a.nil., and the TXT record at the apex.
# Then we do a SOA-only update.
@@ -94,17 +96,17 @@ EOF
sleep 1
$RNDCCMD 10.53.0.1 refresh nil
$RNDCCMD 10.53.0.1 refresh nil | sed 's/^/ns1 /' | cat_i
sleep 2
$DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'successful IXFR' >/dev/null || {
echo_i "failed"
status=1
}
$DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'successful IXFR' >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "testing AXFR fallback after IXFR failure ($n)"
ret=0
# Provide a broken IXFR response and a working fallback AXFR response
@@ -129,14 +131,13 @@ EOF
sleep 1
$RNDCCMD 10.53.0.1 refresh nil
$RNDCCMD 10.53.0.1 refresh nil | sed 's/^/ns1 /' | cat_i
sleep 2
$DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'fallback AXFR' >/dev/null || {
echo_i "failed"
status=1
}
$DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'fallback AXFR' >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "testing ixfr-from-differences option ($n)"
@@ -146,150 +147,84 @@ if [ $? -ne 0 ]
then
echo_i "named-checkzone returned failure on ns3/mytest.db"
fi
# modify the primary
#echo_i "digging against primary: "
#$DIG $DIGOPTS @10.53.0.3 a host1.test.
#echo_i "digging against secondary: "
#$DIG $DIGOPTS @10.53.0.4 a host1.test.
# wait for secondary to be stable
for i in 0 1 2 3 4 5 6 7 8 9
do
$DIG $DIGOPTS +tcp @10.53.0.4 SOA test > dig.out.test$n
grep -i "hostmaster\.test\..1" dig.out.test$n > /dev/null && break
sleep 1
done
retry_quiet 10 wait_for_serial 10.53.0.4 test. 1 dig.out.test$n || ret=1
nextpart ns4/named.run > /dev/null
# modify the primary
cp ns3/mytest1.db ns3/mytest.db
$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i
#wait for primary to reload load
for i in 0 1 2 3 4 5 6 7 8 9
do
$DIG $DIGOPTS +tcp @10.53.0.3 SOA test > dig.out.test$n
grep -i "hostmaster\.test\..2" dig.out.test$n > /dev/null && break
sleep 1
done
# wait for primary to reload
retry_quiet 10 wait_for_serial 10.53.0.3 test. 2 dig.out.test$n || ret=1
#wait for secondary to transfer zone
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
do
$DIG $DIGOPTS +tcp @10.53.0.4 SOA test > dig.out.test$n
grep -i "hostmaster\.test\..2" dig.out.test$n > /dev/null && break
# re-notify if we've been waiting a long time
if [ $i -ge 5 ]; then
$RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i
fi
sleep 1
done
# secondary should have gotten notify and updated
for i in 0 1 2 3 4 5 6 7 8 9
do
INCR=`grep "test/IN/primary" ns4/named.run|grep "got incremental"|wc -l`
[ $INCR -eq 1 ] && break
sleep 1
done
if [ $INCR -ne 1 ]
then
echo_i "failed to get incremental response"
status=1
# wait for secondary to reload
tret=0
retry_quiet 5 wait_for_serial 10.53.0.4 test. 2 dig.out.test$n || tret=1
if [ $tret -eq 1 ]; then
# re-noitfy after 5 seconds, then wait another 10
$RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i
retry_quiet 10 wait_for_serial 10.53.0.4 test. 2 dig.out.test$n || ret=1
fi
wait_for_log 10 'got incremental' ns4/named.run || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "testing request-ixfr option in view vs zone ($n)"
echo_i "testing 'request-ixfr no' option inheritance from view ($n)"
ret=0
# There's a view with 2 zones. In the view, "request-ixfr yes"
# but in the zone "sub.test", request-ixfr no"
# we want to make sure that a change to sub.test results in AXFR, while
# changes to test. result in IXFR
echo_ic "this result should be AXFR"
cp ns3/subtest1.db ns3/subtest.db # change to sub.test zone, should be AXFR
nextpart ns4/named.run > /dev/null
$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i
#wait for primary to reload zone
for i in 0 1 2 3 4 5 6 7 8 9
do
$DIG $DIGOPTS +tcp @10.53.0.3 SOA sub.test > dig.out.test$n
grep -i "hostmaster\.test\..3" dig.out.test$n > /dev/null && break
sleep 1
done
# wait for primary to reload
retry_quiet 10 wait_for_serial 10.53.0.3 sub.test. 3 dig.out.test$n || ret=1
#wait for secondary to transfer zone
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
do
$DIG $DIGOPTS +tcp @10.53.0.4 SOA sub.test > dig.out.test$n
grep -i "hostmaster\.test\..3" dig.out.test$n > /dev/null && break
# re-notify if we've been waiting a long time
if [ $i -ge 5 ]; then
$RNDCCMD 10.53.0.3 notify sub.test | set 's/^/ns3 /' | cat_i
fi
sleep 1
done
echo_ic "this result should be AXFR"
for i in 0 1 2 3 4 5 6 7 8 9
do
NONINCR=`grep 'sub\.test/IN/primary' ns4/named.run|grep "got nonincremental" | wc -l`
[ $NONINCR -eq 2 ] && break
sleep 1
done
if [ $NONINCR -ne 2 ]
then
echo_ic "failed to get nonincremental response in 2nd AXFR test"
echo_i "failed"
status=1
else
echo_ic "success: AXFR it was"
# wait for secondary to reload
tret=0
retry_quiet 5 wait_for_serial 10.53.0.4 sub.test. 3 dig.out.test$n || tret=1
if [ $tret -eq 1 ]; then
# re-noitfy after 5 seconds, then wait another 10
$RNDCCMD 10.53.0.3 notify sub.test | set 's/^/ns3 /' | cat_i
retry_quiet 10 wait_for_serial 10.53.0.4 sub.test. 3 dig.out.test$n || ret=1
fi
echo_ic "this result should be IXFR"
cp ns3/mytest2.db ns3/mytest.db # change to test zone, should be IXFR
$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i
# wait for primary to reload zone
for i in 0 1 2 3 4 5 6 7 8 9
do
$DIG +tcp -p 5300 @10.53.0.3 SOA test > dig.out.test$n
grep -i "hostmaster\.test\..4" dig.out.test$n > /dev/null && break
sleep 1
done
# wait for secondary to transfer zone
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
do
$DIG $DIGOPTS +tcp @10.53.0.4 SOA test > dig.out.test$n
grep -i "hostmaster\.test\..4" dig.out.test$n > /dev/null && break
# re-notify if we've been waiting a long time
if [ $i -ge 5 ]; then
$RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i
fi
sleep 1
done
for i in 0 1 2 3 4 5 6 7 8 9
do
INCR=`grep "test/IN/primary" ns4/named.run|grep "got incremental"|wc -l`
[ $INCR -eq 2 ] && break
sleep 1
done
if [ $INCR -ne 2 ]
then
echo_ic "failed to get incremental response in 2nd IXFR test"
echo_i "failed"
status=1
else
echo_ic "success: IXFR it was"
fi
wait_for_log 10 'got nonincremental response' ns4/named.run || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "testing 'request-ixfr yes' option inheritance from view ($n)"
ret=0
cp ns3/mytest2.db ns3/mytest.db # change to test zone, should be IXFR
nextpart ns4/named.run > /dev/null
$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i
# wait for primary to reload
retry_quiet 10 wait_for_serial 10.53.0.3 test. 3 dig.out.test$n || ret=1
# wait for secondary to reload
tret=0
retry_quiet 5 wait_for_serial 10.53.0.4 test. 3 dig.out.test$n || tret=1
if [ $tret -eq 1 ]; then
# re-noitfy after 5 seconds, then wait another 10
$RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i
retry_quiet 10 wait_for_serial 10.53.0.4 test. 3 dig.out.test$n || ret=1
fi
wait_for_log 10 'got incremental response' ns4/named.run || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
ret=0
echo_i "testing DiG's handling of a multi message AXFR style IXFR response ($n)"
(
(sleep 10 && kill $$) 2>/dev/null &
@@ -298,9 +233,11 @@ $DIG -p ${PORT} ixfr=0 large @10.53.0.3 > dig.out.test$n
kill $sub
)
lines=`grep hostmaster.large dig.out.test$n | wc -l`
test ${lines:-0} -eq 2 || { echo_i "failed"; status=1; }
test ${lines:-0} -eq 2 || ret=1
messages=`sed -n 's/^;;.*messages \([0-9]*\),.*/\1/p' dig.out.test$n`
test ${messages:-0} -gt 1 || { echo_i "failed"; status=1; }
test ${messages:-0} -gt 1 || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "test 'dig +notcp ixfr=<value>' vs 'dig ixfr=<value> +notcp' vs 'dig ixfr=<value>' ($n)"
@@ -314,24 +251,19 @@ awk '$4 == "SOA" { if ($7 == 3) exit(0); else exit(1);}' dig.out1.test$n || ret=
# Should be incremental transfer.
$DIG $DIGOPTS ixfr=1 test @10.53.0.4 > dig.out3.test$n || ret=1
awk '$4 == "SOA" { soacnt++} END { if (soacnt == 6) exit(0); else exit(1);}' dig.out3.test$n || ret=1
if [ ${ret} != 0 ]; then
echo_i "failed"
status=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
# make sure ns5 has transfered the zone
# wait for secondary to reload
tret=0
retry_quiet 5 wait_for_serial 10.53.0.5 test. 4 dig.out.test$n || tret=1
if [ $tret -eq 1 ]; then
# re-noitfy after 5 seconds, then wait another 10
$RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i
retry_quiet 10 wait_for_serial 10.53.0.5 test. 3 dig.out.test$n || ret=1
fi
# wait for secondary to transfer zone
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
do
$DIG $DIGOPTS +tcp @10.53.0.5 SOA test > dig.out.test$n
grep -i "hostmaster\.test\..4" dig.out.test$n > /dev/null && break
# re-notify if we've been waiting a long time
if [ $i -ge 5 ]; then
$RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i
fi
sleep 1
done
n=$((n+1))
echo_i "test 'provide-ixfr no;' (serial < current) ($n)"
ret=0
@@ -342,32 +274,6 @@ $DIG $DIGOPTS ixfr=1 test @10.53.0.5 > dig.out1.test$n || ret=1
$DIG $DIGOPTS ixfr=1 +notcp test @10.53.0.5 > dig.out2.test$n || ret=1
awk '$4 == "SOA" { soacnt++} END {if (soacnt == 2) exit(0); else exit(1);}' dig.out1.test$n || ret=1
awk '$4 == "SOA" { soacnt++} END {if (soacnt == 1) exit(0); else exit(1);}' dig.out2.test$n || ret=1
msg="IXFR delta response disabled due to 'provide-ixfr no;' being set"
nextpart ns5/named.run | grep "$msg" > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "test 'provide-ixfr no;' (serial = current) ($n)"
ret=0
# Should be "AXFR style" response
$DIG $DIGOPTS ixfr=3 test @10.53.0.5 > dig.out1.test$n || ret=1
# Should be "switch to TCP" response
$DIG $DIGOPTS ixfr=3 +notcp test @10.53.0.5 > dig.out2.test$n || ret=1
awk '$4 == "SOA" { soacnt++} END {if (soacnt == 1) exit(0); else exit(1);}' dig.out1.test$n || ret=1
awk '$4 == "SOA" { soacnt++} END {if (soacnt == 1) exit(0); else exit(1);}' dig.out2.test$n || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "test 'provide-ixfr no;' (serial > current) ($n)"
ret=0
# Should be "AXFR style" response
$DIG $DIGOPTS ixfr=4 test @10.53.0.5 > dig.out1.test$n || ret=1
# Should be "switch to TCP" response
$DIG $DIGOPTS ixfr=4 +notcp test @10.53.0.5 > dig.out2.test$n || ret=1
awk '$4 == "SOA" { soacnt++} END {if (soacnt == 1) exit(0); else exit(1);}' dig.out1.test$n || ret=1
awk '$4 == "SOA" { soacnt++} END {if (soacnt == 1) exit(0); else exit(1);}' dig.out2.test$n || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@@ -376,32 +282,51 @@ echo_i "checking whether dig calculates IXFR statistics correctly ($n)"
ret=0
$DIG $DIGOPTS +noedns +stat -b 10.53.0.4 @10.53.0.4 test. ixfr=2 > dig.out1.test$n
get_dig_xfer_stats dig.out1.test$n > stats.dig
diff ixfr-stats.good stats.dig || ret=1
diff ixfr-stats.good stats.dig > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
# Note: in the next two tests, we use ns4 logs for checking both incoming and
# outgoing transfer statistics as ns4 is both a secondary server (for ns3) and a
# primary server (for dig queries from the previous test) for "test".
_wait_for_stats () {
get_named_xfer_stats ns4/named.run "$1" test "$2" > "$3"
diff ixfr-stats.good "$3" > /dev/null || return 1
return 0
}
n=$((n+1))
echo_i "checking whether named calculates incoming IXFR statistics correctly ($n)"
ret=0
get_named_xfer_stats ns4/named.run 10.53.0.3 test "Transfer completed" > stats.incoming
diff ixfr-stats.good stats.incoming || ret=1
retry_quiet 10 _wait_for_stats 10.53.0.3 "Transfer completed" stats.incoming
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "checking whether named calculates outgoing IXFR statistics correctly ($n)"
ret=1
for i in 0 1 2 3 4 5 6 7 8 9; do
get_named_xfer_stats ns4/named.run 10.53.0.4 test "IXFR ended" > stats.outgoing
if diff ixfr-stats.good stats.outgoing > /dev/null; then
ret=0
break
fi
sleep 1
done
retry_quiet 10 _wait_for_stats 10.53.0.4 "IXFR ended" stats.outgoing
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
ret=0
echo_i "testing fallback to AXFR when max-ixfr-ratio is exceeded ($n)"
nextpart ns4/named.run > /dev/null
cp ns3/mytest3.db ns3/mytest.db # change to test zone, too big for IXFR
$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i
# wait for secondary to reload
tret=0
retry_quiet 5 wait_for_serial 10.53.0.4 test. 4 dig.out.test$n || tret=1
if [ $tret -eq 1 ]; then
# re-noitfy after 5 seconds, then wait another 10
$RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i
retry_quiet 10 wait_for_serial 10.53.0.4 test. 4 dig.out.test$n || ret=1
fi
wait_for_log 10 'got nonincremental response' ns4/named.run || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
Regular → Executable
View File
+1
View File
@@ -35,6 +35,7 @@ zone <string> [ <class> ] {
key-directory <quoted_string>;
masterfile-format ( map | raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-transfer-idle-out <integer>;
+1
View File
@@ -16,6 +16,7 @@ zone <string> [ <class> ] {
masterfile-format ( map | raw | text );
masterfile-style ( full | relative );
masters [ port <integer> ] [ dscp <integer> ] { ( <primaries> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ]; ... };
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-refresh-time <integer>;
+4
View File
@@ -241,6 +241,7 @@ options {
max-cache-ttl <duration>;
max-clients-per-query <integer>;
max-ixfr-log-size ( default | unlimited | <sizeval> ); // ancient
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-records <integer>;
@@ -608,6 +609,7 @@ view <string> [ <class> ] {
max-cache-ttl <duration>;
max-clients-per-query <integer>;
max-ixfr-log-size ( default | unlimited | <sizeval> ); // ancient
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-records <integer>;
@@ -835,6 +837,7 @@ view <string> [ <class> ] {
... };
max-ixfr-log-size ( default | unlimited |
<sizeval> ); // ancient
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-refresh-time <integer>;
@@ -943,6 +946,7 @@ zone <string> [ <class> ] {
<ipv4_address> [ port <integer> ] | <ipv6_address> [ port
<integer> ] ) [ key <string> ]; ... };
max-ixfr-log-size ( default | unlimited | <sizeval> ); // ancient
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-refresh-time <integer>;
+4
View File
@@ -215,6 +215,7 @@ options {
max-cache-size ( default | unlimited | <sizeval> | <percentage> );
max-cache-ttl <duration>;
max-clients-per-query <integer>;
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-records <integer>;
@@ -545,6 +546,7 @@ view <string> [ <class> ] {
max-cache-size ( default | unlimited | <sizeval> | <percentage> );
max-cache-ttl <duration>;
max-clients-per-query <integer>;
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-ncache-ttl <duration>;
max-records <integer>;
@@ -755,6 +757,7 @@ view <string> [ <class> ] {
<primaries> | <ipv4_address> [ port <integer> ] |
<ipv6_address> [ port <integer> ] ) [ key <string> ];
... };
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-refresh-time <integer>;
@@ -856,6 +859,7 @@ zone <string> [ <class> ] {
masters [ port <integer> ] [ dscp <integer> ] { ( <primaries> |
<ipv4_address> [ port <integer> ] | <ipv6_address> [ port
<integer> ] ) [ key <string> ]; ... };
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-refresh-time <integer>;
+1
View File
@@ -28,6 +28,7 @@ zone <string> [ <class> ] {
masterfile-format ( map | raw | text );
masterfile-style ( full | relative );
masters [ port <integer> ] [ dscp <integer> ] { ( <primaries> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ]; ... };
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-refresh-time <integer>;
+12 -1
View File
@@ -24,7 +24,18 @@ Known Issues
New Features
~~~~~~~~~~~~
- None.
- When a secondary server receives a large incremental zone
transfer (IXFR), it can have a negative impact on query
performance while the incremental changes are applied to
the zone. To address this, ``named`` can now
limit the size of IXFR responses it sends in response to zone
transfer requests. If an IXFR response would be larger than an
AXFR of the entire zone, it will send an AXFR resonse instead.
This behavior is controlled by the ``max-ixfr-ratio``
option - a percentage value representing the ratio of IXFR size
to the size of a full zone transfer. This value cannot exceed
100%, which is also the default. [GL #1515]
Removed Features
~~~~~~~~~~~~~~~~
+18
View File
@@ -1567,6 +1567,24 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
}
}
obj = NULL;
(void)cfg_map_get(options, "max-ixfr-ratio", &obj);
if (obj != NULL && cfg_obj_ispercentage(obj)) {
uint32_t percent = cfg_obj_aspercentage(obj);
if (percent == 0) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"'ixfr-max-ratio' must be a nonzero "
"percentage or 'unlimited')");
if (result == ISC_R_SUCCESS) {
result = ISC_R_RANGE;
}
} else if (percent > 100) {
cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
"'ixfr-max-ratio %d%%' exceeds 100%%",
percent);
}
}
obj = NULL;
(void)cfg_map_get(options, "check-names", &obj);
if (obj != NULL && !cfg_obj_islist(obj)) {
+3 -3
View File
@@ -1489,10 +1489,10 @@ dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
isc_result_t
dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
uint64_t *bytes);
uint64_t *xfrsize);
/*%<
* On success if 'records' is not NULL, it is set to the number of records
* in the given version of the database. If 'bytes' is not NULL, it is
* in the given version of the database. If 'xfrisize' is not NULL, it is
* set to the approximate number of bytes needed to transfer the records,
* counting name, TTL, type, class, and rdata for each RR. (This is meant
* to be a rough approximation of the size of a full zone transfer, though
@@ -1502,7 +1502,7 @@ dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
* \li 'db' is a valid zone database.
* \li 'version' is NULL or a valid version.
* \li 'records' is NULL or a pointer to return the record count in.
* \li 'bytes' is NULL or a pointer to return the byte count in.
* \li 'xfrsize' is NULL or a pointer to return the byte count in.
*
* Returns:
* \li #ISC_R_SUCCESS
+7 -1
View File
@@ -190,11 +190,17 @@ dns_journal_last_serial(dns_journal_t *j);
isc_result_t
dns_journal_iter_init(dns_journal_t *j, uint32_t begin_serial,
uint32_t end_serial);
uint32_t end_serial, size_t *xfrsizep);
/*%<
* Prepare to iterate over the transactions that will bring the database
* from SOA serial number 'begin_serial' to 'end_serial'.
*
* If 'xfrsizep' is not NULL, then on success it will be set to the
* total size of all records in the iteration (excluding headers). This
* is meant to be a rough approximation of the size of an incremental
* zone transfer, though it does not account for DNS message overhead
* or name compression.)
*
* Returns:
*\li ISC_R_SUCCESS
*\li ISC_R_RANGE begin_serial is outside the addressable range.
+19
View File
@@ -2338,6 +2338,25 @@ dns_zone_setrequestixfr(dns_zone_t *zone, bool flag);
* \li 'zone' to be valid.
*/
uint32_t
dns_zone_getixfrratio(dns_zone_t *zone);
/*%
* Returns the zone's current IXFR ratio.
*
* Requires:
* \li 'zone' to be valid.
*/
void
dns_zone_setixfrratio(dns_zone_t *zone, uint32_t ratio);
/*%
* Sets the ratio of IXFR size to zone size above which we use an AXFR
* response, expressed as a percentage. Cannot exceed 100.
*
* Requires:
* \li 'zone' to be valid.
*/
void
dns_zone_setserialupdatemethod(dns_zone_t *zone, dns_updatemethod_t method);
/*%
+54 -13
View File
@@ -221,6 +221,7 @@ typedef union {
*/
typedef struct {
unsigned char size[4]; /*%< In bytes, excluding header. */
unsigned char count[4]; /*%< Number of records in transaction */
unsigned char serial0[4]; /*%< SOA serial before update. */
unsigned char serial1[4]; /*%< SOA serial after update. */
} journal_rawxhdr_t;
@@ -256,9 +257,9 @@ typedef struct {
/*%
* The in-core representation of the transaction header.
*/
typedef struct {
uint32_t size;
uint32_t count;
uint32_t serial0;
uint32_t serial1;
} journal_xhdr_t;
@@ -304,13 +305,13 @@ struct dns_journal {
isc_offset_t offset; /*%< Current file offset */
journal_header_t header; /*%< In-core journal header */
unsigned char *rawindex; /*%< In-core buffer for journal index
* in
* on-disk format */
* in on-disk format */
journal_pos_t *index; /*%< In-core journal index */
/*% Current transaction state (when writing). */
struct {
unsigned int n_soa; /*%< Number of SOAs seen */
unsigned int n_rr; /*%< Number of RRs to write */
journal_pos_t pos[2]; /*%< Begin/end position */
} x;
@@ -323,8 +324,7 @@ struct dns_journal {
uint32_t current_serial; /*%< Current SOA serial
* */
isc_buffer_t source; /*%< Data from disk */
isc_buffer_t target; /*%< Data from _fromwire check
* */
isc_buffer_t target; /*%< Data from _fromwire check */
dns_decompress_t dctx; /*%< Dummy decompression ctx */
dns_name_t name; /*%< Current domain name */
dns_rdata_t rdata; /*%< Current rdata */
@@ -462,16 +462,18 @@ journal_read_xhdr(dns_journal_t *j, journal_xhdr_t *xhdr) {
return (result);
}
xhdr->size = decode_uint32(raw.size);
xhdr->count = decode_uint32(raw.count);
xhdr->serial0 = decode_uint32(raw.serial0);
xhdr->serial1 = decode_uint32(raw.serial1);
return (ISC_R_SUCCESS);
}
static isc_result_t
journal_write_xhdr(dns_journal_t *j, uint32_t size, uint32_t serial0,
uint32_t serial1) {
journal_write_xhdr(dns_journal_t *j, uint32_t size, uint32_t count,
uint32_t serial0, uint32_t serial1) {
journal_rawxhdr_t raw;
encode_uint32(size, raw.size);
encode_uint32(count, raw.count);
encode_uint32(serial0, raw.serial0);
encode_uint32(serial1, raw.serial1);
return (journal_write(j, &raw, sizeof(raw)));
@@ -1026,7 +1028,8 @@ dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) {
dns_difftuple_t *t;
isc_buffer_t buffer;
void *mem = NULL;
uint64_t size;
uint64_t size = 0;
uint32_t rrcount = 0;
isc_result_t result;
isc_region_t used;
@@ -1040,7 +1043,6 @@ dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) {
* Pass 1: determine the buffer size needed, and
* keep track of SOA serial numbers.
*/
size = 0;
for (t = ISC_LIST_HEAD(diff->tuples); t != NULL;
t = ISC_LIST_NEXT(t, link)) {
if (t->rdata.type == dns_rdatatype_soa) {
@@ -1089,12 +1091,15 @@ dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) {
isc_buffer_putuint16(&buffer, (uint16_t)t->rdata.length);
INSIST(isc_buffer_availablelength(&buffer) >= t->rdata.length);
isc_buffer_putmem(&buffer, t->rdata.data, t->rdata.length);
rrcount++;
}
isc_buffer_usedregion(&buffer, &used);
INSIST(used.length == size);
j->x.pos[1].offset += used.length;
j->x.n_rr = rrcount;
/*
* Write the buffer contents to the journal file.
@@ -1205,7 +1210,8 @@ dns_journal_commit(dns_journal_t *j) {
* Update the transaction header.
*/
CHECK(journal_seek(j, j->x.pos[0].offset));
CHECK(journal_write_xhdr(j, offset, j->x.pos[0].serial,
CHECK(journal_write_xhdr(j, offset, j->x.n_rr,
j->x.pos[0].serial,
j->x.pos[1].serial));
}
@@ -1355,7 +1361,7 @@ roll_forward(dns_journal_t *j, dns_db_t *db, unsigned int options) {
CHECK(DNS_R_UPTODATE);
}
CHECK(dns_journal_iter_init(j, db_serial, end_serial));
CHECK(dns_journal_iter_init(j, db_serial, end_serial, NULL));
for (result = dns_journal_first_rr(j); result == ISC_R_SUCCESS;
result = dns_journal_next_rr(j))
@@ -1515,7 +1521,7 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
start_serial = dns_journal_first_serial(j);
end_serial = dns_journal_last_serial(j);
CHECK(dns_journal_iter_init(j, start_serial, end_serial));
CHECK(dns_journal_iter_init(j, start_serial, end_serial, NULL));
for (result = dns_journal_first_rr(j); result == ISC_R_SUCCESS;
result = dns_journal_next_rr(j))
@@ -1672,7 +1678,7 @@ size_buffer(isc_mem_t *mctx, isc_buffer_t *b, unsigned size) {
isc_result_t
dns_journal_iter_init(dns_journal_t *j, uint32_t begin_serial,
uint32_t end_serial) {
uint32_t end_serial, size_t *xfrsizep) {
isc_result_t result;
CHECK(journal_find(j, begin_serial, &j->it.bpos));
@@ -1681,6 +1687,41 @@ dns_journal_iter_init(dns_journal_t *j, uint32_t begin_serial,
CHECK(journal_find(j, end_serial, &j->it.epos));
INSIST(j->it.epos.serial == end_serial);
if (xfrsizep != NULL) {
journal_pos_t pos = j->it.bpos;
journal_xhdr_t xhdr;
uint64_t size = 0;
uint32_t count = 0;
/*
* We already know the beginning and ending serial
* numbers are in the journal. Scan through them,
* adding up sizes and RR counts so we can calculate
* the IXFR size.
*/
CHECK(journal_seek(j, pos.offset));
do {
CHECK(journal_read_xhdr(j, &xhdr));
size += xhdr.size;
count += xhdr.count;
result = journal_next(j, &pos);
if (result == ISC_R_NOMORE) {
result = ISC_R_SUCCESS;
}
CHECK(result);
} while (pos.serial != end_serial);
/*
* For each RR, subtract the length of the RR header,
* as this would not be present in IXFR messages.
* (We don't need to worry about the transaction header
* because that was already excluded from xdr.size.)
*/
*xfrsizep = size - (count * sizeof(journal_rawrrhdr_t));
}
result = ISC_R_SUCCESS;
failure:
j->it.result = result;
+25 -25
View File
@@ -441,11 +441,11 @@ typedef struct rbtdb_version {
unsigned char salt[DNS_NSEC3_SALTSIZE];
/*
* records and bytes are covered by rwlock.
* records and xfrsize are covered by rwlock.
*/
isc_rwlock_t rwlock;
uint64_t records;
uint64_t bytes;
uint64_t xfrsize;
isc_rwlock_t glue_rwlock;
size_t glue_table_bits;
@@ -1396,7 +1396,7 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) {
RWLOCK(&rbtdb->current_version->rwlock,
isc_rwlocktype_read);
version->records = rbtdb->current_version->records;
version->bytes = rbtdb->current_version->bytes;
version->xfrsize = rbtdb->current_version->xfrsize;
RWUNLOCK(&rbtdb->current_version->rwlock,
isc_rwlocktype_read);
rbtdb->next_serial++;
@@ -6067,18 +6067,18 @@ recordsize(rdatasetheader_t *header, unsigned int namelen) {
}
static void
update_recordsandbytes(bool add, rbtdb_version_t *rbtversion,
rdatasetheader_t *header, unsigned int namelen) {
update_recordsandxfrsize(bool add, rbtdb_version_t *rbtversion,
rdatasetheader_t *header, unsigned int namelen) {
unsigned char *hdr = (unsigned char *)header;
size_t hdrsize = sizeof(*header);
RWLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
if (add) {
rbtversion->records += dns_rdataslab_count(hdr, hdrsize);
rbtversion->bytes += recordsize(header, namelen);
rbtversion->xfrsize += recordsize(header, namelen);
} else {
rbtversion->records -= dns_rdataslab_count(hdr, hdrsize);
rbtversion->bytes -= recordsize(header, namelen);
rbtversion->xfrsize -= recordsize(header, namelen);
}
RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
}
@@ -6491,9 +6491,9 @@ find_header:
}
newheader->next = topheader->next;
if (rbtversion != NULL && !header_nx) {
update_recordsandbytes(false, rbtversion,
header,
nodename->length);
update_recordsandxfrsize(false, rbtversion,
header,
nodename->length);
}
free_rdataset(rbtdb, rbtdb->common.mctx, header);
} else {
@@ -6544,9 +6544,9 @@ find_header:
}
}
if (rbtversion != NULL && !header_nx) {
update_recordsandbytes(false, rbtversion,
header,
nodename->length);
update_recordsandxfrsize(false, rbtversion,
header,
nodename->length);
}
}
} else {
@@ -6623,8 +6623,8 @@ find_header:
}
if (rbtversion != NULL && !newheader_nx) {
update_recordsandbytes(true, rbtversion, newheader,
nodename->length);
update_recordsandxfrsize(true, rbtversion, newheader,
nodename->length);
}
/*
@@ -7118,8 +7118,8 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
* to additional info. We need to clear these fields
* to avoid having duplicated references.
*/
update_recordsandbytes(true, rbtversion, newheader,
nodename->length);
update_recordsandxfrsize(true, rbtversion, newheader,
nodename->length);
} else if (result == DNS_R_NXRRSET) {
/*
* This subtraction would remove all of the rdata;
@@ -7155,8 +7155,8 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
* topheader.
*/
INSIST(rbtversion->serial >= topheader->serial);
update_recordsandbytes(false, rbtversion, header,
nodename->length);
update_recordsandxfrsize(false, rbtversion, header,
nodename->length);
if (topheader_prev != NULL) {
topheader_prev->next = newheader;
} else {
@@ -7520,8 +7520,8 @@ rbt_datafixer(dns_rbtnode_t *rbtnode, void *base, size_t filesize, void *arg,
}
}
update_recordsandbytes(true, rbtdb->current_version, header,
rbtnode->fullnamelen);
update_recordsandxfrsize(true, rbtdb->current_version, header,
rbtnode->fullnamelen);
}
/* We're done deserializing; clear fullnamelen */
@@ -8142,7 +8142,7 @@ getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash,
static isc_result_t
getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
uint64_t *bytes) {
uint64_t *xfrsize) {
dns_rbtdb_t *rbtdb;
isc_result_t result = ISC_R_SUCCESS;
rbtdb_version_t *rbtversion = version;
@@ -8162,8 +8162,8 @@ getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
*records = rbtversion->records;
}
if (bytes != NULL) {
*bytes = rbtversion->bytes;
if (xfrsize != NULL) {
*xfrsize = rbtversion->xfrsize;
}
RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_read);
RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
@@ -8805,7 +8805,7 @@ dns_rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
}
rbtdb->current_version->records = 0;
rbtdb->current_version->bytes = 0;
rbtdb->current_version->xfrsize = 0;
rbtdb->future_version = NULL;
ISC_LIST_INIT(rbtdb->open_versions);
/*
+2
View File
@@ -1221,6 +1221,7 @@ dns_zone_getgluecachestats
dns_zone_getidlein
dns_zone_getidleout
dns_zone_getincludes
dns_zone_getixfrratio
dns_zone_getjournal
dns_zone_getjournalsize
dns_zone_getkasp
@@ -1323,6 +1324,7 @@ dns_zone_setforwardacl
dns_zone_setidlein
dns_zone_setidleout
dns_zone_setisself
dns_zone_setixfrratio
dns_zone_setjournal
dns_zone_setjournalsize
dns_zone_setkasp
+2 -2
View File
@@ -1529,10 +1529,10 @@ maybe_free(dns_xfrin_ctx_t *xfr) {
xfrin_log(xfr, ISC_LOG_INFO,
"Transfer completed: %d messages, %d records, "
"%" PRIu64 " bytes, "
"%u.%03u secs (%u bytes/sec)",
"%u.%03u secs (%u bytes/sec) (serial %u)",
xfr->nmsg, xfr->nrecs, xfr->nbytes,
(unsigned int)(msecs / 1000), (unsigned int)(msecs % 1000),
(unsigned int)persec);
(unsigned int)persec, xfr->end_serial);
if (xfr->socket != NULL) {
isc_socket_detach(&xfr->socket);
+15 -1
View File
@@ -407,6 +407,7 @@ struct dns_zone {
* whether ixfr is requested
*/
bool requestixfr;
uint32_t ixfr_ratio;
/*%
* whether EDNS EXPIRE is requested
@@ -1128,6 +1129,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->sourceserial = 0;
zone->sourceserialset = false;
zone->requestixfr = true;
zone->ixfr_ratio = 100;
zone->requestexpire = true;
ISC_LIST_INIT(zone->rss_events);
ISC_LIST_INIT(zone->rss_post);
@@ -15741,7 +15743,7 @@ sync_secure_journal(dns_zone_t *zone, dns_zone_t *raw, dns_journal_t *journal,
return (DNS_R_UNCHANGED);
}
CHECK(dns_journal_iter_init(journal, start, end));
CHECK(dns_journal_iter_init(journal, start, end, NULL));
for (result = dns_journal_first_rr(journal); result == ISC_R_SUCCESS;
result = dns_journal_next_rr(journal))
{
@@ -20561,6 +20563,18 @@ dns_zone_getrequestixfr(dns_zone_t *zone) {
return (zone->requestixfr);
}
void
dns_zone_setixfrratio(dns_zone_t *zone, uint32_t ratio) {
REQUIRE(DNS_ZONE_VALID(zone));
zone->ixfr_ratio = ratio;
}
uint32_t
dns_zone_getixfrratio(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
return (zone->ixfr_ratio);
}
void
dns_zone_setrequestexpire(dns_zone_t *zone, bool flag) {
REQUIRE(DNS_ZONE_VALID(zone));
+25
View File
@@ -92,6 +92,7 @@ static cfg_type_t cfg_type_dnstapoutput;
static cfg_type_t cfg_type_dyndb;
static cfg_type_t cfg_type_plugin;
static cfg_type_t cfg_type_ixfrdifftype;
static cfg_type_t cfg_type_ixfrratio;
static cfg_type_t cfg_type_key;
static cfg_type_t cfg_type_logfile;
static cfg_type_t cfg_type_logging;
@@ -2203,6 +2204,8 @@ static cfg_clausedef_t zone_clauses[] = {
CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR | CFG_ZONE_STUB |
CFG_ZONE_REDIRECT },
{ "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_ANCIENT },
{ "max-ixfr-ratio", &cfg_type_ixfrratio,
CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
{ "max-journal-size", &cfg_type_size,
CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR },
{ "max-records", &cfg_type_uint32,
@@ -2740,6 +2743,28 @@ static cfg_type_t cfg_type_sizeorpercent = {
doc_parse_size_or_percent, &cfg_rep_string, sizeorpercent_enums
};
/*%
* An IXFR size ratio: percentage, or "unlimited".
*/
static isc_result_t
parse_ixfrratio(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_percentage, ret));
}
static void
doc_ixfrratio(cfg_printer_t *pctx, const cfg_type_t *type) {
UNUSED(type);
cfg_print_cstr(pctx, "( unlimited | ");
cfg_doc_terminal(pctx, &cfg_type_percentage);
cfg_print_cstr(pctx, " )");
}
static const char *ixfrratio_enums[] = { "unlimited", NULL };
static cfg_type_t cfg_type_ixfrratio = { "ixfr_ratio", parse_ixfrratio,
NULL, doc_ixfrratio,
NULL, ixfrratio_enums };
/*%
* optional_keyvalue
*/
+56 -6
View File
@@ -225,10 +225,10 @@ static rrstream_methods_t ixfr_rrstream_methods;
static isc_result_t
ixfr_rrstream_create(isc_mem_t *mctx, const char *journal_filename,
uint32_t begin_serial, uint32_t end_serial,
uint32_t begin_serial, uint32_t end_serial, size_t *sizep,
rrstream_t **sp) {
ixfr_rrstream_t *s;
isc_result_t result;
ixfr_rrstream_t *s = NULL;
INSIST(sp != NULL && *sp == NULL);
@@ -240,7 +240,8 @@ ixfr_rrstream_create(isc_mem_t *mctx, const char *journal_filename,
CHECK(dns_journal_open(mctx, journal_filename, DNS_JOURNAL_READ,
&s->journal));
CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial));
CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial,
sizep));
*sp = (rrstream_t *)s;
return (ISC_R_SUCCESS);
@@ -663,6 +664,7 @@ typedef struct {
bool shuttingdown;
bool poll;
const char *mnemonic; /* Style of transfer */
uint32_t end_serial; /* Serial number after XFR is done */
struct xfr_stats stats; /*%< Transfer statistics */
} xfrout_ctx_t;
@@ -959,6 +961,26 @@ got_soa:
current_serial = dns_soa_getserial(&current_soa_tuple->rdata);
if (reqtype == dns_rdatatype_ixfr) {
size_t jsize;
uint64_t dbsize;
/*
* Outgoing IXFR may have been disabled for this peer
* or globally.
*/
if ((client->attributes & NS_CLIENTATTR_TCP) != 0) {
bool provide_ixfr;
provide_ixfr = client->view->provideixfr;
if (peer != NULL) {
(void)dns_peer_getprovideixfr(peer,
&provide_ixfr);
}
if (provide_ixfr == false) {
goto axfr_fallback;
}
}
if (!have_soa) {
FAILC(DNS_R_FORMERR, "IXFR request missing SOA");
}
@@ -1010,7 +1032,7 @@ got_soa:
if (journalfile != NULL) {
result = ixfr_rrstream_create(
mctx, journalfile, begin_serial, current_serial,
&data_stream);
&jsize, &data_stream);
} else {
result = ISC_R_NOTFOUND;
}
@@ -1023,6 +1045,32 @@ got_soa:
goto axfr_fallback;
}
CHECK(result);
result = dns_db_getsize(db, ver, NULL, &dbsize);
if (result == ISC_R_SUCCESS) {
uint32_t ratio = dns_zone_getixfrratio(zone);
if (ratio != 0 && ((100 * jsize) / dbsize) > ratio) {
data_stream->methods->destroy(&data_stream);
data_stream = NULL;
xfrout_log1(client, question_name,
question_class, ISC_LOG_DEBUG(4),
"IXFR delta size (%zu bytes) "
"exceeds the maximum ratio to "
"database size "
"(%" PRIu64 " bytes), "
"falling back to AXFR",
jsize, dbsize);
mnemonic = "AXFR-style IXFR";
goto axfr_fallback;
} else {
xfrout_log1(client, question_name,
question_class, ISC_LOG_DEBUG(4),
"IXFR delta size (%zu bytes); "
"database size "
"(%" PRIu64 " bytes)",
jsize, dbsize);
}
}
is_ixfr = true;
} else {
axfr_fallback:
@@ -1062,6 +1110,7 @@ have_stream:
(format == dns_many_answers) ? true : false, &xfr);
}
xfr->end_serial = current_serial;
xfr->mnemonic = mnemonic;
stream = NULL;
quota = NULL;
@@ -1675,10 +1724,11 @@ xfrout_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
"%s ended: "
"%" PRIu64 " messages, %" PRIu64 " records, "
"%" PRIu64 " bytes, "
"%u.%03u secs (%u bytes/sec)",
"%u.%03u secs (%u bytes/sec) (serial %u)",
xfr->mnemonic, xfr->stats.nmsg, xfr->stats.nrecs,
xfr->stats.nbytes, (unsigned int)(msecs / 1000),
(unsigned int)(msecs % 1000), (unsigned int)persec);
(unsigned int)(msecs % 1000), (unsigned int)persec,
xfr->end_serial);
/*
* We're done, unreference the handle and destroy the xfr