diff --git a/SOURCES/bind99-CVE-2017-3136.patch b/SOURCES/bind99-CVE-2017-3136.patch
new file mode 100644
index 0000000..f83f93e
--- /dev/null
+++ b/SOURCES/bind99-CVE-2017-3136.patch
@@ -0,0 +1,26 @@
+From d4d151cf34fab415e2823deada3433df7f475c71 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
+Date: Tue, 11 Apr 2017 16:19:08 +0200
+Subject: [PATCH 1/3] 4575.   [security]      DNS64 with "break-dnssec yes;"
+ can result in an                         assertion failure. (CVE-2017-3136)
+ [RT #44653]
+
+---
+ bin/named/query.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/bin/named/query.c b/bin/named/query.c
+index f60078b..6e988f5 100644
+--- a/bin/named/query.c
++++ b/bin/named/query.c
+@@ -7324,6 +7324,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
+ 			result = query_dns64(client, &fname, rdataset,
+ 					     sigrdataset, dbuf,
+ 					     DNS_SECTION_ANSWER);
++			noqname = NULL;
+ 			dns_rdataset_disassociate(rdataset);
+ 			dns_message_puttemprdataset(client->message, &rdataset);
+ 			if (result == ISC_R_NOMORE) {
+-- 
+2.9.3
+
diff --git a/SOURCES/bind99-CVE-2017-3137.patch b/SOURCES/bind99-CVE-2017-3137.patch
new file mode 100644
index 0000000..a0d97e5
--- /dev/null
+++ b/SOURCES/bind99-CVE-2017-3137.patch
@@ -0,0 +1,1126 @@
+From 93aec4d3d80a0d1cdb6553f70f35a2e2cb1fbaa8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
+Date: Tue, 11 Apr 2017 16:19:51 +0200
+Subject: [PATCH 2/3] 4578.   [security]      Some chaining (CNAME or DNAME)
+ responses to upstream                         queries could trigger assertion
+ failures.                         (CVE-2017-3137) [RT #44734]
+
+(including part of commit fea8a9d)
+---
+ bin/tests/system/dname/ans3/ans.pl    |  16 +-
+ bin/tests/system/dname/ns1/root.db    |   2 +-
+ bin/tests/system/dname/ns2/example.db |   3 +-
+ bin/tests/system/dname/tests.sh       |  17 +-
+ lib/dns/name.c                        |   2 -
+ lib/dns/resolver.c                    | 850 +++++++++++++---------------------
+ 6 files changed, 349 insertions(+), 541 deletions(-)
+
+diff --git a/bin/tests/system/dname/ans3/ans.pl b/bin/tests/system/dname/ans3/ans.pl
+index 271fc7d..af338fe 100644
+--- a/bin/tests/system/dname/ans3/ans.pl
++++ b/bin/tests/system/dname/ans3/ans.pl
+@@ -1,10 +1,18 @@
+ #!/usr/bin/env perl
+ #
+-# Copyright (C) 2014-2016  Internet Systems Consortium, Inc. ("ISC")
++# Copyright (C) 2017  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/.
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
+ 
+ use strict;
+ use warnings;
+diff --git a/bin/tests/system/dname/ns1/root.db b/bin/tests/system/dname/ns1/root.db
+index 2e84ae0..3d55ace 100644
+--- a/bin/tests/system/dname/ns1/root.db
++++ b/bin/tests/system/dname/ns1/root.db
+@@ -1,4 +1,4 @@
+-; Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
++; Copyright (C) 2011, 2017  Internet Systems Consortium, Inc. ("ISC")
+ ;
+ ; Permission to use, copy, modify, and/or distribute this software for any
+ ; purpose with or without fee is hereby granted, provided that the above
+diff --git a/bin/tests/system/dname/ns2/example.db b/bin/tests/system/dname/ns2/example.db
+index 4289134..c0193de 100644
+--- a/bin/tests/system/dname/ns2/example.db
++++ b/bin/tests/system/dname/ns2/example.db
+@@ -1,4 +1,4 @@
+-; Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
++; Copyright (C) 2011, 2017  Internet Systems Consortium, Inc. ("ISC")
+ ;
+ ; Permission to use, copy, modify, and/or distribute this software for any
+ ; purpose with or without fee is hereby granted, provided that the above
+@@ -29,6 +29,7 @@ a.short			A	10.0.0.1
+ short-dname		DNAME	short
+ a.longlonglonglonglonglonglonglonglonglonglonglonglong	A 10.0.0.2
+ long-dname		DNAME	longlonglonglonglonglonglonglonglonglonglonglonglong
++toolong-dname		DNAME	longlonglonglonglonglonglonglonglonglonglonglonglong
+ cname			CNAME	a.cnamedname
+ cnamedname		DNAME	target
+ a.target		A	10.0.0.3
+diff --git a/bin/tests/system/dname/tests.sh b/bin/tests/system/dname/tests.sh
+index 6dc9e88..1487bd9 100644
+--- a/bin/tests/system/dname/tests.sh
++++ b/bin/tests/system/dname/tests.sh
+@@ -1,6 +1,6 @@
+ #!/bin/sh
+ #
+-# Copyright (C) 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
++# Copyright (C) 2011, 2012, 2017  Internet Systems Consortium, Inc. ("ISC")
+ #
+ # Permission to use, copy, modify, and/or distribute this software for any
+ # purpose with or without fee is hereby granted, provided that the above
+@@ -57,10 +57,19 @@ grep "status: YXDOMAIN" dig.out.ns2.toolong > /dev/null || ret=1
+ if [ $ret != 0 ]; then echo "I:failed"; fi
+ status=`expr $status + $ret`
+ 
+-echo "I:checking (too) long dname from recursive"
++echo "I:checking (too) long dname from recursive with cached DNAME"
+ ret=0
+-$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.toolong || ret=1
+-grep "status: YXDOMAIN" dig.out.ns4.toolong > /dev/null || ret=1
++$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.cachedtoolong || ret=1
++grep "status: YXDOMAIN" dig.out.ns4.cachedtoolong > /dev/null || ret=1
++grep '^long-dname\.example\..*DNAME.*long' dig.out.ns4.cachedtoolong > /dev/null || ret=1
++if [ $ret != 0 ]; then echo "I:failed"; fi
++status=`expr $status + $ret`
++
++echo "I:checking (too) long dname from recursive without cached DNAME"
++ret=0
++$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglong.toolong-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.uncachedtoolong || ret=1
++grep "status: YXDOMAIN" dig.out.ns4.uncachedtoolong > /dev/null || ret=1
++grep '^toolong-dname\.example\..*DNAME.*long' dig.out.ns4.uncachedtoolong > /dev/null || ret=1
+ if [ $ret != 0 ]; then echo "I:failed"; fi
+ status=`expr $status + $ret`
+ 
+diff --git a/lib/dns/name.c b/lib/dns/name.c
+index 93173ee..d02e713 100644
+--- a/lib/dns/name.c
++++ b/lib/dns/name.c
+@@ -2119,11 +2119,9 @@ dns_name_split(dns_name_t *name, unsigned int suffixlabels,
+ 	REQUIRE(prefix != NULL || suffix != NULL);
+ 	REQUIRE(prefix == NULL ||
+ 		(VALID_NAME(prefix) &&
+-		 prefix->buffer != NULL &&
+ 		 BINDABLE(prefix)));
+ 	REQUIRE(suffix == NULL ||
+ 		(VALID_NAME(suffix) &&
+-		 suffix->buffer != NULL &&
+ 		 BINDABLE(suffix)));
+ 
+ 	splitlabel = name->labels - suffixlabels;
+diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
+index c3607fa..860a792 100644
+--- a/lib/dns/resolver.c
++++ b/lib/dns/resolver.c
+@@ -3817,6 +3817,7 @@ is_lame(fetchctx_t *fctx) {
+ 	isc_result_t result;
+ 
+ 	if (message->rcode != dns_rcode_noerror &&
++	    message->rcode != dns_rcode_yxdomain &&
+ 	    message->rcode != dns_rcode_nxdomain)
+ 		return (ISC_FALSE);
+ 
+@@ -5386,79 +5387,6 @@ chase_additional(fetchctx_t *fctx) {
+ 		goto again;
+ }
+ 
+-static inline isc_result_t
+-cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) {
+-	isc_result_t result;
+-	dns_rdata_t rdata = DNS_RDATA_INIT;
+-	dns_rdata_cname_t cname;
+-
+-	result = dns_rdataset_first(rdataset);
+-	if (result != ISC_R_SUCCESS)
+-		return (result);
+-	dns_rdataset_current(rdataset, &rdata);
+-	result = dns_rdata_tostruct(&rdata, &cname, NULL);
+-	if (result != ISC_R_SUCCESS)
+-		return (result);
+-	dns_name_init(tname, NULL);
+-	dns_name_clone(&cname.cname, tname);
+-	dns_rdata_freestruct(&cname);
+-
+-	return (ISC_R_SUCCESS);
+-}
+-
+-/*%
+- * Construct the synthesised CNAME from the existing QNAME and
+- * the DNAME RR and store it in 'target'.
+- */
+-static inline isc_result_t
+-dname_target(dns_rdataset_t *rdataset, dns_name_t *qname,
+-	     unsigned int nlabels, dns_name_t *target)
+-{
+-	isc_result_t result;
+-	dns_rdata_t rdata = DNS_RDATA_INIT;
+-	dns_rdata_dname_t dname;
+-	dns_fixedname_t prefix;
+-
+-	/*
+-	 * Get the target name of the DNAME.
+-	 */
+-	result = dns_rdataset_first(rdataset);
+-	if (result != ISC_R_SUCCESS)
+-		return (result);
+-	dns_rdataset_current(rdataset, &rdata);
+-	result = dns_rdata_tostruct(&rdata, &dname, NULL);
+-	if (result != ISC_R_SUCCESS)
+-		return (result);
+-
+-	dns_fixedname_init(&prefix);
+-	dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL);
+-	result = dns_name_concatenate(dns_fixedname_name(&prefix),
+-				      &dname.dname, target, NULL);
+-	dns_rdata_freestruct(&dname);
+-	return (result);
+-}
+-
+-/*%
+- * Check if it was possible to construct 'qname' from 'lastcname'
+- * and 'rdataset'.
+- */
+-static inline isc_result_t
+-fromdname(dns_rdataset_t *rdataset, dns_name_t *lastcname,
+-	  unsigned int nlabels, const dns_name_t *qname)
+-{
+-	dns_fixedname_t fixed;
+-	isc_result_t result;
+-	dns_name_t *target;
+-
+-	dns_fixedname_init(&fixed);
+-	target = dns_fixedname_name(&fixed);
+-	result = dname_target(rdataset, lastcname, nlabels, target);
+-	if (result != ISC_R_SUCCESS || !dns_name_equal(qname, target))
+-		return (ISC_R_NOTFOUND);
+-
+-	return (ISC_R_SUCCESS);
+-}
+-
+ static isc_boolean_t
+ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name,
+ 			 dns_rdataset_t *rdataset)
+@@ -5534,9 +5462,8 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name,
+ }
+ 
+ static isc_boolean_t
+-is_answertarget_allowed(dns_view_t *view, dns_name_t *name,
+-			dns_rdatatype_t type, dns_name_t *tname,
+-			dns_name_t *domain)
++is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname,
++			dns_rdataset_t *rdataset, isc_boolean_t *chainingp)
+ {
+ 	isc_result_t result;
+ 	dns_rbtnode_t *node = NULL;
+@@ -5544,8 +5471,57 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name,
+ 	char tnamebuf[DNS_NAME_FORMATSIZE];
+ 	char classbuf[64];
+ 	char typebuf[64];
++	dns_name_t *tname = NULL;
++	dns_rdata_cname_t cname;
++	dns_rdata_dname_t dname;
++	dns_view_t *view = fctx->res->view;
++	dns_rdata_t rdata = DNS_RDATA_INIT;
++	unsigned int nlabels;
++	dns_fixedname_t fixed;
++	dns_name_t prefix;
++
++	REQUIRE(rdataset != NULL);
++	REQUIRE(rdataset->type == dns_rdatatype_cname ||
++		rdataset->type == dns_rdatatype_dname);
++
++	/*
++	 * By default, we allow any target name.
++	 * If newqname != NULL we also need to extract the newqname.
++	 */
++	if (chainingp == NULL && view->denyanswernames == NULL)
++		return (ISC_TRUE);
++
++	result = dns_rdataset_first(rdataset);
++	RUNTIME_CHECK(result == ISC_R_SUCCESS);
++	dns_rdataset_current(rdataset, &rdata);
++	switch (rdataset->type) {
++	case dns_rdatatype_cname:
++		result = dns_rdata_tostruct(&rdata, &cname, NULL);
++		RUNTIME_CHECK(result == ISC_R_SUCCESS);
++		tname = &cname.cname;
++		break;
++	case dns_rdatatype_dname:
++		result = dns_rdata_tostruct(&rdata, &dname, NULL);
++		RUNTIME_CHECK(result == ISC_R_SUCCESS);
++		dns_name_init(&prefix, NULL);
++		dns_fixedname_init(&fixed);
++		tname = dns_fixedname_name(&fixed);
++		nlabels = dns_name_countlabels(qname) -
++			  dns_name_countlabels(rname);
++		dns_name_split(qname, nlabels, &prefix, NULL);
++		result = dns_name_concatenate(&prefix, &dname.dname, tname,
++					      NULL);
++		if (result == DNS_R_NAMETOOLONG)
++			return (ISC_TRUE);
++		RUNTIME_CHECK(result == ISC_R_SUCCESS);
++		break;
++	default:
++		INSIST(0);
++	}
++
++	if (chainingp != NULL)
++		*chainingp = ISC_TRUE;
+ 
+-	/* By default, we allow any target name. */
+ 	if (view->denyanswernames == NULL)
+ 		return (ISC_TRUE);
+ 
+@@ -5554,8 +5530,8 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name,
+ 	 * or partially, allow it.
+ 	 */
+ 	if (view->answernames_exclude != NULL) {
+-		result = dns_rbt_findnode(view->answernames_exclude, name, NULL,
+-					  &node, NULL, 0, NULL, NULL);
++		result = dns_rbt_findnode(view->answernames_exclude, qname,
++					  NULL, &node, NULL, 0, NULL, NULL);
+ 		if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
+ 			return (ISC_TRUE);
+ 	}
+@@ -5563,7 +5539,7 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name,
+ 	/*
+ 	 * If the target name is a subdomain of the search domain, allow it.
+ 	 */
+-	if (dns_name_issubdomain(tname, domain))
++	if (dns_name_issubdomain(tname, &fctx->domain))
+ 		return (ISC_TRUE);
+ 
+ 	/*
+@@ -5572,9 +5548,9 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name,
+ 	result = dns_rbt_findnode(view->denyanswernames, tname, NULL, &node,
+ 				  NULL, 0, NULL, NULL);
+ 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+-		dns_name_format(name, qnamebuf, sizeof(qnamebuf));
++		dns_name_format(qname, qnamebuf, sizeof(qnamebuf));
+ 		dns_name_format(tname, tnamebuf, sizeof(tnamebuf));
+-		dns_rdatatype_format(type, typebuf, sizeof(typebuf));
++		dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
+ 		dns_rdataclass_format(view->rdclass, classbuf,
+ 				      sizeof(classbuf));
+ 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+@@ -6057,473 +6033,301 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
+ 	return (ISC_R_SUCCESS);
+ }
+ 
++static isc_boolean_t
++validinanswer(dns_rdataset_t *rdataset, fetchctx_t *fctx) {
++	if (rdataset->type == dns_rdatatype_nsec3) {
++		/*
++		 * NSEC3 records are not allowed to
++		 * appear in the answer section.
++		 */
++		log_formerr(fctx, "NSEC3 in answer");
++		return (ISC_FALSE);
++	}
++	if (rdataset->type == dns_rdatatype_tkey) {
++		/*
++		 * TKEY is not a valid record in a
++		 * response to any query we can make.
++		 */
++		log_formerr(fctx, "TKEY in answer");
++		return (ISC_FALSE);
++	}
++	if (rdataset->rdclass != fctx->res->rdclass) {
++		log_formerr(fctx, "Mismatched class in answer");
++		return (ISC_FALSE);
++	}
++	return (ISC_TRUE);
++}
++
+ static isc_result_t
+ answer_response(fetchctx_t *fctx) {
+ 	isc_result_t result;
+-	dns_message_t *message;
+-	dns_name_t *name, *dname = NULL, *qname, tname, *ns_name;
+-	dns_name_t *cname = NULL, *lastcname = NULL;
+-	dns_rdataset_t *rdataset, *ns_rdataset;
+-	isc_boolean_t done, external, aa, found, want_chaining;
+-	isc_boolean_t have_answer, found_cname, found_dname, found_type;
+-	isc_boolean_t wanted_chaining;
+-	unsigned int aflag, chaining;
++	dns_message_t *message = NULL;
++	dns_name_t *name = NULL, *qname = NULL, *ns_name = NULL;
++	dns_name_t *aname = NULL, *cname = NULL, *dname = NULL;
++	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
++	dns_rdataset_t *ardataset = NULL, *crdataset = NULL;
++	dns_rdataset_t *drdataset = NULL, *ns_rdataset = NULL;
++	isc_boolean_t done = ISC_FALSE, aa;
++	unsigned int dname_labels, domain_labels;
++	isc_boolean_t chaining = ISC_FALSE;
+ 	dns_rdatatype_t type;
+-	dns_fixedname_t fdname, fqname;
+-	dns_view_t *view;
++	dns_view_t *view = NULL;
++	dns_trust_t trust;
++
++	REQUIRE(VALID_FCTX(fctx));
+ 
+ 	FCTXTRACE("answer_response");
+ 
+ 	message = fctx->rmessage;
++	qname = &fctx->name;
++	view = fctx->res->view;
++	type = fctx->type;
+ 
+ 	/*
+-	 * Examine the answer section, marking those rdatasets which are
+-	 * part of the answer and should be cached.
++	 * There can be multiple RRSIG and SIG records at a name so
++	 * we treat these types as a subset of ANY.
+ 	 */
++	if (type == dns_rdatatype_rrsig || type == dns_rdatatype_sig) {
++		type = dns_rdatatype_any;
++	}
+ 
+-	done = ISC_FALSE;
+-	found_cname = ISC_FALSE;
+-	found_dname = ISC_FALSE;
+-	found_type = ISC_FALSE;
+-	have_answer = ISC_FALSE;
+-	want_chaining = ISC_FALSE;
+-	chaining = 0;
+-	POST(want_chaining);
+-	if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
+-		aa = ISC_TRUE;
+-	else
+-		aa = ISC_FALSE;
+-	qname = &fctx->name;
+-	type = fctx->type;
+-	view = fctx->res->view;
+-	result = dns_message_firstname(message, DNS_SECTION_ANSWER);
+-	while (!done && result == ISC_R_SUCCESS) {
+-		dns_namereln_t namereln, lastreln;
+-		int order, lastorder;
+-		unsigned int nlabels, lastnlabels;
++	/*
++	 * Bigger than any valid DNAME label count.
++	 */
++	dname_labels = dns_name_countlabels(qname);
++	domain_labels = dns_name_countlabels(&fctx->domain);
++
++	/*
++	 * Perform a single pass looking for the answer, cname or covering
++	 * dname.
++	 */
++	for (result = dns_message_firstname(message, DNS_SECTION_ANSWER);
++	     result == ISC_R_SUCCESS;
++	     result = dns_message_nextname(message, DNS_SECTION_ANSWER))
++	{
++		int order;
++		unsigned int nlabels;
++		dns_namereln_t namereln;
+ 
+ 		name = NULL;
+ 		dns_message_currentname(message, DNS_SECTION_ANSWER, &name);
+-		external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
+ 		namereln = dns_name_fullcompare(qname, name, &order, &nlabels);
+-
+-		if (namereln == dns_namereln_equal) {
+-			wanted_chaining = ISC_FALSE;
++		switch (namereln) {
++		case dns_namereln_equal:
+ 			for (rdataset = ISC_LIST_HEAD(name->list);
+ 			     rdataset != NULL;
+-			     rdataset = ISC_LIST_NEXT(rdataset, link)) {
+-				found = ISC_FALSE;
+-				want_chaining = ISC_FALSE;
+-				aflag = 0;
+-				if (rdataset->type == dns_rdatatype_nsec3) {
+-					/*
+-					 * NSEC3 records are not allowed to
+-					 * appear in the answer section.
+-					 */
+-					log_formerr(fctx, "NSEC3 in answer");
+-					return (DNS_R_FORMERR);
+-				}
+-				if (rdataset->type == dns_rdatatype_tkey) {
+-					/*
+-					 * TKEY is not a valid record in a
+-					 * response to any query we can make.
+-					 */
+-					log_formerr(fctx, "TKEY in answer");
+-					return (DNS_R_FORMERR);
+-				}
+-				if (rdataset->rdclass != fctx->res->rdclass) {
+-					log_formerr(fctx, "Mismatched class "
+-						    "in answer");
+-					return (DNS_R_FORMERR);
+-				}
+-
+-				/*
+-				 * Apply filters, if given, on answers to reject
+-				 * a malicious attempt of rebinding.
+-				 */
+-				if ((rdataset->type == dns_rdatatype_a ||
+-				     rdataset->type == dns_rdatatype_aaaa) &&
+-				    !is_answeraddress_allowed(view, name,
+-							      rdataset)) {
+-					return (DNS_R_SERVFAIL);
+-				}
+-
+-				if (rdataset->type == type && !found_cname) {
+-					/*
+-					 * We've found an ordinary answer.
+-					 */
+-					found = ISC_TRUE;
+-					found_type = ISC_TRUE;
+-					done = ISC_TRUE;
+-					aflag = DNS_RDATASETATTR_ANSWER;
+-				} else if (type == dns_rdatatype_any) {
+-					/*
+-					 * We've found an answer matching
+-					 * an ANY query.  There may be
+-					 * more.
+-					 */
+-					found = ISC_TRUE;
+-					aflag = DNS_RDATASETATTR_ANSWER;
+-				} else if (rdataset->type == dns_rdatatype_rrsig
+-					   && rdataset->covers == type
+-					   && !found_cname) {
+-					/*
+-					 * We've found a signature that
+-					 * covers the type we're looking for.
+-					 */
+-					found = ISC_TRUE;
+-					found_type = ISC_TRUE;
+-					aflag = DNS_RDATASETATTR_ANSWERSIG;
+-				} else if (rdataset->type ==
+-					   dns_rdatatype_cname
+-					   && !found_type) {
+-					/*
+-					 * We're looking for something else,
+-					 * but we found a CNAME.
+-					 *
+-					 * Getting a CNAME response for some
+-					 * query types is an error, see
+-					 * RFC 4035, Section 2.5.
+-					 */
+-					if (type == dns_rdatatype_rrsig ||
+-					    type == dns_rdatatype_key ||
+-					    type == dns_rdatatype_nsec) {
+-						char buf[DNS_RDATATYPE_FORMATSIZE];
+-						dns_rdatatype_format(fctx->type,
+-							      buf, sizeof(buf));
+-						log_formerr(fctx,
+-							    "CNAME response "
+-							    "for %s RR", buf);
+-						return (DNS_R_FORMERR);
+-					}
+-					found = ISC_TRUE;
+-					found_cname = ISC_TRUE;
+-					want_chaining = ISC_TRUE;
+-					aflag = DNS_RDATASETATTR_ANSWER;
+-					result = cname_target(rdataset,
+-							      &tname);
+-					if (result != ISC_R_SUCCESS)
+-						return (result);
+-					/* Apply filters on the target name. */
+-					if (!is_answertarget_allowed(view,
+-							name,
+-							rdataset->type,
+-							&tname,
+-							&fctx->domain)) {
+-						return (DNS_R_SERVFAIL);
++			     rdataset = ISC_LIST_NEXT(rdataset, link))
++			{
++				if (rdataset->type == type ||
++				    type == dns_rdatatype_any)
++				{
++					aname = name;
++					if (type != dns_rdatatype_any) {
++						ardataset = rdataset;
+ 					}
+-					lastcname = name;
+-				} else if (rdataset->type == dns_rdatatype_rrsig
+-					   && rdataset->covers ==
+-					   dns_rdatatype_cname
+-					   && !found_type) {
+-					/*
+-					 * We're looking for something else,
+-					 * but we found a SIG CNAME.
+-					 */
+-					found = ISC_TRUE;
+-					found_cname = ISC_TRUE;
+-					aflag = DNS_RDATASETATTR_ANSWERSIG;
++					break;
+ 				}
+-
+-				if (found) {
+-					/*
+-					 * We've found an answer to our
+-					 * question.
+-					 */
+-					name->attributes |=
+-						DNS_NAMEATTR_CACHE;
+-					rdataset->attributes |=
+-						DNS_RDATASETATTR_CACHE;
+-					rdataset->trust = dns_trust_answer;
+-					if (chaining == 0) {
+-						/*
+-						 * This data is "the" answer
+-						 * to our question only if
+-						 * we're not chaining (i.e.
+-						 * if we haven't followed
+-						 * a CNAME or DNAME).
+-						 */
+-						INSIST(!external);
+-						/*
+-						 * Don't use found_cname here
+-						 * as we have just set it
+-						 * above.
+-						 */
+-						if (cname == NULL &&
+-						    !found_dname &&
+-						    aflag ==
+-						     DNS_RDATASETATTR_ANSWER)
+-						{
+-							have_answer = ISC_TRUE;
+-							if (found_cname &&
+-							    cname == NULL)
+-								cname = name;
+-							name->attributes |=
+-								DNS_NAMEATTR_ANSWER;
+-						}
+-						rdataset->attributes |= aflag;
+-						if (aa)
+-							rdataset->trust =
+-							  dns_trust_authanswer;
+-					} else if (external) {
+-						/*
+-						 * This data is outside of
+-						 * our query domain, and
+-						 * may not be cached.
+-						 */
+-						rdataset->attributes |=
+-						    DNS_RDATASETATTR_EXTERNAL;
+-					}
+-
+-					/*
+-					 * Mark any additional data related
+-					 * to this rdataset.
+-					 */
+-					(void)dns_rdataset_additionaldata(
+-							rdataset,
+-							check_related,
+-							fctx);
+-
+-					/*
+-					 * CNAME chaining.
+-					 */
+-					if (want_chaining) {
+-						wanted_chaining = ISC_TRUE;
+-						name->attributes |=
+-							DNS_NAMEATTR_CHAINING;
+-						rdataset->attributes |=
+-						    DNS_RDATASETATTR_CHAINING;
+-						qname = &tname;
+-					}
++				if (rdataset->type == dns_rdatatype_cname) {
++					cname = name;
++					crdataset = rdataset;
++					break;
+ 				}
+-				/*
+-				 * We could add an "else" clause here and
+-				 * log that we're ignoring this rdataset.
+-				 */
+ 			}
++			break;
++
++		case dns_namereln_subdomain:
+ 			/*
+-			 * If wanted_chaining is true, we've done
+-			 * some chaining as the result of processing
+-			 * this node, and thus we need to set
+-			 * chaining to true.
+-			 *
+-			 * We don't set chaining inside of the
+-			 * rdataset loop because doing that would
+-			 * cause us to ignore the signatures of
+-			 * CNAMEs.
++			 * In-scope DNAME records must have at least
++			 * as many labels as the domain being queried.
++			 * They also must be less that qname's labels
++			 * and any previously found dname.
+ 			 */
+-			if (wanted_chaining && chaining < 2U)
+-				chaining++;
+-		} else {
+-			dns_rdataset_t *dnameset = NULL;
+-			isc_boolean_t synthcname = ISC_FALSE;
+-
+-			if (lastcname != NULL) {
+-				lastreln = dns_name_fullcompare(lastcname,
+-								name,
+-								&lastorder,
+-								&lastnlabels);
+-				if (lastreln == dns_namereln_subdomain &&
+-				    lastnlabels == dns_name_countlabels(name))
+-					synthcname = ISC_TRUE;
++			if (nlabels >= dname_labels || nlabels < domain_labels)
++			{
++				continue;
+ 			}
+ 
+ 			/*
+-			 * Look for a DNAME (or its SIG).  Anything else is
+-			 * ignored.
++			 * We are looking for the shortest DNAME if there
++			 * are multiple ones (which there shouldn't be).
+ 			 */
+-			wanted_chaining = ISC_FALSE;
+ 			for (rdataset = ISC_LIST_HEAD(name->list);
+ 			     rdataset != NULL;
+ 			     rdataset = ISC_LIST_NEXT(rdataset, link))
+ 			{
+-				if (rdataset->rdclass != fctx->res->rdclass) {
+-					log_formerr(fctx, "Mismatched class "
+-						    "in answer");
+-					return (DNS_R_FORMERR);
+-				}
+-
+-				/*
+-				 * Only pass DNAME or RRSIG(DNAME).
+-				 */
+-				if (rdataset->type != dns_rdatatype_dname &&
+-				    (rdataset->type != dns_rdatatype_rrsig ||
+-				     rdataset->covers != dns_rdatatype_dname))
++				if (rdataset->type != dns_rdatatype_dname) {
+ 					continue;
+-
+-				/*
+-				 * If we're not chaining, then the DNAME and
+-				 * its signature should not be external.
+-				 */
+-				if (chaining == 0 && external) {
+-					char qbuf[DNS_NAME_FORMATSIZE];
+-					char obuf[DNS_NAME_FORMATSIZE];
+-
+-					dns_name_format(name, qbuf,
+-							sizeof(qbuf));
+-					dns_name_format(&fctx->domain, obuf,
+-							sizeof(obuf));
+-					log_formerr(fctx, "external DNAME or "
+-						    "RRSIG covering DNAME "
+-						    "in answer: %s is "
+-						    "not in %s", qbuf, obuf);
+-					return (DNS_R_FORMERR);
+-				}
+-
+-				/*
+-				 * If DNAME + synthetic CNAME then the
+-				 * namereln is dns_namereln_subdomain.
+-				 */
+-				if (namereln != dns_namereln_subdomain &&
+-				    !synthcname)
+-				{
+-					char qbuf[DNS_NAME_FORMATSIZE];
+-					char obuf[DNS_NAME_FORMATSIZE];
+-
+-					dns_name_format(qname, qbuf,
+-							sizeof(qbuf));
+-					dns_name_format(name, obuf,
+-							sizeof(obuf));
+-					log_formerr(fctx, "unrelated DNAME "
+-						    "in answer: %s is "
+-						    "not in %s", qbuf, obuf);
+-					return (DNS_R_FORMERR);
+ 				}
++				dname = name;
++				drdataset = rdataset;
++				dname_labels = nlabels;
++				break;
++			}
++			break;
++		default:
++			break;
++		}
++	}
+ 
+-				aflag = 0;
+-				if (rdataset->type == dns_rdatatype_dname) {
+-					want_chaining = ISC_TRUE;
+-					POST(want_chaining);
+-					aflag = DNS_RDATASETATTR_ANSWER;
+-					dns_fixedname_init(&fdname);
+-					dname = dns_fixedname_name(&fdname);
+-					if (synthcname) {
+-						result = fromdname(rdataset,
+-								   lastcname,
+-								   lastnlabels,
+-								   qname);
+-					} else {
+-						result = dname_target(rdataset,
+-								      qname,
+-								      nlabels,
+-								      dname);
+-					}
+-					if (result == ISC_R_NOSPACE) {
+-						/*
+-						 * We can't construct the
+-						 * DNAME target.  Do not
+-						 * try to continue.
+-						 */
+-						want_chaining = ISC_FALSE;
+-						POST(want_chaining);
+-					} else if (result != ISC_R_SUCCESS)
+-						return (result);
+-					else
+-						dnameset = rdataset;
++	if (dname != NULL) {
++		aname = NULL;
++		ardataset = NULL;
++		cname = NULL;
++		crdataset = NULL;
++	} else if (aname != NULL) {
++		cname = NULL;
++		crdataset = NULL;
++	}
+ 
+-					if (!synthcname &&
+-					    !is_answertarget_allowed(view,
+-						     qname, rdataset->type,
+-						     dname, &fctx->domain))
+-					{
+-						return (DNS_R_SERVFAIL);
+-					}
+-				} else {
+-					/*
+-					 * We've found a signature that
+-					 * covers the DNAME.
+-					 */
+-					aflag = DNS_RDATASETATTR_ANSWERSIG;
+-				}
++	aa = ISC_TF((message->flags & DNS_MESSAGEFLAG_AA) != 0);
++	trust = aa ? dns_trust_authanswer : dns_trust_answer;
+ 
+-				/*
+-				 * We've found an answer to our
+-				 * question.
+-				 */
+-				name->attributes |= DNS_NAMEATTR_CACHE;
+-				rdataset->attributes |= DNS_RDATASETATTR_CACHE;
+-				rdataset->trust = dns_trust_answer;
+-				/*
+-				 * If we are not chaining or the first CNAME
+-				 * is a synthesised CNAME before the DNAME.
+-				 */
+-				if ((chaining == 0) ||
+-				    (chaining == 1U && synthcname))
+-				{
+-					/*
+-					 * This data is "the" answer to
+-					 * our question only if we're
+-					 * not chaining.
+-					 */
+-					INSIST(!external);
+-					if (aflag == DNS_RDATASETATTR_ANSWER) {
+-						have_answer = ISC_TRUE;
+-						found_dname = ISC_TRUE;
+-						if (cname != NULL &&
+-						    synthcname)
+-						{
+-							cname->attributes &=
+-							   ~DNS_NAMEATTR_ANSWER;
+-						}
+-						name->attributes |=
+-							DNS_NAMEATTR_ANSWER;
+-					}
+-					rdataset->attributes |= aflag;
+-					if (aa)
+-						rdataset->trust =
+-						  dns_trust_authanswer;
+-				} else if (external) {
+-					rdataset->attributes |=
+-					    DNS_RDATASETATTR_EXTERNAL;
+-				}
++	if (aname != NULL && type == dns_rdatatype_any) {
++		for (rdataset = ISC_LIST_HEAD(aname->list);
++		     rdataset != NULL;
++		     rdataset = ISC_LIST_NEXT(rdataset, link))
++		{
++			if (!validinanswer(rdataset, fctx)) {
++				return (DNS_R_FORMERR);
+ 			}
+-
+-			/*
+-			 * DNAME chaining.
+-			 */
+-			if (dnameset != NULL) {
+-				if (!synthcname) {
+-					/*
+-					 * Copy the dname into the qname fixed
+-					 * name.
+-					 *
+-					 * Although we check for failure of the
+-					 * copy operation, in practice it
+-					 * should never fail since we already
+-					 * know that the result fits in a
+-					 * fixedname.
+-					 */
+-					dns_fixedname_init(&fqname);
+-					qname = dns_fixedname_name(&fqname);
+-					result = dns_name_copy(dname, qname,
+-							       NULL);
+-					if (result != ISC_R_SUCCESS)
+-						return (result);
+-				}
+-				wanted_chaining = ISC_TRUE;
+-				name->attributes |= DNS_NAMEATTR_CHAINING;
+-				dnameset->attributes |=
+-					    DNS_RDATASETATTR_CHAINING;
++			if ((fctx->type == dns_rdatatype_sig ||
++			     fctx->type == dns_rdatatype_rrsig) &&
++			     rdataset->type != fctx->type)
++			{
++				continue;
+ 			}
+-			/*
+-			 * Ensure that we can't ever get chaining == 1
+-			 * above if we have processed a DNAME.
+-			 */
+-			if (wanted_chaining && chaining < 2U)
+-				chaining += 2;
++			if ((rdataset->type == dns_rdatatype_a ||
++			     rdataset->type == dns_rdatatype_aaaa) &&
++			    !is_answeraddress_allowed(view, aname, rdataset))
++			{
++				return (DNS_R_SERVFAIL);
++			}
++			if ((rdataset->type == dns_rdatatype_cname ||
++			     rdataset->type == dns_rdatatype_dname) &&
++			     !is_answertarget_allowed(fctx, qname, aname,
++						      rdataset, NULL))
++			{
++				return (DNS_R_SERVFAIL);
++			}
++			aname->attributes |= DNS_NAMEATTR_CACHE;
++			aname->attributes |= DNS_NAMEATTR_ANSWER;
++			rdataset->attributes |= DNS_RDATASETATTR_ANSWER;
++			rdataset->attributes |= DNS_RDATASETATTR_CACHE;
++			rdataset->trust = trust;
++			(void)dns_rdataset_additionaldata(rdataset,
++							  check_related,
++							  fctx);
+ 		}
+-		result = dns_message_nextname(message, DNS_SECTION_ANSWER);
+-	}
+-	if (result == ISC_R_NOMORE)
+-		result = ISC_R_SUCCESS;
+-	if (result != ISC_R_SUCCESS)
+-		return (result);
+-
+-	/*
+-	 * We should have found an answer.
+-	 */
+-	if (!have_answer) {
++	} else if (aname != NULL) {
++		if (!validinanswer(ardataset, fctx))
++			return (DNS_R_FORMERR);
++		if ((ardataset->type == dns_rdatatype_a ||
++		     ardataset->type == dns_rdatatype_aaaa) &&
++		    !is_answeraddress_allowed(view, aname, ardataset)) {
++			return (DNS_R_SERVFAIL);
++		}
++		if ((ardataset->type == dns_rdatatype_cname ||
++		     ardataset->type == dns_rdatatype_dname) &&
++		     !is_answertarget_allowed(fctx, qname, aname, ardataset,
++					      NULL))
++		{
++			return (DNS_R_SERVFAIL);
++		}
++		aname->attributes |= DNS_NAMEATTR_CACHE;
++		aname->attributes |= DNS_NAMEATTR_ANSWER;
++		ardataset->attributes |= DNS_RDATASETATTR_ANSWER;
++		ardataset->attributes |= DNS_RDATASETATTR_CACHE;
++		ardataset->trust = trust;
++		(void)dns_rdataset_additionaldata(ardataset, check_related,
++						  fctx);
++		for (sigrdataset = ISC_LIST_HEAD(aname->list);
++		     sigrdataset != NULL;
++		     sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
++			if (!validinanswer(sigrdataset, fctx))
++				return (DNS_R_FORMERR);
++			if (sigrdataset->type != dns_rdatatype_rrsig ||
++			    sigrdataset->covers != type)
++				continue;
++			sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG;
++			sigrdataset->attributes |= DNS_RDATASETATTR_CACHE;
++			sigrdataset->trust = trust;
++			break;
++		}
++	} else if (cname != NULL) {
++		if (!validinanswer(crdataset, fctx)) {
++			return (DNS_R_FORMERR);
++		}
++		if (type == dns_rdatatype_rrsig || type == dns_rdatatype_key ||
++		    type == dns_rdatatype_nsec)
++		{
++			char buf[DNS_RDATATYPE_FORMATSIZE];
++			dns_rdatatype_format(type, buf, sizeof(buf));
++			log_formerr(fctx, "CNAME response for %s RR", buf);
++			return (DNS_R_FORMERR);
++		}
++		if (!is_answertarget_allowed(fctx, qname, cname, crdataset,
++					     NULL))
++		{
++			return (DNS_R_SERVFAIL);
++		}
++		cname->attributes |= DNS_NAMEATTR_CACHE;
++		cname->attributes |= DNS_NAMEATTR_ANSWER;
++		cname->attributes |= DNS_NAMEATTR_CHAINING;
++		crdataset->attributes |= DNS_RDATASETATTR_ANSWER;
++		crdataset->attributes |= DNS_RDATASETATTR_CACHE;
++		crdataset->attributes |= DNS_RDATASETATTR_CHAINING;
++		crdataset->trust = trust;
++		for (sigrdataset = ISC_LIST_HEAD(cname->list);
++		     sigrdataset != NULL;
++		     sigrdataset = ISC_LIST_NEXT(sigrdataset, link))
++		{
++			if (!validinanswer(sigrdataset, fctx)) {
++				return (DNS_R_FORMERR);
++			}
++			if (sigrdataset->type != dns_rdatatype_rrsig ||
++			    sigrdataset->covers != dns_rdatatype_cname)
++			{
++				continue;
++			}
++			sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG;
++			sigrdataset->attributes |= DNS_RDATASETATTR_CACHE;
++			sigrdataset->trust = trust;
++			break;
++		}
++		chaining = ISC_TRUE;
++	} else if (dname != NULL) {
++		if (!validinanswer(drdataset, fctx)) {
++			return (DNS_R_FORMERR);
++		}
++		if (!is_answertarget_allowed(fctx, qname, dname, drdataset,
++					     &chaining)) {
++			return (DNS_R_SERVFAIL);
++		}
++		dname->attributes |= DNS_NAMEATTR_CACHE;
++		dname->attributes |= DNS_NAMEATTR_ANSWER;
++		dname->attributes |= DNS_NAMEATTR_CHAINING;
++		drdataset->attributes |= DNS_RDATASETATTR_ANSWER;
++		drdataset->attributes |= DNS_RDATASETATTR_CACHE;
++		drdataset->attributes |= DNS_RDATASETATTR_CHAINING;
++		drdataset->trust = trust;
++		for (sigrdataset = ISC_LIST_HEAD(dname->list);
++		     sigrdataset != NULL;
++		     sigrdataset = ISC_LIST_NEXT(sigrdataset, link))
++		{
++			if (!validinanswer(sigrdataset, fctx)) {
++				return (DNS_R_FORMERR);
++			}
++			if (sigrdataset->type != dns_rdatatype_rrsig ||
++			    sigrdataset->covers != dns_rdatatype_dname)
++			{
++				continue;
++			}
++			sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG;
++			sigrdataset->attributes |= DNS_RDATASETATTR_CACHE;
++			sigrdataset->trust = trust;
++			break;
++		}
++	} else {
+ 		log_formerr(fctx, "reply has no answer");
+ 		return (DNS_R_FORMERR);
+ 	}
+@@ -6536,14 +6340,8 @@ answer_response(fetchctx_t *fctx) {
+ 	/*
+ 	 * Did chaining end before we got the final answer?
+ 	 */
+-	if (chaining != 0) {
+-		/*
+-		 * Yes.  This may be a negative reply, so hand off
+-		 * authority section processing to the noanswer code.
+-		 * If it isn't a noanswer response, no harm will be
+-		 * done.
+-		 */
+-		return (noanswer_response(fctx, qname, 0));
++	if (chaining) {
++		return (ISC_R_SUCCESS);
+ 	}
+ 
+ 	/*
+@@ -6562,11 +6360,9 @@ answer_response(fetchctx_t *fctx) {
+ 	 * We expect there to be only one owner name for all the rdatasets
+ 	 * in this section, and we expect that it is not external.
+ 	 */
+-	done = ISC_FALSE;
+-	ns_name = NULL;
+-	ns_rdataset = NULL;
+ 	result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+ 	while (!done && result == ISC_R_SUCCESS) {
++		isc_boolean_t external;
+ 		name = NULL;
+ 		dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+ 		external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
+@@ -6585,12 +6381,13 @@ answer_response(fetchctx_t *fctx) {
+ 						DNS_NAMEATTR_CACHE;
+ 					rdataset->attributes |=
+ 						DNS_RDATASETATTR_CACHE;
+-					if (aa && chaining == 0)
++					if (aa && !chaining) {
+ 						rdataset->trust =
+ 						    dns_trust_authauthority;
+-					else
++					} else {
+ 						rdataset->trust =
+ 						    dns_trust_additional;
++					}
+ 
+ 					if (rdataset->type == dns_rdatatype_ns)
+ 					{
+@@ -7249,6 +7046,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
+ 	 * Is the remote server broken, or does it dislike us?
+ 	 */
+ 	if (message->rcode != dns_rcode_noerror &&
++	    message->rcode != dns_rcode_yxdomain &&
+ 	    message->rcode != dns_rcode_nxdomain) {
+ 		if (((message->rcode == dns_rcode_formerr ||
+ 		      message->rcode == dns_rcode_notimp) ||
+@@ -7293,13 +7091,6 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
+ 				log_formerr(fctx, "server sent FORMERR");
+ 				result = DNS_R_FORMERR;
+ 			}
+-		} else if (message->rcode == dns_rcode_yxdomain) {
+-			/*
+-			 * DNAME mapping failed because the new name
+-			 * was too long.  There's no chance of success
+-			 * for this fetch.
+-			 */
+-			result = DNS_R_YXDOMAIN;
+ 		} else if (message->rcode == dns_rcode_badvers) {
+ 			unsigned int flags, mask;
+ 			unsigned int version;
+@@ -7404,6 +7195,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
+ 	 */
+ 	if (message->counts[DNS_SECTION_ANSWER] > 0 &&
+ 	    (message->rcode == dns_rcode_noerror ||
++	     message->rcode == dns_rcode_yxdomain ||
+ 	     message->rcode == dns_rcode_nxdomain)) {
+ 		/*
+ 		 * [normal case]
+-- 
+2.9.3
+
diff --git a/SPECS/bind.spec b/SPECS/bind.spec
index 69626bb..28a3d5d 100644
--- a/SPECS/bind.spec
+++ b/SPECS/bind.spec
@@ -25,7 +25,7 @@ Summary:  The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) serv
 Name:     bind
 License:  ISC
 Version:  9.9.4
-Release:  38%{?PATCHVER}%{?PREVER}%{?dist}.2
+Release:  38%{?PATCHVER}%{?PREVER}%{?dist}.3
 Epoch:    32
 Url:      http://www.isc.org/products/BIND/
 Buildroot:%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@@ -121,6 +121,10 @@ Patch173:bind99-rt43779.patch
 Patch174:bind99-CVE-2017-3135.patch
 # ISC 4558
 Patch175:bind99-rt44318.patch
+# ISC 4575
+Patch176:bind99-CVE-2017-3136.patch
+# ISC 4578
+Patch177:bind99-CVE-2017-3137.patch
 
 # Native PKCS#11 functionality from 9.10
 Patch150:bind-9.9-allow_external_dnskey.patch
@@ -416,6 +420,8 @@ tar -xf %{SOURCE48} -C bin/tests/system/geoip/data
 %patch173 -p1 -b .rt43779
 %patch174 -p1 -b .CVE-2017-3135
 %patch175 -p1 -b .rt44318
+%patch176 -p1 -b .CVE-2017-3136
+%patch177 -p1 -b .CVE-2017-3137
 
 %if %{PKCS11}
 cp -r bin/named{,-pkcs11}
@@ -1095,6 +1101,10 @@ rm -rf ${RPM_BUILD_ROOT}
 %endif
 
 %changelog
+* Wed Apr 12 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-38.3
+- Fix CVE-2017-3136 (ISC change 4575)
+- Fix CVE-2017-3137 (ISC change 4578)
+
 * Wed Feb 08 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-38.2
 - Fix CVE-2017-3135 (ISC change 4557)
 - Fix and test caching CNAME before DNAME (ISC change 4558)