mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 05:09:59 -04:00
Test named reconfiguration during zone transfer's SOA request
This new test checks that named can correctly process an interrupted SOA request during zone transfer, caused by reconfiguration. Co-authored-by: Michał Kępień <michal@isc.org>
This commit is contained in:
parent
b07ec4f0b3
commit
aa6ca3e776
4 changed files with 162 additions and 0 deletions
111
bin/tests/system/xfer/ans9/ans.py
Normal file
111
bin/tests/system/xfer/ans9/ans.py
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
"""
|
||||
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
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 https://mozilla.org/MPL/2.0/.
|
||||
|
||||
See the COPYRIGHT file distributed with this work for additional
|
||||
information regarding copyright ownership.
|
||||
"""
|
||||
|
||||
from typing import AsyncGenerator
|
||||
|
||||
import dns.message
|
||||
import dns.rdataclass
|
||||
import dns.rdatatype
|
||||
import dns.rrset
|
||||
|
||||
from isctest.asyncserver import (
|
||||
ControllableAsyncDnsServer,
|
||||
DomainHandler,
|
||||
QueryContext,
|
||||
ResponseAction,
|
||||
DnsResponseSend,
|
||||
ToggleResponsesCommand,
|
||||
)
|
||||
|
||||
|
||||
class AXFRServer(DomainHandler):
|
||||
"""
|
||||
Yield SOA and AXFR responses. Every new AXFR response increments the SOA
|
||||
version.
|
||||
"""
|
||||
|
||||
domains = ["xfr-and-reconfig"]
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.soa_version = 0
|
||||
|
||||
async def get_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[ResponseAction, None]:
|
||||
# This is oversimplified because I am lazy - we are appending the SOA
|
||||
# RRset to the ANSWER section for _every_ QTYPE. named is only
|
||||
# expected to send a SOA query over UDP and then an AXFR query over
|
||||
# TCP. Responses to both of those start with a SOA RRset in the ANSWER
|
||||
# section :-)
|
||||
soa_message = dns.message.make_response(qctx.query)
|
||||
soa_rrset = dns.rrset.from_text(
|
||||
qctx.qname,
|
||||
300,
|
||||
dns.rdataclass.IN,
|
||||
dns.rdatatype.SOA,
|
||||
f". . {self.soa_version} 0 0 0 0",
|
||||
)
|
||||
soa_message.answer.append(soa_rrset)
|
||||
|
||||
yield DnsResponseSend(soa_message, authoritative=True)
|
||||
|
||||
if qctx.qtype == dns.rdatatype.SOA:
|
||||
# If QTYPE=SOA, the SOA record is the complete response.
|
||||
return
|
||||
|
||||
if qctx.qtype != dns.rdatatype.AXFR:
|
||||
# If QTYPE=AXFR, we will continue cramming RRsets into the ANSWER
|
||||
# section of a subsequent DNS message below.
|
||||
#
|
||||
# If QTYPE was not SOA or AXFR, abort. Yeah, we just sent a broken
|
||||
# response by yielding DnsResponseSend() with a SOA RRset in the
|
||||
# ANSWER section above. We will have to carry that burden for the
|
||||
# rest of our lives.
|
||||
return
|
||||
|
||||
# Send just the obligatory NS RRset at zone apex in the next message.
|
||||
# This is stupidly inefficient, but makes looping below simpler as we
|
||||
# will already have been done with the mandatory stuff by then.
|
||||
ns_message = dns.message.make_response(qctx.query)
|
||||
ns_rrset = dns.rrset.from_text(
|
||||
qctx.qname, 300, dns.rdataclass.IN, dns.rdatatype.NS, "."
|
||||
)
|
||||
ns_message.answer.append(ns_rrset)
|
||||
|
||||
yield DnsResponseSend(ns_message, authoritative=True)
|
||||
|
||||
# Generate the AXFR with a txt rrset.
|
||||
txt_message = dns.message.make_response(qctx.query)
|
||||
txt_rrset = dns.rrset.from_text(
|
||||
qctx.qname,
|
||||
300,
|
||||
dns.rdataclass.IN,
|
||||
dns.rdatatype.TXT,
|
||||
"foo bar",
|
||||
)
|
||||
txt_message.answer.append(txt_rrset)
|
||||
|
||||
yield DnsResponseSend(txt_message, authoritative=True)
|
||||
|
||||
# Finish the AXFR transaction by sending the second SOA RRset.
|
||||
yield DnsResponseSend(soa_message, authoritative=True)
|
||||
|
||||
# This makes sure that the next SOA request causes a new zone transfer
|
||||
self.soa_version += 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
server = ControllableAsyncDnsServer([ToggleResponsesCommand])
|
||||
server.install_response_handler(AXFRServer())
|
||||
server.run()
|
||||
|
|
@ -111,3 +111,10 @@ zone "ixfr-too-many-diffs" {
|
|||
primaries { 10.53.0.1; };
|
||||
file "ixfr-too-many-diffs.bk";
|
||||
};
|
||||
|
||||
zone "xfr-and-reconfig" {
|
||||
type secondary;
|
||||
primaries { 10.53.0.9; };
|
||||
file "xfr-and-reconfig.bk";
|
||||
request-ixfr no; # ans9 supports only axfr
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p ${PORT}"
|
|||
RNDCCMD="$RNDC -c ../_common/rndc.conf -p ${CONTROLPORT} -s"
|
||||
NS_PARAMS="-m record -c named.conf -d 99 -g -T maxcachesize=2097152"
|
||||
|
||||
dig_with_opts() (
|
||||
"$DIG" -p "$PORT" "$@"
|
||||
)
|
||||
|
||||
status=0
|
||||
n=0
|
||||
|
||||
|
|
@ -752,5 +756,44 @@ if [ $tmp -eq 0 ]; then
|
|||
fi
|
||||
status=$((status + tmp))
|
||||
|
||||
nextpart ns6/named.run >/dev/null
|
||||
|
||||
sendcmd() (
|
||||
dig_with_opts "@${1}" "${2}._control." TXT +time=5 +tries=1 +tcp >/dev/null 2>&1
|
||||
)
|
||||
|
||||
# See #5307#note_558185
|
||||
n=$((n + 1))
|
||||
echo_i "test reconfiguration when zone transfer is in the middle of a SOA query (part 1) ($n)"
|
||||
tmp=0
|
||||
# Check that xfr-and-reconfig has been successfully transferred by the secondary.
|
||||
grep -F 'zone xfr-and-reconfig/IN: zone transfer finished: success' ns6/named.run 2>&1 >/dev/null || tmp=0
|
||||
# Make ans6 receive queries without responding to them.
|
||||
sendcmd 10.53.0.9 "disable.send-responses"
|
||||
sleep 1
|
||||
# Try to reload the zone from an unresponsive primary.
|
||||
$RNDCCMD 10.53.0.6 reload xfr-and-reconfig 2>&1 | sed 's/^/ns6 /' | cat_i
|
||||
sleep 1
|
||||
# Reconfigure named while zone transfer attempt is in progress.
|
||||
$RNDCCMD 10.53.0.6 reconfig 2>&1 | sed 's/^/ns6 /' | cat_i
|
||||
# Confirm that the ongoing SOA request was canceled, caused by the reconfiguratoin.
|
||||
retry_quiet 60 wait_for_message "refresh: request result: shutting down" || tmp=1
|
||||
if test $tmp != 0; then echo_i "failed"; fi
|
||||
status=$((status + tmp))
|
||||
|
||||
nextpart ns6/named.run >/dev/null
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "test reconfiguration when zone transfer is in the middle of a SOA query (part 2) ($n)"
|
||||
tmp=0
|
||||
# Make ans6 receive queries and respond to them.
|
||||
sendcmd 10.53.0.9 "enable.send-responses"
|
||||
sleep 1
|
||||
# Try to reload the zone from the primary.
|
||||
$RNDCCMD 10.53.0.6 reload xfr-and-reconfig 2>&1 | sed 's/^/ns6 /' | cat_i
|
||||
retry_quiet 60 wait_for_message "zone xfr-and-reconfig/IN: Transfer started." || tmp=1
|
||||
if test $tmp != 0; then echo_i "failed"; fi
|
||||
status=$((status + tmp))
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ pytestmark = pytest.mark.extra_artifacts(
|
|||
"ns6/primary.db.jnl",
|
||||
"ns6/sec.bk",
|
||||
"ns6/xot-primary-try-next.bk",
|
||||
"ns6/xfr-and-reconfig.bk",
|
||||
"ns7/edns-expire.bk",
|
||||
"ns7/primary2.db",
|
||||
"ns7/sec.bk",
|
||||
|
|
|
|||
Loading…
Reference in a new issue