mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 12:30:00 -04:00
[v9_9] change 4558 was incomplete
(cherry picked from commit cd668ea57f)
This commit is contained in:
parent
61a5559acd
commit
a6bae6d52c
5 changed files with 212 additions and 40 deletions
95
bin/tests/system/dname/ans3/ans.pl
Normal file
95
bin/tests/system/dname/ans3/ans.pl
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/env perl
|
||||
#
|
||||
# Copyright (C) 2014-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/.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use IO::File;
|
||||
use Getopt::Long;
|
||||
use Net::DNS::Nameserver;
|
||||
|
||||
my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!";
|
||||
print $pidf "$$\n" or die "cannot write pid file: $!";
|
||||
$pidf->close or die "cannot close pid file: $!";
|
||||
sub rmpid { unlink "ans.pid"; exit 1; };
|
||||
|
||||
$SIG{INT} = \&rmpid;
|
||||
$SIG{TERM} = \&rmpid;
|
||||
|
||||
my $localaddr = "10.53.0.3";
|
||||
my $localport = 5300;
|
||||
my $verbose = 0;
|
||||
my $ttl = 60;
|
||||
my $zone = "example.broken";
|
||||
my $nsname = "ns3.$zone";
|
||||
my $synth = "synth-then-dname.$zone";
|
||||
my $synth2 = "synth2-then-dname.$zone";
|
||||
|
||||
sub reply_handler {
|
||||
my ($qname, $qclass, $qtype, $peerhost, $query, $conn) = @_;
|
||||
my ($rcode, @ans, @auth, @add);
|
||||
|
||||
print ("request: $qname/$qtype\n");
|
||||
STDOUT->flush();
|
||||
|
||||
if ($qname eq "example.broken") {
|
||||
if ($qtype eq "SOA") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass SOA . . 0 0 0 0 0");
|
||||
push @ans, $rr;
|
||||
} elsif ($qtype eq "NS") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass NS $nsname");
|
||||
push @ans, $rr;
|
||||
$rr = new Net::DNS::RR("$nsname $ttl $qclass A $localaddr");
|
||||
push @add, $rr;
|
||||
}
|
||||
$rcode = "NOERROR";
|
||||
} elsif ($qname eq "cname-to-$synth2") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.$synth2");
|
||||
push @ans, $rr;
|
||||
$rr = new Net::DNS::RR("name.$synth2 $ttl $qclass CNAME name");
|
||||
push @ans, $rr;
|
||||
$rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME .");
|
||||
push @ans, $rr;
|
||||
$rcode = "NOERROR";
|
||||
} elsif ($qname eq "$synth" || $qname eq "$synth2") {
|
||||
if ($qtype eq "DNAME") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass DNAME .");
|
||||
push @ans, $rr;
|
||||
}
|
||||
$rcode = "NOERROR";
|
||||
} elsif ($qname eq "name.$synth") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.");
|
||||
push @ans, $rr;
|
||||
$rr = new Net::DNS::RR("$synth $ttl $qclass DNAME .");
|
||||
push @ans, $rr;
|
||||
$rcode = "NOERROR";
|
||||
} elsif ($qname eq "name.$synth2") {
|
||||
my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.");
|
||||
push @ans, $rr;
|
||||
$rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME .");
|
||||
push @ans, $rr;
|
||||
$rcode = "NOERROR";
|
||||
} else {
|
||||
$rcode = "REFUSED";
|
||||
}
|
||||
return ($rcode, \@ans, \@auth, \@add, { aa => 1 });
|
||||
}
|
||||
|
||||
GetOptions(
|
||||
'port=i' => \$localport,
|
||||
'verbose!' => \$verbose,
|
||||
);
|
||||
|
||||
my $ns = Net::DNS::Nameserver->new(
|
||||
LocalAddr => $localaddr,
|
||||
LocalPort => $localport,
|
||||
ReplyHandler => \&reply_handler,
|
||||
Verbose => $verbose,
|
||||
);
|
||||
|
||||
$ns->main_loop;
|
||||
|
|
@ -12,8 +12,6 @@
|
|||
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
; PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
; $Id: root.db,v 1.2 2011/03/18 21:14:19 fdupont Exp $
|
||||
|
||||
$TTL 300
|
||||
. IN SOA gson.nominum.com. a.root.servers.nil. (
|
||||
2000042100 ; serial
|
||||
|
|
@ -27,3 +25,6 @@ a.root-servers.nil. A 10.53.0.1
|
|||
|
||||
example. NS ns2.example.
|
||||
ns2.example. A 10.53.0.2
|
||||
|
||||
example.broken. NS ns3.example.broken.
|
||||
ns3.example.broken. A 10.53.0.3
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ SYSTEMTESTTOP=..
|
|||
. $SYSTEMTESTTOP/conf.sh
|
||||
|
||||
status=0
|
||||
n=0
|
||||
|
||||
echo "I:checking short dname from authoritative"
|
||||
ret=0
|
||||
|
|
@ -81,6 +82,26 @@ grep '^a.target.example.' dig.out.ns4.cname > /dev/null || ret=1
|
|||
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
echo "I:exit status: $status"
|
||||
n=`expr $n + 1`
|
||||
echo "I:checking dname is returned with synthesized cname before dname ($n)"
|
||||
ret=0
|
||||
$DIG @10.53.0.4 -p 5300 name.synth-then-dname.example.broken A > dig.out.test$n
|
||||
grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
|
||||
grep '^name.synth-then-dname\.example\.broken\..*CNAME.*name.$' dig.out.test$n > /dev/null || ret=1
|
||||
grep '^synth-then-dname\.example\.broken\..*DNAME.*\.$' dig.out.test$n > /dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
n=`expr $n + 1`
|
||||
echo "I:checking dname is returned with cname to synthesized cname before dname ($n)"
|
||||
ret=0
|
||||
$DIG @10.53.0.4 -p 5300 cname-to-synth2-then-dname.example.broken A > dig.out.test$n
|
||||
grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
|
||||
grep '^cname-to-synth2-then-dname\.example\.broken\..*CNAME.*name\.synth2-then-dname\.example\.broken.$' dig.out.test$n > /dev/null || ret=1
|
||||
grep '^name\.synth2-then-dname\.example\.broken\..*CNAME.*name.$' dig.out.test$n > /dev/null || ret=1
|
||||
grep '^synth2-then-dname\.example\.broken\..*DNAME.*\.$' dig.out.test$n > /dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
echo "I:exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
|
|
|||
|
|
@ -137,6 +137,14 @@
|
|||
|
||||
<section xml:id="relnotes_bugs"><info><title>Bug Fixes</title></info>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
A synthesized CNAME record appearing in a response before the
|
||||
associated DNAME could be cached, when it should not have been.
|
||||
This was a regression introduced while addressing CVE-2016-8864.
|
||||
[RT #44318]
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Named could deadlock there were multiple changes to
|
||||
|
|
|
|||
|
|
@ -5818,9 +5818,13 @@ cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) {
|
|||
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_fixedname_t *fixeddname)
|
||||
dname_target(dns_rdataset_t *rdataset, const dns_name_t *qname,
|
||||
unsigned int nlabels, dns_name_t *target)
|
||||
{
|
||||
isc_result_t result;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
|
|
@ -5840,14 +5844,33 @@ dname_target(dns_rdataset_t *rdataset, dns_name_t *qname,
|
|||
|
||||
dns_fixedname_init(&prefix);
|
||||
dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL);
|
||||
dns_fixedname_init(fixeddname);
|
||||
result = dns_name_concatenate(dns_fixedname_name(&prefix),
|
||||
&dname.dname,
|
||||
dns_fixedname_name(fixeddname), NULL);
|
||||
&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, const 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)
|
||||
|
|
@ -6464,7 +6487,7 @@ 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;
|
||||
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;
|
||||
|
|
@ -6500,14 +6523,15 @@ answer_response(fetchctx_t *fctx) {
|
|||
view = fctx->res->view;
|
||||
result = dns_message_firstname(message, DNS_SECTION_ANSWER);
|
||||
while (!done && result == ISC_R_SUCCESS) {
|
||||
dns_namereln_t namereln;
|
||||
int order;
|
||||
unsigned int nlabels;
|
||||
dns_namereln_t namereln, lastreln;
|
||||
int order, lastorder;
|
||||
unsigned int nlabels, lastnlabels;
|
||||
|
||||
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;
|
||||
for (rdataset = ISC_LIST_HEAD(name->list);
|
||||
|
|
@ -6613,6 +6637,7 @@ answer_response(fetchctx_t *fctx) {
|
|||
&fctx->domain)) {
|
||||
return (DNS_R_SERVFAIL);
|
||||
}
|
||||
lastcname = name;
|
||||
} else if (rdataset->type == dns_rdatatype_rrsig
|
||||
&& rdataset->covers ==
|
||||
dns_rdatatype_cname
|
||||
|
|
@ -6717,6 +6742,17 @@ answer_response(fetchctx_t *fctx) {
|
|||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for a DNAME (or its SIG). Anything else is
|
||||
|
|
@ -6763,16 +6799,9 @@ answer_response(fetchctx_t *fctx) {
|
|||
/*
|
||||
* If DNAME + synthetic CNAME then the
|
||||
* namereln is dns_namereln_subdomain.
|
||||
*
|
||||
* If synthetic CNAME + DNAME then the
|
||||
* namereln is dns_namereln_commonancestor
|
||||
* and the number of label must match the
|
||||
* DNAME. This order is not RFC compliant.
|
||||
*/
|
||||
|
||||
if (namereln != dns_namereln_subdomain &&
|
||||
(namereln != dns_namereln_commonancestor ||
|
||||
nlabels != dns_name_countlabels(name)))
|
||||
!synthcname)
|
||||
{
|
||||
char qbuf[DNS_NAME_FORMATSIZE];
|
||||
char obuf[DNS_NAME_FORMATSIZE];
|
||||
|
|
@ -6792,8 +6821,19 @@ answer_response(fetchctx_t *fctx) {
|
|||
want_chaining = ISC_TRUE;
|
||||
POST(want_chaining);
|
||||
aflag = DNS_RDATASETATTR_ANSWER;
|
||||
result = dname_target(rdataset, qname,
|
||||
nlabels, &fdname);
|
||||
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
|
||||
|
|
@ -6807,8 +6847,8 @@ answer_response(fetchctx_t *fctx) {
|
|||
else
|
||||
dnameset = rdataset;
|
||||
|
||||
dname = dns_fixedname_name(&fdname);
|
||||
if (!is_answertarget_allowed(view,
|
||||
if (!synthcname &&
|
||||
!is_answertarget_allowed(view,
|
||||
qname, rdataset->type,
|
||||
dname, &fctx->domain))
|
||||
{
|
||||
|
|
@ -6834,8 +6874,7 @@ answer_response(fetchctx_t *fctx) {
|
|||
* is a synthesised CNAME before the DNAME.
|
||||
*/
|
||||
if ((chaining == 0) ||
|
||||
(chaining == 1U &&
|
||||
namereln == dns_namereln_commonancestor))
|
||||
(chaining == 1U && synthcname))
|
||||
{
|
||||
/*
|
||||
* This data is "the" answer to
|
||||
|
|
@ -6846,9 +6885,12 @@ answer_response(fetchctx_t *fctx) {
|
|||
if (aflag == DNS_RDATASETATTR_ANSWER) {
|
||||
have_answer = ISC_TRUE;
|
||||
found_dname = ISC_TRUE;
|
||||
if (cname != NULL)
|
||||
if (cname != NULL &&
|
||||
synthcname)
|
||||
{
|
||||
cname->attributes &=
|
||||
~DNS_NAMEATTR_ANSWER;
|
||||
}
|
||||
name->attributes |=
|
||||
DNS_NAMEATTR_ANSWER;
|
||||
}
|
||||
|
|
@ -6866,19 +6908,24 @@ answer_response(fetchctx_t *fctx) {
|
|||
* DNAME chaining.
|
||||
*/
|
||||
if (dnameset != NULL) {
|
||||
/*
|
||||
* 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);
|
||||
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 |=
|
||||
|
|
|
|||
Loading…
Reference in a new issue