Commit 2a2f47d3 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[2911] select initial request type based on config and SOA availability.

parent 60a17382
......@@ -3205,6 +3205,13 @@ class TestXfrinProcess(unittest.TestCase):
self.__published = []
# How many connections were created.
self.__created_connections = 0
# prepare for possible replacement
self.__orig_get_zone_soa = xfrin._get_zone_soa
xfrin._get_zone_soa = lambda x, y, z: begin_soa_rdata
def tearDown(self):
# restore original value
xfrin._get_zone_soa = self.__orig_get_zone_soa
def __get_connection(self, *args):
......@@ -3269,8 +3276,8 @@ class TestXfrinProcess(unittest.TestCase):
self.__rets = rets
published = rets[-1]
xfrin.process_xfrin(self, XfrinRecorder(), Name(""),
RRClass.IN, None, None, None, True, None,
request_ixfr, self.__get_connection)
True, None, request_ixfr, self.__get_connection)
self.assertEqual([], self.__rets)
self.assertEqual(transfers, self.__transfers)
# Create a connection for each attempt
......@@ -3333,6 +3340,35 @@ class TestXfrinProcess(unittest.TestCase):
def test_initial_request_type(self):
"""Check initial xfr reuqest type (AXFR or IXFR).
Varying the policy of use of IXFR and availability of current
zone SOA. We are only interested in the initial request type,
so won't check the xfr results.
for soa in [begin_soa_rdata, None]:
for request_ixfr in [ZoneInfo.REQUEST_IXFR_FIRST,
# set up our dummy _get_zone_soa()
xfrin._get_zone_soa = lambda x, y, z: soa
# Clear all counters
self.__transfers = []
self.__published = []
self.__created_connections = 0
# Determine the expected type
expected_type = RRType.IXFR
if (soa is None or
request_ixfr == ZoneInfo.REQUEST_IXFR_DISABLED):
expected_type = RRType.AXFR
# perform the test
self.__do_test([XFRIN_OK], [expected_type], request_ixfr)
class TestFormatting(unittest.TestCase):
# If the formatting functions are moved to a more general library
# (ticket #1379), these tests should be moved with them.
......@@ -31,6 +31,7 @@ from isc.config.ccsession import *
from isc.statistics import Counters
from isc.notify import notify_out
import isc.util.process
from isc.util.address_formatter import AddressFormatter
from isc.datasrc import DataSourceClient, ZoneFinder
from isc.xfrin.diff import Diff
......@@ -1077,7 +1078,8 @@ def _get_zone_soa(datasrc_client, zone_name, zone_class):
"""Retrieve the current SOA RR of the zone to be transferred.
This function is essentially private to the module, but will also
be called from tests; no one else should use this function directly.
be called (or tweaked) from tests; no one else should use this
function directly.
It will be used for various purposes in subsequent xfr protocol
processing. It is validly possible that the zone is currently
......@@ -1100,6 +1102,11 @@ def _get_zone_soa(datasrc_client, zone_name, zone_class):
We'll deprecate this API in a near future, too).
# datasrc_client should never be None in production case (only tests could
# specify None)
if datasrc_client is None:
return None
# get the zone finder. this must be SUCCESS (not even
# PARTIALMATCH) because we are specifying the zone origin name.
result, finder = datasrc_client.find_zone(zone_name)
......@@ -1125,6 +1132,29 @@ def _get_zone_soa(datasrc_client, zone_name, zone_class):
return None
return soa_rrset
def __get_initial_xfr_type(zone_soa, request_ixfr, zname, zclass, master_addr):
"""Determine the initial xfr request type.
This is a dedicated subroutine of __process_xfrin.
if zone_soa is None:
# This is a kind of special case, so we log it at info level., format_zone_str(zname, zclass),
return RRType.AXFR
if request_ixfr == ZoneInfo.REQUEST_IXFR_DISABLED:
format_zone_str(zname, zclass),
return RRType.AXFR
assert(request_ixfr == ZoneInfo.REQUEST_IXFR_FIRST or
request_ixfr == ZoneInfo.REQUEST_IXFR_ONLY)
format_zone_str(zname, zclass),
return RRType.IXFR
def __process_xfrin(server, zone_name, rrclass, db_file,
shutdown_event, master_addrinfo, check_soa, tsig_key,
request_ixfr, conn_class):
......@@ -1148,9 +1178,12 @@ def __process_xfrin(server, zone_name, rrclass, db_file,
datasrc_config = "{ \"database_file\": \"" + db_file + "\"}"
datasrc_client = DataSourceClient(datasrc_type, datasrc_config)
zone_soa = None
if datasrc_client is not None:
zone_soa = _get_zone_soa(datasrc_client, zone_name, rrclass)
# Get the current zone SOA (if available) and determine the initial
# reuqest type: AXFR or IXFR.
zone_soa = _get_zone_soa(datasrc_client, zone_name, rrclass)
request_type = __get_initial_xfr_type(zone_soa, request_ixfr,
zone_name, rrclass,
# Create a TCP connection for the XFR session and perform the
# operation.
......@@ -1162,10 +1195,6 @@ def __process_xfrin(server, zone_name, rrclass, db_file,
# attempt. In the case of connected but failed IXFR, we set it to true
# once again.
retry = True
if request_ixfr == ZoneInfo.REQUEST_IXFR_DISABLED:
request_type = RRType.AXFR
request_type = RRType.IXFR
while retry:
retry = False
conn = conn_class(sock_map, zone_name, rrclass, datasrc_client,
......@@ -80,6 +80,24 @@ is not equal to the requested SOA serial.
There was an error importing the python DNS module pydnspp. The most
likely cause is a PYTHONPATH problem.
% XFRIN_INITIAL_AXFR no SOA available for %1 yet, requesting AXFR of initial version from %2
On starting the zone transfer, it's detected that there is no SOA
record available for the zone. This is always the case for the very
first transfer or if the administrator has removed the locally copied
data by hand for some reason. In this case trying IXFR does not make
sense for the obvious reason, so AXFR will be used from the beginning,
regardless of the request_ixfr configuration (even if "only" is
% XFRIN_INITIAL_IXFR requesting IXFR for %1 from %2
IXFR will be used for the initial request type for the specified zone
transfer. It will fall back to AXFR if the initial request fails
(and unless specified not to do so by configuration).
% XFRIN_INITIAL_IXFR_DISABLED IXFR disabled for %1, requesting AXFR from %2
The use of IXFR is disabled by configuration for the specified zone,
so only AXFR will be tried.
% XFRIN_INVALID_ZONE_DATA zone %1 received from %2 is broken and unusable
The zone was received, but it failed sanity validation. The previous version
of zone (if any is available) will be used. Look for previous
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment