Commit 744c1db6 authored by Mark Andrews's avatar Mark Andrews

4504. [security] Allow the maximum number of records in a zone to

                        be specified.  This provides a control for issues
                        raised in CVE-2016-6170. [RT #42143]

(cherry picked from commit 5f8412a4)
parent b7ae121e
......@@ -3,6 +3,10 @@
4505. [port] Use IP_PMTUDISC_OMIT if available. [RT #35494]
4504. [security] Allow the maximum number of records in a zone to
be specified. This provides a control for issues
raised in CVE-2016-6170. [RT #42143]
4503. [cleanup] "make uninstall" now removes files installed by
BIND. (This currently excludes Python files
due to lack of support in setup.py.) [RT #42912]
......
......@@ -221,6 +221,7 @@ options {\n\
max-transfer-time-out 120;\n\
max-transfer-idle-in 60;\n\
max-transfer-idle-out 60;\n\
max-records 0;\n\
max-retry-time 1209600; /* 2 weeks */\n\
min-retry-time 500;\n\
max-refresh-time 2419200; /* 4 weeks */\n\
......
......@@ -360,6 +360,7 @@ options {
};
max-journal-size <replaceable>size_no_default</replaceable>;
max-records <replaceable>integer</replaceable>;
max-transfer-time-in <replaceable>integer</replaceable>;
max-transfer-time-out <replaceable>integer</replaceable>;
max-transfer-idle-in <replaceable>integer</replaceable>;
......@@ -564,6 +565,7 @@ view <replaceable>string</replaceable> <replaceable>optional_class</replaceable>
};
max-journal-size <replaceable>size_no_default</replaceable>;
max-records <replaceable>integer</replaceable>;
max-transfer-time-in <replaceable>integer</replaceable>;
max-transfer-time-out <replaceable>integer</replaceable>;
max-transfer-idle-in <replaceable>integer</replaceable>;
......@@ -665,6 +667,7 @@ zone <replaceable>string</replaceable> <replaceable>optional_class</replaceable>
};
max-journal-size <replaceable>size_no_default</replaceable>;
max-records <replaceable>integer</replaceable>;
max-transfer-time-in <replaceable>integer</replaceable>;
max-transfer-time-out <replaceable>integer</replaceable>;
max-transfer-idle-in <replaceable>integer</replaceable>;
......
......@@ -2496,6 +2496,8 @@ update_action(isc_task_t *task, isc_event_t *event) {
isc_boolean_t had_dnskey;
dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
dns_ttl_t maxttl = 0;
isc_uint32_t maxrecords;
isc_uint64_t records;
INSIST(event->ev_type == DNS_EVENT_UPDATE);
......@@ -3180,6 +3182,20 @@ update_action(isc_task_t *task, isc_event_t *event) {
}
}
maxrecords = dns_zone_getmaxrecords(zone);
if (maxrecords != 0U) {
result = dns_db_getsize(db, ver, &records, NULL);
if (result == ISC_R_SUCCESS && records > maxrecords) {
update_log(client, zone, ISC_LOG_ERROR,
"records in zone (%"
ISC_PRINT_QUADFORMAT
"u) exceeds max-records (%u)",
records, maxrecords);
result = DNS_R_TOOMANYRECORDS;
goto failure;
}
}
journalfile = dns_zone_getjournal(zone);
if (journalfile != NULL) {
update_log(client, zone, LOGLEVEL_DEBUG,
......
......@@ -991,6 +991,13 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
dns_zone_setmaxttl(raw, maxttl);
}
obj = NULL;
result = ns_config_get(maps, "max-records", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setmaxrecords(mayberaw, cfg_obj_asuint32(obj));
if (zone != mayberaw)
dns_zone_setmaxrecords(zone, 0);
if (raw != NULL && filename != NULL) {
#define SIGNED ".signed"
size_t signedlen = strlen(filename) + sizeof(SIGNED);
......
......@@ -623,7 +623,8 @@ static dns_dbmethods_t sampledb_methods = {
findext,
setcachestats,
hashsize,
NULL
NULL,
NULL,
};
/* Auxiliary driver functions. */
......
......@@ -31,5 +31,6 @@ rm -f ns3/dsset-*
rm -f ns3/example.db
rm -f ns3/many.test.bk
rm -f ns3/nsec3param.test.db
rm -f ns3/too-big.test.db
rm -f nsupdate.out*
rm -f typelist.out.*
......@@ -65,3 +65,10 @@ zone "delegation.test" {
allow-update { any; };
file "delegation.test.db.signed";
};
zone "too-big.test" {
type master;
allow-update { any; };
max-records 3;
file "too-big.test.db";
};
; Copyright (C) 2016 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/.
$TTL 10
too-big.test. IN SOA too-big.test. hostmaster.too-big.test. 1 3600 900 2419200 3600
too-big.test. IN NS too-big.test.
too-big.test. IN A 10.53.0.3
......@@ -18,6 +18,7 @@ test -r $RANDFILE || $GENRANDOM 400 $RANDFILE
rm -f ns1/*.jnl ns1/example.db ns2/*.jnl ns2/example.bk
rm -f ns2/update.bk ns2/update.alt.bk
rm -f ns3/example.db.jnl
rm -f ns3/too-big.test.db.jnl
cp -f ns1/example1.db ns1/example.db
sed 's/example.nil/other.nil/g' ns1/example1.db > ns1/other.db
......@@ -25,6 +26,7 @@ sed 's/example.nil/unixtime.nil/g' ns1/example1.db > ns1/unixtime.db
sed 's/example.nil/yyyymmddvv.nil/g' ns1/example1.db > ns1/yyyymmddvv.db
sed 's/example.nil/keytests.nil/g' ns1/example1.db > ns1/keytests.db
cp -f ns3/example.db.in ns3/example.db
cp -f ns3/too-big.test.db.in ns3/too-big.test.db
# update_test.pl has its own zone file because it
# requires a specific NS record set.
......
......@@ -686,5 +686,20 @@ $DIG +tcp @10.53.0.3 -p 5300 ns child.delegation.test > dig.out.ns1.test$n
grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null 2>&1 || ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
n=`expr $n + 1`
echo "I:check that adding too many records is blocked ($n)"
ret=0
$NSUPDATE -v << EOF > nsupdate.out-$n 2>&1 && ret=1
server 10.53.0.3 5300
zone too-big.test.
update add r1.too-big.test 3600 IN TXT r1.too-big.test
send
EOF
grep "update failed: SERVFAIL" nsupdate.out-$n > /dev/null || ret=1
DIG +tcp @10.53.0.3 -p 5300 r1.too-big.test TXT > dig.out.ns3.test$n
grep "status: NXDOMAIN" dig.out.ns3.test$n > /dev/null || ret=1
grep "records in zone (4) exceeds max-records (3)" ns3/named.run > /dev/null || ret=1
[ $ret = 0 ] || { echo I:failed; status=1; }
echo "I:exit status: $status"
[ $status -eq 0 ] || exit 1
......@@ -34,3 +34,4 @@ rm -f ns*/named.lock
rm -f ns2/mapped.db
rm -f ns3/mapped.bk
rm -f dig.out.?.*
rm -f ns1/ixfr-too-big.db ns1/ixfr-too-big.db.jnl
; Copyright (C) 2016 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/.
$TTL 3600
@ IN SOA . . 0 0 0 0 0
@ IN NS .
$GENERATE 1-29 host$ A 1.2.3.$
; Copyright (C) 2016 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/.
$TTL 3600
@ IN SOA . . 0 0 0 0 0
@ IN NS ns1
@ IN NS ns6
ns1 IN A 10.53.0.1
ns6 IN A 10.53.0.6
$GENERATE 1-25 host$ A 1.2.3.$
......@@ -40,3 +40,14 @@ zone "edns-expire" {
type master;
file "edns-expire.db";
};
zone "axfr-too-big" {
type master;
file "axfr-too-big.db";
};
zone "ixfr-too-big" {
type master;
allow-update { any; };
file "ixfr-too-big.db";
};
......@@ -50,3 +50,17 @@ zone "edns-expire" {
masters { 10.53.0.1; };
file "edns-expire.bk";
};
zone "axfr-too-big" {
type slave;
max-records 30;
masters { 10.53.0.1; };
file "axfr-too-big.bk";
};
zone "ixfr-too-big" {
type slave;
max-records 30;
masters { 10.53.0.1; };
file "ixfr-too-big.bk";
};
......@@ -30,3 +30,5 @@ cp ns2/mapped.db.in ns2/mapped.db
$PERL -e 'for ($i=0;$i<4096;$i++){ printf("name%u 259200 A 1.2.3.4\nname%u 259200 TXT \"Hello World %u\"\n", $i, $i, $i);}' > ns8/small.db
$PERL -e 'printf("large IN TYPE45234 \\# 48000 "); for ($i=0;$i<16*3000;$i++) { printf("%02x", $i % 256); } printf("\n");' > ns8/large.db
cp -f ns1/ixfr-too-big.db.in ns1/ixfr-too-big.db
......@@ -414,5 +414,31 @@ $PERL ../digcomp.pl knowngood.mapped dig.out.3.$n || tmp=1
if test $tmp != 0 ; then echo "I:failed"; fi
status=`expr $status + $tmp`
n=`expr $n + 1`
echo "I:test that a zone with too many records is rejected (AXFR) ($n)"
tmp=0
grep "'axfr-too-big/IN'.*: too many records" ns6/named.run >/dev/null || tmp=1
if test $tmp != 0 ; then echo "I:failed"; fi
status=`expr $status + $tmp`
n=`expr $n + 1`
echo "I:test that a zone with too many records is rejected (IXFR) ($n)"
tmp=0
grep "'ixfr-too-big./IN.*: too many records" ns6/named.run >/dev/null && tmp=1
$NSUPDATE << EOF
zone ixfr-too-big
server 10.53.0.1 5300
update add the-31st-record.ixfr-too-big 0 TXT this is it
send
EOF
for i in 1 2 3 4 5 6 7 8
do
grep "'ixfr-too-big/IN'.*: too many records" ns6/named.run >/dev/null && break
sleep 1
done
grep "'ixfr-too-big/IN'.*: too many records" ns6/named.run >/dev/null || tmp=1
if test $tmp != 0 ; then echo "I:failed"; fi
status=`expr $status + $tmp`
echo "I:exit status: $status"
[ $status -eq 0 ] || exit 1
......@@ -4521,6 +4521,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<optional> use-queryport-pool <replaceable>yes_or_no</replaceable>; </optional>
<optional> queryport-pool-ports <replaceable>number</replaceable>; </optional>
<optional> queryport-pool-updateinterval <replaceable>number</replaceable>; </optional>
<optional> max-records <replaceable>number</replaceable>; </optional>
<optional> max-transfer-time-in <replaceable>number</replaceable>; </optional>
<optional> max-transfer-time-out <replaceable>number</replaceable>; </optional>
<optional> max-transfer-idle-in <replaceable>number</replaceable>; </optional>
......@@ -8453,6 +8454,16 @@ avoid-v6-udp-ports { 40000; range 50000 60000; };
</listitem>
</varlistentry>
<varlistentry>
<term><command>max-records</command></term>
<listitem>
<para>
The maximum number of records permitted in a zone.
The default is zero which means unlimited.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>host-statistics-max</command></term>
<listitem>
......@@ -12503,6 +12514,16 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea
</listitem>
</varlistentry>
<varlistentry>
<term><command>max-records</command></term>
<listitem>
<para>
See the description of
<command>max-records</command> in <xref linkend="server_resource_limits"/>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>max-transfer-time-in</command></term>
<listitem>
......
......@@ -66,6 +66,15 @@
<section xml:id="relnotes_security"><info><title>Security Fixes</title></info>
<itemizedlist>
<listitem>
<para>
Added the ability to specify the maximum number of records
permitted in a zone (max-records #;). This provides a mechanism
to block overly large zone transfers, which is a potential risk
with slave zones from other parties, as described in CVE-2016-6170.
[RT #42143]
</para>
</listitem>
<listitem>
<para>
It was possible to trigger a assertion when rendering a
......
......@@ -1756,6 +1756,8 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
REDIRECTZONE },
{ "masters", SLAVEZONE | STUBZONE | REDIRECTZONE },
{ "max-ixfr-log-size", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
{ "max-records", MASTERZONE | SLAVEZONE | STUBZONE | STREDIRECTZONE |
STATICSTUBZONE | REDIRECTZONE },
{ "max-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
{ "max-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
{ "max-transfer-idle-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
......
......@@ -1003,6 +1003,19 @@ dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
return (ISC_R_NOTFOUND);
}
isc_result_t
dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, isc_uint64_t *records,
isc_uint64_t *bytes)
{
REQUIRE(DNS_DB_VALID(db));
REQUIRE(dns_db_iszone(db) == ISC_TRUE);
if (db->methods->getsize != NULL)
return ((db->methods->getsize)(db, version, records, bytes));
return (ISC_R_NOTFOUND);
}
isc_result_t
dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
isc_stdtime_t resign)
......
......@@ -582,7 +582,8 @@ static dns_dbmethods_t ecdb_methods = {
NULL, /* findext */
NULL, /* setcachestats */
NULL, /* hashsize */
NULL /* nodefullname */
NULL, /* nodefullname */
NULL /* getsize */
};
static isc_result_t
......
......@@ -188,6 +188,8 @@ typedef struct dns_dbmethods {
size_t (*hashsize)(dns_db_t *db);
isc_result_t (*nodefullname)(dns_db_t *db, dns_dbnode_t *node,
dns_name_t *name);
isc_result_t (*getsize)(dns_db_t *db, dns_dbversion_t *version,
isc_uint64_t *records, isc_uint64_t *bytes);
} dns_dbmethods_t;
typedef isc_result_t
......@@ -1501,6 +1503,24 @@ dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
* or this zone does not have NSEC3 records.
*/
isc_result_t
dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, isc_uint64_t *records,
isc_uint64_t *bytes);
/*%<
* Get the number of records in the given version of the database as well
* as the number bytes used to store those records.
*
* Requires:
* \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.
*
* Returns:
* \li #ISC_R_SUCCESS
* \li #ISC_R_NOTIMPLEMENTED
*/
isc_result_t
dns_db_findnsec3node(dns_db_t *db, dns_name_t *name,
isc_boolean_t create, dns_dbnode_t **nodep);
......
......@@ -95,6 +95,7 @@ dns_rdataslab_tordataset(unsigned char *slab, unsigned int reservelen,
* Ensures:
*\li 'rdataset' is associated and points to a valid rdataest.
*/
unsigned int
dns_rdataslab_size(unsigned char *slab, unsigned int reservelen);
/*%<
......@@ -107,6 +108,18 @@ dns_rdataslab_size(unsigned char *slab, unsigned int reservelen);
*\li The number of bytes in the slab, including the reservelen.
*/
unsigned int
dns_rdataslab_count(unsigned char *slab, unsigned int reservelen);
/*%<
* Return the number of records in the rdataslab
*
* Requires:
*\li 'slab' points to a slab.
*
* Returns:
*\li The number of records in the slab.
*/
isc_result_t
dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
unsigned int reservelen, isc_mem_t *mctx,
......
......@@ -149,8 +149,9 @@
#define DNS_R_BADDNSTAP (ISC_RESULTCLASS_DNS + 114)
#define DNS_R_BADTSIG (ISC_RESULTCLASS_DNS + 115)
#define DNS_R_BADSIG0 (ISC_RESULTCLASS_DNS + 116)
#define DNS_R_TOOMANYRECORDS (ISC_RESULTCLASS_DNS + 117)
#define DNS_R_NRESULTS 117 /*%< Number of results */
#define DNS_R_NRESULTS 118 /*%< Number of results */
/*
* DNS wire format rcodes.
......
......@@ -295,6 +295,32 @@ dns_zone_getfile(dns_zone_t *zone);
*\li Pointer to null-terminated file name, or NULL.
*/
void
dns_zone_setmaxrecords(dns_zone_t *zone, isc_uint32_t records);
/*%<
* Sets the maximim number of records permitted in a zone.
* 0 implies unlimited.
*
* Requires:
*\li 'zone' to be valid initialised zone.
*
* Returns:
*\li void
*/
isc_uint32_t
dns_zone_getmaxrecords(dns_zone_t *zone);
/*%<
* Gets the maximim number of records permitted in a zone.
* 0 implies unlimited.
*
* Requires:
*\li 'zone' to be valid initialised zone.
*
* Returns:
*\li isc_uint32_t maxrecords.
*/
void
dns_zone_setmaxttl(dns_zone_t *zone, isc_uint32_t maxttl);
/*%<
......@@ -316,7 +342,7 @@ dns_zone_getmaxttl(dns_zone_t *zone);
*\li 'zone' to be valid initialised zone.
*
* Returns:
*\li isc_uint32_t maxttl.
*\li dns_ttl_t maxttl.
*/
isc_result_t
......
......@@ -202,6 +202,7 @@ typedef isc_uint64_t rbtdb_serial_t;
#define free_rbtdb_callback free_rbtdb_callback64
#define free_rdataset free_rdataset64
#define getnsec3parameters getnsec3parameters64
#define getsize getsize64
#define getoriginnode getoriginnode64
#define getrrsetstats getrrsetstats64
#define getsigningtime getsigningtime64
......@@ -603,6 +604,13 @@ typedef struct rbtdb_version {
isc_uint16_t iterations;
isc_uint8_t salt_length;
unsigned char salt[DNS_NSEC3_SALTSIZE];
/*
* records and bytes are covered by rwlock.
*/
isc_rwlock_t rwlock;
isc_uint64_t records;
isc_uint64_t bytes;
} rbtdb_version_t;
typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
......@@ -1174,6 +1182,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
INSIST(refs == 0);
UNLINK(rbtdb->open_versions, rbtdb->current_version, link);
isc_refcount_destroy(&rbtdb->current_version->references);
isc_rwlock_destroy(&rbtdb->current_version->rwlock);
isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
sizeof(rbtdb_version_t));
}
......@@ -1437,6 +1446,7 @@ allocate_version(isc_mem_t *mctx, rbtdb_serial_t serial,
static isc_result_t
newversion(dns_db_t *db, dns_dbversion_t **versionp) {
isc_result_t result;
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
rbtdb_version_t *version;
......@@ -1469,13 +1479,28 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) {
version->salt_length = 0;
memset(version->salt, 0, sizeof(version->salt));
}
rbtdb->next_serial++;
rbtdb->future_version = version;
}
result = isc_rwlock_init(&version->rwlock, 0, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_destroy(&version->references);
isc_mem_put(rbtdb->common.mctx, version,
sizeof(*version));
version = NULL;
} else {
RWLOCK(&rbtdb->current_version->rwlock,
isc_rwlocktype_read);
version->records = rbtdb->current_version->records;
version->bytes = rbtdb->current_version->bytes;
RWUNLOCK(&rbtdb->current_version->rwlock,
isc_rwlocktype_read);
rbtdb->next_serial++;
rbtdb->future_version = version;
}
} else
result = ISC_R_NOMEMORY;
RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
if (version == NULL)
return (ISC_R_NOMEMORY);
return (result);
*versionp = version;
......@@ -2760,6 +2785,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
if (cleanup_version != NULL) {
INSIST(EMPTY(cleanup_version->changed_list));
isc_rwlock_destroy(&cleanup_version->rwlock);
isc_mem_put(rbtdb->common.mctx, cleanup_version,
sizeof(*cleanup_version));
}
......@@ -6341,6 +6367,26 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
else
rbtnode->data = newheader;
newheader->next = topheader->next;
if (rbtversion != NULL)
RWLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
if (rbtversion != NULL && !header_nx) {
rbtversion->records -=
dns_rdataslab_count((unsigned char *)header,
sizeof(*header));
rbtversion->bytes -=
dns_rdataslab_size((unsigned char *)header,
sizeof(*header));
}
if (rbtversion != NULL && !newheader_nx) {
rbtversion->records +=
dns_rdataslab_count((unsigned char *)newheader,
sizeof(*newheader));
rbtversion->bytes +=
dns_rdataslab_size((unsigned char *)newheader,
sizeof(*newheader));
}
if (rbtversion != NULL)
RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
if (loading) {
/*
* There are no other references to 'header' when
......@@ -6442,6 +6488,16 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
newheader->down = NULL;
rbtnode->data = newheader;
}
if (rbtversion != NULL && !newheader_nx) {
RWLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
rbtversion->records +=
dns_rdataslab_count((unsigned char *)newheader,
sizeof(*newheader));
rbtversion->bytes +=
dns_rdataslab_size((unsigned char *)newheader,
sizeof(*newheader));
RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
}
idx = newheader->node->locknum;
if (IS_CACHE(rbtdb)) {
ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
......@@ -6914,6 +6970,12 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
*/
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
rbtversion->records +=
dns_rdataslab_count((unsigned char *)newheader,
sizeof(*newheader));
rbtversion->bytes +=
dns_rdataslab_size((unsigned char *)newheader,
sizeof(*newheader));
} else if (result == DNS_R_NXRRSET) {
/*
* This subtraction would remove all of the rdata;
......@@ -6950,6 +7012,12 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
* topheader.
*/
INSIST(rbtversion->serial >= topheader->serial);
rbtversion->records -=
dns_rdataslab_count((unsigned char *)header,
sizeof(*header));
rbtversion->bytes -=
dns_rdataslab_size((unsigned char *)header,
sizeof(*header));
if (topheader_prev != NULL)
topheader_prev->next = newheader;
else
......@@ -7288,6 +7356,7 @@ rbt_datafixer(dns_rbtnode_t *rbtnode, void *base, size_t filesize,
unsigned char *limit = ((unsigned char *) base) + filesize;
unsigned char *p;
size_t size;
unsigned int count;
REQUIRE(rbtnode != NULL);
......@@ -7295,6 +7364,9 @@ rbt_datafixer(dns_rbtnode_t *rbtnode, void *base, size_t filesize,
p = (unsigned char *) header;
size = dns_rdataslab_size(p, sizeof(*header));
count = dns_rdataslab_count(p, sizeof(*header));;
rbtdb->current_version->records += count;
rbtdb->current_version->bytes += size;
isc_crc64_update(crc, p, size);