CVE-2016-6170: ISC BIND through 9.9.9-P1, 9.10.x through 9.10.4-P1, and
9.11.x through 9.11.0b1 allows primary DNS servers to cause a denial of
service (secondary DNS server crash) via a large AXFR response, and
possibly allows IXFR servers to cause a denial of service (IXFR client
crash) via a large IXFR response and allows remote authenticated users
to cause a denial of service (primary DNS server crash) via a large
UPDATE message.

External References:
https://nvd.nist.gov/vuln/detail/CVE-2016-6170

Patch from:
https://source.isc.org/cgi-bin/gitweb.cgi?p=bind9.git;a=commit;h=1bbcfe2fc84f57b1e4e075fb3bc2a1dd0a3a851f

Signed-off-by: Yi Zhao <yi.z...@windriver.com>
---
 .../bind/bind/CVE-2016-6170.patch                  | 1088 ++++++++++++++++++++
 meta/recipes-connectivity/bind/bind_9.10.3-P3.bb   |    1 +
 2 files changed, 1089 insertions(+)
 create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2016-6170.patch

diff --git a/meta/recipes-connectivity/bind/bind/CVE-2016-6170.patch 
b/meta/recipes-connectivity/bind/bind/CVE-2016-6170.patch
new file mode 100644
index 0000000..e0653bf
--- /dev/null
+++ b/meta/recipes-connectivity/bind/bind/CVE-2016-6170.patch
@@ -0,0 +1,1088 @@
+From 1bbcfe2fc84f57b1e4e075fb3bc2a1dd0a3a851f Mon Sep 17 00:00:00 2001
+From: Mark Andrews <ma...@isc.org>
+Date: Wed, 2 Nov 2016 17:31:27 +1100
+Subject: [PATCH] 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 5f8412a4cb5ee14a0e8cddd4107854b40ee3291e)
+
+Upstream-Status: Backport
+[https://source.isc.org/cgi-bin/gitweb.cgi?p=bind9.git;a=commit;h=1bbcfe2fc84f57b1e4e075fb3bc2a1dd0a3a851f]
+
+Signed-off-by: Yi Zhao <yi.z...@windriver.com>
+---
+ CHANGES                                          |   4 +
+ bin/named/config.c                               |   1 +
+ bin/named/named.conf.docbook                     |   3 +
+ bin/named/update.c                               |  16 +++
+ bin/named/zoneconf.c                             |   7 ++
+ bin/tests/system/nsupdate/clean.sh               |   1 +
+ bin/tests/system/nsupdate/ns3/named.conf         |   7 ++
+ bin/tests/system/nsupdate/ns3/too-big.test.db.in |  10 ++
+ bin/tests/system/nsupdate/setup.sh               |   2 +
+ bin/tests/system/nsupdate/tests.sh               |  15 +++
+ bin/tests/system/xfer/clean.sh                   |   1 +
+ bin/tests/system/xfer/ns1/axfr-too-big.db        |  10 ++
+ bin/tests/system/xfer/ns1/ixfr-too-big.db.in     |  13 +++
+ bin/tests/system/xfer/ns1/named.conf             |  11 ++
+ bin/tests/system/xfer/ns6/named.conf             |  14 +++
+ bin/tests/system/xfer/setup.sh                   |   2 +
+ bin/tests/system/xfer/tests.sh                   |  26 +++++
+ doc/arm/Bv9ARM-book.xml                          |  21 ++++
+ doc/arm/notes.xml                                |   9 ++
+ lib/bind9/check.c                                |   2 +
+ lib/dns/db.c                                     |  13 +++
+ lib/dns/ecdb.c                                   |   3 +-
+ lib/dns/include/dns/db.h                         |  20 ++++
+ lib/dns/include/dns/rdataslab.h                  |  13 +++
+ lib/dns/include/dns/result.h                     |   6 +-
+ lib/dns/include/dns/zone.h                       |  28 ++++-
+ lib/dns/rbtdb.c                                  | 127 +++++++++++++++++++++--
+ lib/dns/rdataslab.c                              |  13 +++
+ lib/dns/result.c                                 |   9 +-
+ lib/dns/sdb.c                                    |   3 +-
+ lib/dns/sdlz.c                                   |   3 +-
+ lib/dns/xfrin.c                                  |  22 +++-
+ lib/dns/zone.c                                   |  23 +++-
+ lib/isccfg/namedconf.c                           |   1 +
+ 34 files changed, 444 insertions(+), 15 deletions(-)
+ create mode 100644 bin/tests/system/nsupdate/ns3/too-big.test.db.in
+ create mode 100644 bin/tests/system/xfer/ns1/axfr-too-big.db
+ create mode 100644 bin/tests/system/xfer/ns1/ixfr-too-big.db.in
+
+diff --git a/CHANGES b/CHANGES
+index 41cfce5..97d2e60 100644
+--- a/CHANGES
++++ b/CHANGES
+@@ -1,3 +1,7 @@
++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]
++
+ 4489. [security]      It was possible to trigger assertions when processing
+                       a response. (CVE-2016-8864) [RT #43465]
+ 
+diff --git a/bin/named/config.c b/bin/named/config.c
+index f06348c..c24e334 100644
+--- a/bin/named/config.c
++++ b/bin/named/config.c
+@@ -209,6 +209,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\
+diff --git a/bin/named/named.conf.docbook b/bin/named/named.conf.docbook
+index 4c99a61..c2d173a 100644
+--- a/bin/named/named.conf.docbook
++++ b/bin/named/named.conf.docbook
+@@ -338,6 +338,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>;
+@@ -527,6 +528,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>;
+@@ -624,6 +626,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>;
+diff --git a/bin/named/update.c b/bin/named/update.c
+index 83b1a05..cc2a611 100644
+--- a/bin/named/update.c
++++ b/bin/named/update.c
+@@ -2455,6 +2455,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);
+ 
+@@ -3138,6 +3140,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,
+diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c
+index 4ee3dfe..14dd8ce 100644
+--- a/bin/named/zoneconf.c
++++ b/bin/named/zoneconf.c
+@@ -978,6 +978,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);
+diff --git a/bin/tests/system/nsupdate/clean.sh 
b/bin/tests/system/nsupdate/clean.sh
+index aaefc02..ea25545 100644
+--- a/bin/tests/system/nsupdate/clean.sh
++++ b/bin/tests/system/nsupdate/clean.sh
+@@ -32,6 +32,7 @@ rm -f ns3/example.db.jnl ns3/example.db
+ rm -f ns3/nsec3param.test.db.signed.jnl ns3/nsec3param.test.db 
ns3/nsec3param.test.db.signed ns3/dsset-nsec3param.test.
+ rm -f ns3/dnskey.test.db.signed.jnl ns3/dnskey.test.db 
ns3/dnskey.test.db.signed ns3/dsset-dnskey.test.
+ rm -f ns3/K*
++rm -f ns3/too-big.test.db
+ rm -f dig.out.*
+ rm -f jp.out.ns3.*
+ rm -f Kxxx.*
+diff --git a/bin/tests/system/nsupdate/ns3/named.conf 
b/bin/tests/system/nsupdate/ns3/named.conf
+index 2abd522..68ff27a 100644
+--- a/bin/tests/system/nsupdate/ns3/named.conf
++++ b/bin/tests/system/nsupdate/ns3/named.conf
+@@ -60,3 +60,10 @@ zone "dnskey.test" {
+       allow-update { any; };
+       file "dnskey.test.db.signed";
+ };
++
++zone "too-big.test" {
++      type master;
++      allow-update { any; };
++      max-records 3;
++      file "too-big.test.db";
++};
+diff --git a/bin/tests/system/nsupdate/ns3/too-big.test.db.in 
b/bin/tests/system/nsupdate/ns3/too-big.test.db.in
+new file mode 100644
+index 0000000..7ff1e4a
+--- /dev/null
++++ b/bin/tests/system/nsupdate/ns3/too-big.test.db.in
+@@ -0,0 +1,10 @@
++; 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
+diff --git a/bin/tests/system/nsupdate/setup.sh 
b/bin/tests/system/nsupdate/setup.sh
+index 828255e..43c4094 100644
+--- a/bin/tests/system/nsupdate/setup.sh
++++ b/bin/tests/system/nsupdate/setup.sh
+@@ -27,12 +27,14 @@ 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
+ sed 's/example.nil/unixtime.nil/g' ns1/example1.db > ns1/unixtime.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.
+diff --git a/bin/tests/system/nsupdate/tests.sh 
b/bin/tests/system/nsupdate/tests.sh
+index 78d501e..0a6bbd3 100755
+--- a/bin/tests/system/nsupdate/tests.sh
++++ b/bin/tests/system/nsupdate/tests.sh
+@@ -581,5 +581,20 @@ if [ $ret -ne 0 ]; then
+     status=1
+ fi
+ 
++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"
+ exit $status
+diff --git a/bin/tests/system/xfer/clean.sh b/bin/tests/system/xfer/clean.sh
+index 48aa159..da62a33 100644
+--- a/bin/tests/system/xfer/clean.sh
++++ b/bin/tests/system/xfer/clean.sh
+@@ -36,3 +36,4 @@ rm -f ns7/*.db ns7/*.bk ns7/*.jnl
+ rm -f */named.memstats
+ rm -f */named.run
+ rm -f */ans.run
++rm -f ns1/ixfr-too-big.db ns1/ixfr-too-big.db.jnl
+diff --git a/bin/tests/system/xfer/ns1/axfr-too-big.db 
b/bin/tests/system/xfer/ns1/axfr-too-big.db
+new file mode 100644
+index 0000000..d43760d
+--- /dev/null
++++ b/bin/tests/system/xfer/ns1/axfr-too-big.db
+@@ -0,0 +1,10 @@
++; 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.$
+diff --git a/bin/tests/system/xfer/ns1/ixfr-too-big.db.in 
b/bin/tests/system/xfer/ns1/ixfr-too-big.db.in
+new file mode 100644
+index 0000000..318bb77
+--- /dev/null
++++ b/bin/tests/system/xfer/ns1/ixfr-too-big.db.in
+@@ -0,0 +1,13 @@
++; 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.$
+diff --git a/bin/tests/system/xfer/ns1/named.conf 
b/bin/tests/system/xfer/ns1/named.conf
+index 07dad85..1d29292 100644
+--- a/bin/tests/system/xfer/ns1/named.conf
++++ b/bin/tests/system/xfer/ns1/named.conf
+@@ -44,3 +44,14 @@ zone "slave" {
+       type master;
+       file "slave.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";
++};
+diff --git a/bin/tests/system/xfer/ns6/named.conf 
b/bin/tests/system/xfer/ns6/named.conf
+index c9421b1..a12a92c 100644
+--- a/bin/tests/system/xfer/ns6/named.conf
++++ b/bin/tests/system/xfer/ns6/named.conf
+@@ -52,3 +52,17 @@ zone "slave" {
+       masters { 10.53.0.1; };
+       file "slave.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";
++};
+diff --git a/bin/tests/system/xfer/setup.sh b/bin/tests/system/xfer/setup.sh
+index 56ca901..c55abf8 100644
+--- a/bin/tests/system/xfer/setup.sh
++++ b/bin/tests/system/xfer/setup.sh
+@@ -33,3 +33,5 @@ cp -f ns4/named.conf.base ns4/named.conf
+ 
+ cp ns2/slave.db.in ns2/slave.db
+ touch -t 200101010000 ns2/slave.db
++
++cp -f ns1/ixfr-too-big.db.in ns1/ixfr-too-big.db
+diff --git a/bin/tests/system/xfer/tests.sh b/bin/tests/system/xfer/tests.sh
+index 67b2a1a..fe33f0a 100644
+--- a/bin/tests/system/xfer/tests.sh
++++ b/bin/tests/system/xfer/tests.sh
+@@ -368,5 +368,31 @@ $DIGCMD nil. TXT | grep 'incorrect key AXFR' >/dev/null 
&& {
+     status=1
+ }
+ 
++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"
+ exit $status
+diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
+index 848b582..0369505 100644
+--- a/doc/arm/Bv9ARM-book.xml
++++ b/doc/arm/Bv9ARM-book.xml
+@@ -4858,6 +4858,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>
+@@ -8164,6 +8165,16 @@ avoid-v6-udp-ports { 40000; range 50000 60000; };
+           </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>
+               <para>
+@@ -12056,6 +12067,16 @@ zone <replaceable>zone_name</replaceable> 
<optional><replaceable>class</replacea
+             </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>
+                 <para>
+diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml
+index 095eb5b..36495e7 100644
+--- a/doc/arm/notes.xml
++++ b/doc/arm/notes.xml
+@@ -52,6 +52,15 @@
+     <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>
+          Duplicate EDNS COOKIE options in a response could trigger
+          an assertion failure. This flaw is disclosed in CVE-2016-2088.
+          [RT #41809]
+diff --git a/lib/bind9/check.c b/lib/bind9/check.c
+index b8c05dd..edb7534 100644
+--- a/lib/bind9/check.c
++++ b/lib/bind9/check.c
+@@ -1510,6 +1510,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 },
+diff --git a/lib/dns/db.c b/lib/dns/db.c
+index 7e4f357..ced94a5 100644
+--- a/lib/dns/db.c
++++ b/lib/dns/db.c
+@@ -999,6 +999,19 @@ 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, 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)
+ {
+diff --git a/lib/dns/ecdb.c b/lib/dns/ecdb.c
+index 553a339..b5d04d2 100644
+--- a/lib/dns/ecdb.c
++++ b/lib/dns/ecdb.c
+@@ -587,7 +587,8 @@ static dns_dbmethods_t ecdb_methods = {
+       NULL,                   /* findnodeext */
+       NULL,                   /* findext */
+       NULL,                   /* setcachestats */
+-      NULL                    /* hashsize */
++      NULL,                   /* hashsize */
++      NULL                    /* getsize */
+ };
+ 
+ static isc_result_t
+diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h
+index a4a4482..aff42d6 100644
+--- a/lib/dns/include/dns/db.h
++++ b/lib/dns/include/dns/db.h
+@@ -195,6 +195,8 @@ typedef struct dns_dbmethods {
+                                  dns_rdataset_t *sigrdataset);
+       isc_result_t    (*setcachestats)(dns_db_t *db, isc_stats_t *stats);
+       unsigned int    (*hashsize)(dns_db_t *db);
++      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
+@@ -1485,6 +1487,24 @@ 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, 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);
+ /*%<
+diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h
+index 3ac44b8..2e1e759 100644
+--- a/lib/dns/include/dns/rdataslab.h
++++ b/lib/dns/include/dns/rdataslab.h
+@@ -104,6 +104,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);
+ /*%<
+@@ -116,6 +117,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,
+diff --git a/lib/dns/include/dns/result.h b/lib/dns/include/dns/result.h
+index 7d11c2b..93d1fd5 100644
+--- a/lib/dns/include/dns/result.h
++++ b/lib/dns/include/dns/result.h
+@@ -157,8 +157,12 @@
+ #define DNS_R_BADCDS                  (ISC_RESULTCLASS_DNS + 111)
+ #define DNS_R_BADCDNSKEY              (ISC_RESULTCLASS_DNS + 112)
+ #define DNS_R_OPTERR                  (ISC_RESULTCLASS_DNS + 113)
++#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                        114     /*%< Number of results 
*/
++#define DNS_R_NRESULTS                        118     /*%< Number of results 
*/
+ 
+ /*
+  * DNS wire format rcodes.
+diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h
+index a9367f1..227540b 100644
+--- a/lib/dns/include/dns/zone.h
++++ b/lib/dns/include/dns/zone.h
+@@ -296,6 +296,32 @@ dns_zone_getfile(dns_zone_t *zone);
+  */
+ 
+ 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);
+ /*%<
+  *    Sets the max ttl of the zone.
+@@ -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
+diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
+index 62becfc..72d722f 100644
+--- a/lib/dns/rbtdb.c
++++ b/lib/dns/rbtdb.c
+@@ -209,6 +209,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
+@@ -589,6 +590,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;
+@@ -1130,6 +1138,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));
+       }
+@@ -1383,6 +1392,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;
+ 
+@@ -1415,13 +1425,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;
+ 
+@@ -2681,6 +2706,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));
+       }
+@@ -6254,6 +6280,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
+@@ -6355,6 +6401,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],
+@@ -6811,6 +6867,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;
+@@ -6846,6 +6908,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
+@@ -7172,6 +7240,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);
+ 
+@@ -7179,6 +7248,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);
+ #ifdef DEBUG
+               hexdump("hashing header", p, sizeof(rdatasetheader_t));
+@@ -7777,6 +7849,33 @@ 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, isc_uint64_t *records,
++        isc_uint64_t *bytes)
++{
++      dns_rbtdb_t *rbtdb;
++      isc_result_t result = ISC_R_SUCCESS;
++      rbtdb_version_t *rbtversion = version;
++
++      rbtdb = (dns_rbtdb_t *)db;
++
++      REQUIRE(VALID_RBTDB(rbtdb));
++      INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
++
++      if (rbtversion == NULL)
++              rbtversion = rbtdb->current_version;
++
++      RWLOCK(&rbtversion->rwlock, isc_rwlocktype_read);
++      if (records != NULL)
++              *records = rbtversion->records;
++
++      if (bytes != NULL)
++              *bytes = rbtversion->bytes;
++      RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_read);
++
++      return (result);
++}
++
++static isc_result_t
+ setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) {
+       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+       isc_stdtime_t oldresign;
+@@ -7972,7 +8071,8 @@ static dns_dbmethods_t zone_methods = {
+       NULL,
+       NULL,
+       NULL,
+-      hashsize
++      hashsize,
++      getsize
+ };
+ 
+ static dns_dbmethods_t cache_methods = {
+@@ -8018,7 +8118,8 @@ static dns_dbmethods_t cache_methods = {
+       NULL,
+       NULL,
+       setcachestats,
+-      hashsize
++      hashsize,
++      NULL
+ };
+ 
+ isc_result_t
+@@ -8310,6 +8411,20 @@ dns_rbtdb_create
+       rbtdb->current_version->salt_length = 0;
+       memset(rbtdb->current_version->salt, 0,
+              sizeof(rbtdb->current_version->salt));
++      result = isc_rwlock_init(&rbtdb->current_version->rwlock, 0, 0);
++      if (result != ISC_R_SUCCESS) {
++              isc_refcount_destroy(&rbtdb->current_version->references);
++              isc_mem_put(mctx, rbtdb->current_version,
++                          sizeof(*rbtdb->current_version));
++              rbtdb->current_version = NULL;
++              isc_refcount_decrement(&rbtdb->references, NULL);
++              isc_refcount_destroy(&rbtdb->references);
++              free_rbtdb(rbtdb, ISC_FALSE, NULL);
++              return (result);
++      }
++
++      rbtdb->current_version->records = 0;
++      rbtdb->current_version->bytes = 0;
+       rbtdb->future_version = NULL;
+       ISC_LIST_INIT(rbtdb->open_versions);
+       /*
+diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c
+index e29dc84..63e3728 100644
+--- a/lib/dns/rdataslab.c
++++ b/lib/dns/rdataslab.c
+@@ -523,6 +523,19 @@ dns_rdataslab_size(unsigned char *slab, unsigned int 
reservelen) {
+       return ((unsigned int)(current - slab));
+ }
+ 
++unsigned int
++dns_rdataslab_count(unsigned char *slab, unsigned int reservelen) {
++      unsigned int count;
++      unsigned char *current;
++
++      REQUIRE(slab != NULL);
++
++      current = slab + reservelen;
++      count = *current++ * 256;
++      count += *current++;
++      return (count);
++}
++
+ /*
+  * Make the dns_rdata_t 'rdata' refer to the slab item
+  * beginning at '*current', which is part of a slab of type
+diff --git a/lib/dns/result.c b/lib/dns/result.c
+index 7be4f57..a621909 100644
+--- a/lib/dns/result.c
++++ b/lib/dns/result.c
+@@ -167,11 +167,16 @@ static const char *text[DNS_R_NRESULTS] = {
+       "covered by negative trust anchor",    /*%< 110 DNS_R_NTACOVERED */
+       "bad CDS",                             /*%< 111 DNS_R_BADCSD */
+       "bad CDNSKEY",                         /*%< 112 DNS_R_BADCDNSKEY */
+-      "malformed OPT option"                 /*%< 113 DNS_R_OPTERR */
++      "malformed OPT option",                /*%< 113 DNS_R_OPTERR */
++      "malformed DNSTAP data",               /*%< 114 DNS_R_BADDNSTAP */
++
++      "TSIG in wrong location",              /*%< 115 DNS_R_BADTSIG */
++      "SIG(0) in wrong location",            /*%< 116 DNS_R_BADSIG0 */
++      "too many records",                    /*%< 117 DNS_R_TOOMANYRECORDS */
+ };
+ 
+ static const char *rcode_text[DNS_R_NRCODERESULTS] = {
+-      "NOERROR",                              /*%< 0 DNS_R_NOEROR */
++      "NOERROR",                              /*%< 0 DNS_R_NOERROR */
+       "FORMERR",                              /*%< 1 DNS_R_FORMERR */
+       "SERVFAIL",                             /*%< 2 DNS_R_SERVFAIL */
+       "NXDOMAIN",                             /*%< 3 DNS_R_NXDOMAIN */
+diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c
+index abfeeb0..19397e0 100644
+--- a/lib/dns/sdb.c
++++ b/lib/dns/sdb.c
+@@ -1298,7 +1298,8 @@ static dns_dbmethods_t sdb_methods = {
+       findnodeext,
+       findext,
+       NULL,                   /* setcachestats */
+-      NULL                    /* hashsize */
++      NULL,                   /* hashsize */
++      NULL                    /* getsize */
+ };
+ 
+ static isc_result_t
+diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c
+index b1198a4..0e3163d 100644
+--- a/lib/dns/sdlz.c
++++ b/lib/dns/sdlz.c
+@@ -1269,7 +1269,8 @@ static dns_dbmethods_t sdlzdb_methods = {
+       findnodeext,
+       findext,
+       NULL,                   /* setcachestats */
+-      NULL                    /* hashsize */
++      NULL,                   /* hashsize */
++      NULL                    /* getsize */
+ };
+ 
+ /*
+diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c
+index 2a6c1b4..ac566e1 100644
+--- a/lib/dns/xfrin.c
++++ b/lib/dns/xfrin.c
+@@ -149,6 +149,9 @@ struct dns_xfrin_ctx {
+       unsigned int            nrecs;          /*%< Number of records recvd */
+       isc_uint64_t            nbytes;         /*%< Number of bytes received */
+ 
++      unsigned int            maxrecords;     /*%< The maximum number of
++                                                   records set for the zone */
++
+       isc_time_t              start;          /*%< Start time of the transfer 
*/
+       isc_time_t              end;            /*%< End time of the transfer */
+ 
+@@ -309,10 +312,18 @@ axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
+ static isc_result_t
+ axfr_apply(dns_xfrin_ctx_t *xfr) {
+       isc_result_t result;
++      isc_uint64_t records;
+ 
+       CHECK(dns_diff_load(&xfr->diff, xfr->axfr.add, xfr->axfr.add_private));
+       xfr->difflen = 0;
+       dns_diff_clear(&xfr->diff);
++      if (xfr->maxrecords != 0U) {
++              result = dns_db_getsize(xfr->db, xfr->ver, &records, NULL);
++              if (result == ISC_R_SUCCESS && records > xfr->maxrecords) {
++                      result = DNS_R_TOOMANYRECORDS;
++                      goto failure;
++              }
++      }
+       result = ISC_R_SUCCESS;
+  failure:
+       return (result);
+@@ -396,6 +407,7 @@ ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
+ static isc_result_t
+ ixfr_apply(dns_xfrin_ctx_t *xfr) {
+       isc_result_t result;
++      isc_uint64_t records;
+ 
+       if (xfr->ver == NULL) {
+               CHECK(dns_db_newversion(xfr->db, &xfr->ver));
+@@ -403,6 +415,13 @@ ixfr_apply(dns_xfrin_ctx_t *xfr) {
+                       CHECK(dns_journal_begin_transaction(xfr->ixfr.journal));
+       }
+       CHECK(dns_diff_apply(&xfr->diff, xfr->db, xfr->ver));
++      if (xfr->maxrecords != 0U) {
++              result = dns_db_getsize(xfr->db, xfr->ver, &records, NULL);
++              if (result == ISC_R_SUCCESS && records > xfr->maxrecords) {
++                      result = DNS_R_TOOMANYRECORDS;
++                      goto failure;
++              }
++      }
+       if (xfr->ixfr.journal != NULL) {
+               result = dns_journal_writediff(xfr->ixfr.journal, &xfr->diff);
+               if (result != ISC_R_SUCCESS)
+@@ -759,7 +778,7 @@ xfrin_reset(dns_xfrin_ctx_t *xfr) {
+ 
+ static void
+ xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg) {
+-      if (result != DNS_R_UPTODATE) {
++      if (result != DNS_R_UPTODATE && result != DNS_R_TOOMANYRECORDS) {
+               xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s",
+                         msg, isc_result_totext(result));
+               if (xfr->is_ixfr)
+@@ -852,6 +871,7 @@ xfrin_create(isc_mem_t *mctx,
+       xfr->nmsg = 0;
+       xfr->nrecs = 0;
+       xfr->nbytes = 0;
++      xfr->maxrecords = dns_zone_getmaxrecords(zone);
+       isc_time_now(&xfr->start);
+ 
+       xfr->tsigkey = NULL;
+diff --git a/lib/dns/zone.c b/lib/dns/zone.c
+index 90e558d..2b0d8e4 100644
+--- a/lib/dns/zone.c
++++ b/lib/dns/zone.c
+@@ -253,6 +253,8 @@ struct dns_zone {
+       isc_uint32_t            maxretry;
+       isc_uint32_t            minretry;
+ 
++      isc_uint32_t            maxrecords;
++
+       isc_sockaddr_t          *masters;
+       isc_dscp_t              *masterdscps;
+       dns_name_t              **masterkeynames;
+@@ -10088,6 +10090,20 @@ dns_zone_setmaxretrytime(dns_zone_t *zone, 
isc_uint32_t val) {
+       zone->maxretry = val;
+ }
+ 
++isc_uint32_t
++dns_zone_getmaxrecords(dns_zone_t *zone) {
++        REQUIRE(DNS_ZONE_VALID(zone));
++
++      return (zone->maxrecords);
++}
++
++void
++dns_zone_setmaxrecords(dns_zone_t *zone, isc_uint32_t val) {
++        REQUIRE(DNS_ZONE_VALID(zone));
++
++      zone->maxrecords = val;
++}
++
+ static isc_boolean_t
+ notify_isqueued(dns_zone_t *zone, unsigned int flags, dns_name_t *name,
+               isc_sockaddr_t *addr, dns_tsigkey_t *key)
+@@ -14431,7 +14447,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
+       DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR);
+ 
+       TIME_NOW(&now);
+-      switch (result) {
++      switch (xfrresult) {
+       case ISC_R_SUCCESS:
+               DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+               /*FALLTHROUGH*/
+@@ -14558,6 +14574,11 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
+               DNS_ZONE_SETFLAG(zone, DNS_ZONEFLAG_NOIXFR);
+               goto same_master;
+ 
++      case DNS_R_TOOMANYRECORDS:
++              DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime);
++              inc_stats(zone, dns_zonestatscounter_xfrfail);
++              break;
++
+       default:
+       next_master:
+               /*
+diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
+index 780ab46..e7ff1cc 100644
+--- a/lib/isccfg/namedconf.c
++++ b/lib/isccfg/namedconf.c
+@@ -1679,6 +1679,7 @@ zone_clauses[] = {
+       { "masterfile-format", &cfg_type_masterformat, 0 },
+       { "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_OBSOLETE },
+       { "max-journal-size", &cfg_type_sizenodefault, 0 },
++      { "max-records", &cfg_type_uint32, 0 },
+       { "max-refresh-time", &cfg_type_uint32, 0 },
+       { "max-retry-time", &cfg_type_uint32, 0 },
+       { "max-transfer-idle-in", &cfg_type_uint32, 0 },
+-- 
+2.7.4
+
diff --git a/meta/recipes-connectivity/bind/bind_9.10.3-P3.bb 
b/meta/recipes-connectivity/bind/bind_9.10.3-P3.bb
index fa45809..8160625 100644
--- a/meta/recipes-connectivity/bind/bind_9.10.3-P3.bb
+++ b/meta/recipes-connectivity/bind/bind_9.10.3-P3.bb
@@ -28,6 +28,7 @@ SRC_URI = 
"ftp://ftp.isc.org/isc/bind9/${PV}/${BPN}-${PV}.tar.gz \
            file://CVE-2016-2775.patch \
            file://CVE-2016-2776.patch \
            file://CVE-2016-8864.patch \
+           file://CVE-2016-6170.patch \
            "
 
 SRC_URI[md5sum] = "bcf7e772b616f7259420a3edc5df350a"
-- 
2.7.4

-- 
_______________________________________________
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core

Reply via email to