Merge branch '4372-assertion-failure-in-dispatch-c' into 'main'

Resolve "Assertion failure in dispatch.c"

Closes #4372

See merge request isc-projects/bind9!8397
This commit is contained in:
Mark Andrews 2023-10-20 09:26:07 +00:00
commit 45f088fea7
8 changed files with 164 additions and 10 deletions

View file

@ -81,7 +81,10 @@ Files: **/*.after*
bin/tests/system/unknown/large.out
bin/tests/system/xfer/ans5/badkeydata
bin/tests/system/xfer/ans5/badmessageid
bin/tests/system/xfer/ans5/ednsformerr
bin/tests/system/xfer/ans5/ednsnotimp
bin/tests/system/xfer/ans5/goodaxfr
bin/tests/system/xfer/ans5/ixfrnotimp
bin/tests/system/xfer/ans5/partial
bin/tests/system/xfer/ans5/soamismatch
bin/tests/system/xfer/ans5/unknownkey

View file

@ -1,3 +1,7 @@
6270. [bug] Handle an assertion when the primary server returned
NOTIMP to IXFR or FORMERR to EDNS to SOA/IXFR/AXFR
request when transfering a zone. [GL #4372]
6269. [maint] B.ROOT-SERVERS.NET addresses are now 170.247.170.2 and
2801:1b8:10::b. [GL #4101]

View file

@ -65,6 +65,21 @@
# pattern, only this data will be signed. Currently, this is only
# done for TCP.
#
# /pattern NOTIMP <key> <key_data>/
# /pattern NOTIMP/
#
# Return a NOTIMP response
#
# /pattern EDNS=NOTIMP <key> <key_data>/
# /pattern EDNS=NOTIMP/
#
# Return a NOTIMP response to an EDNS request
#
# /pattern EDNS=FORMERR <key> <key_data>/
# /pattern EDNS=FORMERR/
#
# Return a FORMERR response to an EDNS request
#
# /pattern bad-id <key> <key_data>/
# /pattern bad-id/
#
@ -345,6 +360,11 @@ sub handleTCP {
my $qtype = $questions[0]->qtype;
my $qclass = $questions[0]->qclass;
my $id = $request->header->id;
my @additional = $request->additional;
my $has_opt = 0;
foreach (@additional) {
$has_opt = 1 if (ref($_) eq 'Net::DNS::RR::OPT');
}
my $opaque;
@ -376,14 +396,50 @@ sub handleTCP {
if ("$qname $qtype" =~ /$dbtype/) {
$count_these++;
my $a;
foreach $a (@{$r->{answer}}) {
$packet->push("answer", $a);
my $done = 0;
while (defined($key_name) &&
($key_name eq "NOTIMP" || $key_name eq "EDNS=NOTIMP" ||
$key_name eq "EDNS=FORMERR" || $key_name eq "bad-id")) {
if (defined($key_name) && $key_name eq "NOTIMP") {
$packet->header->rcode('NOTIMP') if (!$done);
$key_name = $key_data;
($key_data, $tname) = split(/ /,$tname);
$done = 1;
}
if (defined($key_name) && $key_name eq "EDNS=NOTIMP") {
if ($has_opt) {
$packet->header->rcode('NOTIMP') if (!$done);
$done = 1;
}
$key_name = $key_data;
($key_data, $tname) = split(/ /,$tname);
}
if (defined($key_name) && $key_name eq "EDNS=FORMERR") {
if ($has_opt) {
$packet->header->rcode('FORMERR') if (!$done);
$done = 1;
}
$key_name = $key_data;
($key_data, $tname) = split(/ /,$tname);
}
if (defined($key_name) && $key_name eq "bad-id") {
$packet->header->id(($id+50)%0xffff);
$key_name = $key_data;
($key_data, $tname) = split(/ /,$tname);
}
}
if (defined($key_name) && $key_name eq "bad-id") {
$packet->header->id(($id+50)%0xffff);
$key_name = $key_data;
($key_data, $tname) = split(/ /,$tname)
if (!$done) {
foreach $a (@{$r->{answer}}) {
$packet->push("answer", $a);
}
}
if (defined($key_name) && defined($key_data)) {
my $tsig;
# sign the packet
@ -453,6 +509,7 @@ sub handleTCP {
}
#$packet->print;
push(@results,$packet->data);
last if ($done);
if ($tname eq "") {
$tname = $qname;
}

View file

@ -0,0 +1,10 @@
/SOA tsig_key LSAnCU+Z/
nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300
/AXFR EDNS=FORMERR tsig_key LSAnCU+Z/
nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300
/AXFR EDNS=FORMERR tsig_key LSAnCU+Z/
nil. 300 NS ns.nil.
nil. 300 TXT "EDNS FORMERR"
a.nil. 60 A 10.0.0.61
/AXFR EDNS=FORMERR tsig_key LSAnCU+Z/
nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300

View file

@ -0,0 +1,12 @@
/SOA tsig_key LSAnCU+Z/
nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300
/AXFR EDNS=NOTIMP tsig_key LSAnCU+Z/
nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300
/AXFR tsig_key LSAnCU+Z/
nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300
/AXFR tsig_key LSAnCU+Z/
nil. 300 NS ns.nil.
nil. 300 TXT "EDNS NOTIMP"
a.nil. 60 A 10.0.0.61
/AXFR tsig_key LSAnCU+Z/
nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300

View file

@ -0,0 +1,11 @@
/SOA tsig_key LSAnCU+Z/
nil. 300 SOA ns.nil. root.nil. 2 300 300 604800 300
/IXFR NOTIMP tsig_key LSAnCU+Z/
/AXFR tsig_key LSAnCU+Z/
nil. 300 SOA ns.nil. root.nil. 2 300 300 604800 300
/AXFR tsig_key LSAnCU+Z/
nil. 300 NS ns.nil.
nil. 300 TXT "IXFR NOTIMP"
a.nil. 60 A 10.0.0.61
/AXFR tsig_key LSAnCU+Z/
nil. 300 SOA ns.nil. root.nil. 2 300 300 604800 300

View file

@ -307,6 +307,25 @@ $DIGCMD nil. TXT | grep 'initial AXFR' >/dev/null || {
status=$((status+1))
}
n=$((n+1))
echo_i "handle IXFR NOTIMP ($n)"
sendcmd < ans5/ixfrnotimp
$RNDCCMD 10.53.0.4 refresh nil | sed 's/^/ns4 /' | cat_i
sleep 2
nextpart ns4/named.run | grep "zone nil/IN: requesting IXFR from 10.53.0.5" > /dev/null || {
echo_i "failed: expected status was not logged"
status=$((status+1))
}
$DIGCMD nil. TXT | grep 'IXFR NOTIMP' >/dev/null || {
echo_i "failed"
status=$((status+1))
}
n=$((n+1))
echo_i "unsigned transfer ($n)"
@ -463,6 +482,38 @@ $DIGCMD nil. TXT | grep 'SOA mismatch AXFR' >/dev/null && {
status=$((status+1))
}
n=$((n+1))
echo_i "handle EDNS NOTIMP ($n)"
$RNDCCMD 10.53.0.4 null testing EDNS NOTIMP | sed 's/^/ns4 /' | cat_i
sendcmd < ans5/ednsnotimp
$RNDCCMD 10.53.0.4 retransfer nil | sed 's/^/ns4 /' | cat_i
sleep 2
nextpart ns4/named.run | grep "Transfer status: NOTIMP" > /dev/null || {
echo_i "failed: expected status was not logged"
status=$((status+1))
}
n=$((n+1))
echo_i "handle EDNS FORMERR ($n)"
$RNDCCMD 10.53.0.4 null testing EDNS FORMERR | sed 's/^/ns4 /' | cat_i
sendcmd < ans5/ednsformerr
$RNDCCMD 10.53.0.4 retransfer nil | sed 's/^/ns4 /' | cat_i
sleep 10
$DIGCMD nil. TXT | grep 'EDNS FORMERR' >/dev/null || {
echo_i "failed"
status=$((status+1))
}
n=$((n+1))
echo_i "check that we ask for and got a EDNS EXPIRE response when transfering from a secondary ($n)"
tmp=0

View file

@ -1205,8 +1205,9 @@ xfrin_start(dns_xfrin_t *xfr) {
* do this because other connections could be using a different
* certificate, so we just create a new dispatch every time.
*/
if (xfr->transport == NULL ||
dns_transport_get_type(xfr->transport) == DNS_TRANSPORT_TCP)
if (xfr->disp == NULL &&
(xfr->transport == NULL ||
dns_transport_get_type(xfr->transport) == DNS_TRANSPORT_TCP))
{
dns_dispatchmgr_t *dispmgr = dns_view_getdispatchmgr(xfr->view);
if (dispmgr == NULL) {
@ -1223,7 +1224,7 @@ xfrin_start(dns_xfrin_t *xfr) {
isc_sockaddr_format(&xfr->primaryaddr, peer, sizeof(peer));
xfrin_log(xfr, ISC_LOG_DEBUG(1),
"attached to TCP connection to %s", peer);
} else {
} else if (xfr->disp == NULL) {
dns_dispatchmgr_t *dispmgr = dns_view_getdispatchmgr(xfr->view);
if (dispmgr == NULL) {
result = ISC_R_SHUTTINGDOWN;
@ -1236,6 +1237,11 @@ xfrin_start(dns_xfrin_t *xfr) {
CHECK(result);
}
/* If this is a retry, we need to cancel the previous dispentry */
if (xfr->dispentry != NULL) {
dns_dispatch_done(&xfr->dispentry);
}
LIBDNS_XFRIN_START(xfr, xfr->info);
/*
@ -1940,7 +1946,7 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) {
case XFRST_GOTSOA:
xfr->reqtype = dns_rdatatype_axfr;
atomic_store(&xfr->state, XFRST_ZONEXFRREQUEST);
CHECK(xfrin_send_request(xfr));
CHECK(xfrin_start(xfr));
break;
case XFRST_AXFR_END:
case XFRST_IXFR_END: