BIND 10 trac1372, updated. a24c6579ab039afd67ecb50a71b9fc8eabf9b6c7 [1372] added a test case for an impossible (buggy) case. also changed the behavior against impossible # of questions.
BIND 10 source code commits
bind10-changes at lists.isc.org
Sat Nov 19 07:14:35 UTC 2011
The branch, trac1372 has been updated
via a24c6579ab039afd67ecb50a71b9fc8eabf9b6c7 (commit)
via 3647e8ff9c194c1c0a576558f4f49ba4ff2614e7 (commit)
via c3d71baca757b39e13968369e0afb39dd4472eb8 (commit)
via a9040d4aba8e3c01a77236c81f07e2b06b300918 (commit)
via 35556de064c193779c3cd5e5b0fde583f4a8d598 (commit)
via c4f22c20ee19e1ffba43914671c059a434f4518c (commit)
via 12b72af07f5e06cf172b115b0acba3fbe3554467 (commit)
via ecd9c5fc4b3cf747e2b5a221504feac3adeb236e (commit)
via d3db538710b6547cc2e04127fb5fc9d2d5a181f9 (commit)
via 2ab2fd55d4a12d1469060a3657893121114e2e2f (commit)
via 2dd7ee33a13a07a00e22fbc81ecb8b19b57efa8f (commit)
from 5cea4cfbee9770f4299f5a701af89f7cbf977ef4 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit a24c6579ab039afd67ecb50a71b9fc8eabf9b6c7
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 23:13:13 2011 -0800
[1372] added a test case for an impossible (buggy) case. also changed
the behavior against impossible # of questions.
commit 3647e8ff9c194c1c0a576558f4f49ba4ff2614e7
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 22:59:24 2011 -0800
[1372] a small comment update
commit c3d71baca757b39e13968369e0afb39dd4472eb8
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 22:58:02 2011 -0800
[1372] added IXFR specific log messages
commit a9040d4aba8e3c01a77236c81f07e2b06b300918
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 21:11:11 2011 -0800
[1372] detect and reject multiple SOA in IXFR's authority section.
commit 35556de064c193779c3cd5e5b0fde583f4a8d598
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 21:03:53 2011 -0800
[1372] ignore SOA in IXFR's authority section with a different RR class
commit c4f22c20ee19e1ffba43914671c059a434f4518c
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 20:48:36 2011 -0800
[1372] check the owner name of SOA in IXFR's authority section against
the query (zone) name
commit 12b72af07f5e06cf172b115b0acba3fbe3554467
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 20:35:49 2011 -0800
[1372] cleanup: naming consistency
commit ecd9c5fc4b3cf747e2b5a221504feac3adeb236e
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 19:12:21 2011 -0800
[1372] added a higher level test for AXFR-style IXFR response with an actual
SQLite3 DB.
commit d3db538710b6547cc2e04127fb5fc9d2d5a181f9
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 18:38:42 2011 -0800
[1372] fixed an overlooked bug in #1333: needed to catch C++ exceptions in
DataSourceClient.get_journal_reader().
commit 2ab2fd55d4a12d1469060a3657893121114e2e2f
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 18:16:30 2011 -0800
[1372] (unrelated cleanup) omit trailing dot from the zone name in log msgs.
commit 2dd7ee33a13a07a00e22fbc81ecb8b19b57efa8f
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Fri Nov 18 18:12:18 2011 -0800
[1372] covered NotImplemented case
-----------------------------------------------------------------------
Summary of changes:
src/bin/xfrout/tests/testdata/test.sqlite3 | Bin 11264 -> 12288 bytes
src/bin/xfrout/tests/xfrout_test.py.in | 142 ++++++++++++++++----
src/bin/xfrout/xfrout.py.in | 73 +++++++---
src/bin/xfrout/xfrout_messages.mes | 31 +++++
src/lib/python/isc/datasrc/client_python.cc | 37 ++++--
src/lib/python/isc/datasrc/tests/datasrc_test.py | 9 ++
.../datasrc/tests/testdata/test.sqlite3.nodiffs | Bin 43008 -> 43008 bytes
7 files changed, 230 insertions(+), 62 deletions(-)
copy src/lib/{ => python/isc}/datasrc/tests/testdata/test.sqlite3.nodiffs (100%)
-----------------------------------------------------------------------
diff --git a/src/bin/xfrout/tests/testdata/test.sqlite3 b/src/bin/xfrout/tests/testdata/test.sqlite3
index af491f5..a203820 100644
Binary files a/src/bin/xfrout/tests/testdata/test.sqlite3 and b/src/bin/xfrout/tests/testdata/test.sqlite3 differ
diff --git a/src/bin/xfrout/tests/xfrout_test.py.in b/src/bin/xfrout/tests/xfrout_test.py.in
index 19c65cd..572b529 100644
--- a/src/bin/xfrout/tests/xfrout_test.py.in
+++ b/src/bin/xfrout/tests/xfrout_test.py.in
@@ -143,6 +143,8 @@ class MockDataSrcClient:
def get_journal_reader(self, zone_name, begin_serial, end_serial):
if zone_name == Name('notauth2.example.com'):
return isc.datasrc.ZoneJournalReader.NO_SUCH_ZONE, None
+ if zone_name == Name('nojournal.example.com'):
+ raise isc.datasrc.NotImplemented('journaling not supported')
if begin_serial == IXFR_NG_VERSION:
return isc.datasrc.ZoneJournalReader.NO_SUCH_VERSION, None
return isc.datasrc.ZoneJournalReader.SUCCESS, self
@@ -216,7 +218,8 @@ class TestXfroutSessionBase(unittest.TestCase):
return msg.get_tsig_record() is not None
def create_request_data(self, with_question=True, with_tsig=False,
- ixfr=None):
+ ixfr=None, qtype=None, zone_name=TEST_ZONE_NAME,
+ soa_class=TEST_RRCLASS, num_soa=1):
'''Create a commonly used XFR request data.
By default the request type is AXFR; if 'ixfr' is an integer,
@@ -224,6 +227,17 @@ class TestXfroutSessionBase(unittest.TestCase):
the value of the parameter will be included in the authority
section.
+ This method has various minor parameters only for creating bad
+ format requests for testing purposes:
+ qtype: the RR type of the question section. By default automatically
+ determined by the value of ixfr, but could be an invalid type
+ for testing.
+ zone_name: the query (zone) name. for IXFR, it's also used as
+ the owner name of the SOA in the authority section.
+ soa_class: IXFR only. The RR class of the SOA RR in the authority
+ section.
+ num_soa: IXFR only. The number of SOA RDATAs in the authority
+ section.
'''
msg = Message(Message.RENDER)
query_id = 0x1035
@@ -232,14 +246,14 @@ class TestXfroutSessionBase(unittest.TestCase):
msg.set_rcode(Rcode.NOERROR())
req_type = RRType.AXFR() if ixfr is None else RRType.IXFR()
if with_question:
- msg.add_question(Question(Name("example.com"), RRClass.IN(),
- req_type))
+ msg.add_question(Question(zone_name, RRClass.IN(),
+ req_type if qtype is None else qtype))
if req_type == RRType.IXFR():
- soa = RRset(Name('example.com'), RRClass.IN(), RRType.SOA(),
- RRTTL(0))
+ soa = RRset(zone_name, soa_class, RRType.SOA(), RRTTL(0))
# In the RDATA only the serial matters.
- soa.add_rdata(Rdata(RRType.SOA(), RRClass.IN(),
- 'm r ' + str(ixfr) + ' 1 1 1 1'))
+ for i in range(0, num_soa):
+ soa.add_rdata(Rdata(RRType.SOA(), soa_class,
+ 'm r ' + str(ixfr) + ' 1 1 1 1'))
msg.add_rrset(Message.SECTION_AUTHORITY, soa)
renderer = MessageRenderer()
@@ -303,7 +317,7 @@ class TestXfroutSession(TestXfroutSessionBase):
# set up a bogus request, which should result in FORMERR. (it only
# has to be something that is different from the previous case)
self.xfrsess._request_data = \
- self.create_request_data(with_question=False)
+ self.create_request_data(ixfr=IXFR_OK_VERSION, num_soa=2)
# Replace the data source client to avoid datasrc related exceptions
self.xfrsess.ClientClass = MockDataSrcClient
XfroutSession._handle(self.xfrsess)
@@ -334,9 +348,12 @@ class TestXfroutSession(TestXfroutSessionBase):
self.assertEqual(Rcode.NOERROR(), rcode)
# Broken request: no question
- request_data = self.create_request_data(with_question=False)
- rcode, msg = self.xfrsess._parse_query_message(request_data)
- self.assertEqual(Rcode.FORMERR(), rcode)
+ self.assertRaises(RuntimeError, self.xfrsess._parse_query_message,
+ self.create_request_data(with_question=False))
+
+ # Broken request: invalid RR type (neither AXFR nor IXFR)
+ self.assertRaises(RuntimeError, self.xfrsess._parse_query_message,
+ self.create_request_data(qtype=RRType.A()))
# tsig signed query message
request_data = self.create_request_data(with_tsig=True)
@@ -680,16 +697,19 @@ class TestXfroutSession(TestXfroutSessionBase):
self.xfrsess.ClientClass = MockDataSrcClient
# Successful case. A zone iterator should be set up.
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), Name('example.com')), Rcode.NOERROR())
+ self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
self.assertNotEqual(None, self.xfrsess._iterator)
# Failure cases
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), Name('notauth.example.com')), Rcode.NOTAUTH())
+ self.getmsg(), Name('notauth.example.com'), TEST_RRCLASS),
+ Rcode.NOTAUTH())
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), Name('nosoa.example.com')), Rcode.SERVFAIL())
+ self.getmsg(), Name('nosoa.example.com'), TEST_RRCLASS),
+ Rcode.SERVFAIL())
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), Name('multisoa.example.com')), Rcode.SERVFAIL())
+ self.getmsg(), Name('multisoa.example.com'), TEST_RRCLASS),
+ Rcode.SERVFAIL())
def test_xfrout_ixfr_setup(self):
self.xfrsess.ClientClass = MockDataSrcClient
@@ -699,28 +719,66 @@ class TestXfroutSession(TestXfroutSessionBase):
# up.
self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), TEST_ZONE_NAME), Rcode.NOERROR())
+ self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
self.assertNotEqual(None, self.xfrsess._jnl_reader)
# Successful case, but as a result of falling back to AXFR-style
# IXFR. A zone iterator should be set up instead of a journal reader.
self.mdata = self.create_request_data(ixfr=IXFR_NG_VERSION)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), TEST_ZONE_NAME), Rcode.NOERROR())
+ self.getmsg(), TEST_ZONE_NAME, TEST_RRCLASS), Rcode.NOERROR())
self.assertNotEqual(None, self.xfrsess._iterator)
self.assertEqual(None, self.xfrsess._jnl_reader)
+ # The data source doesn't support journaling. Should fallback to AXFR.
+ zone_name = Name('nojournal.example.com')
+ self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
+ zone_name=zone_name)
+ self.assertEqual(self.xfrsess._xfrout_setup(
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOERROR())
+ self.assertNotEqual(None, self.xfrsess._iterator)
+
# Failure cases
+ zone_name = Name('notauth.example.com')
+ self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
+ zone_name=zone_name)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), Name('notauth.example.com')), Rcode.NOTAUTH())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH())
# this is a strange case: zone's SOA will be found but the journal
# reader won't be created due to 'no such zone'.
+ zone_name = Name('notauth2.example.com')
+ self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
+ zone_name=zone_name)
+ self.assertEqual(self.xfrsess._xfrout_setup(
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.NOTAUTH())
+ zone_name = Name('nosoa.example.com')
+ self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
+ zone_name=zone_name)
+ self.assertEqual(self.xfrsess._xfrout_setup(
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL())
+ zone_name = Name('multisoa.example.com')
+ self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
+ zone_name=zone_name)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), Name('notauth2.example.com')), Rcode.NOTAUTH())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.SERVFAIL())
+
+ # query name doesn't match the SOA's owner
+ self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION)
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), Name('nosoa.example.com')), Rcode.SERVFAIL())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
+
+ # query's RR class doesn't match the SOA's class
+ zone_name = TEST_ZONE_NAME # make sure the name matches this time
+ self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
+ soa_class=RRClass.CH())
self.assertEqual(self.xfrsess._xfrout_setup(
- self.getmsg(), Name('multisoa.example.com')), Rcode.SERVFAIL())
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
+
+ # multiple SOA RRs
+ self.mdata = self.create_request_data(ixfr=IXFR_OK_VERSION,
+ num_soa=2)
+ self.assertEqual(self.xfrsess._xfrout_setup(
+ self.getmsg(), zone_name, TEST_RRCLASS), Rcode.FORMERR())
def test_dns_xfrout_start_formerror(self):
# formerror
@@ -732,7 +790,7 @@ class TestXfroutSession(TestXfroutSessionBase):
return "example.com"
def test_dns_xfrout_start_notauth(self):
- def notauth(msg, name):
+ def notauth(msg, name, rrclass):
return Rcode.NOTAUTH()
self.xfrsess._xfrout_setup = notauth
self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
@@ -747,7 +805,7 @@ class TestXfroutSession(TestXfroutSessionBase):
self.assertEqual(self.sock.read_msg().get_rcode(), Rcode.SERVFAIL())
def test_dns_xfrout_start_noerror(self):
- def noerror(msg, name):
+ def noerror(msg, name, rrclass):
return Rcode.NOERROR()
self.xfrsess._xfrout_setup = noerror
@@ -808,19 +866,47 @@ class TestXfroutSessionWithSQLite3(TestXfroutSessionBase):
self.xfrsess._server.get_db_file = lambda : TESTDATA_SRCDIR + \
'test.sqlite3'
- def test_axfr_normal_session(self):
- XfroutSession._handle(self.xfrsess)
- response = self.sock.read_msg(Message.PRESERVE_ORDER);
- self.assertEqual(Rcode.NOERROR(), response.get_rcode())
+ def check_axfr_stream(self, response):
+ '''Common checks for AXFR(-style) response for the test zone.
+ '''
# This zone contains two A RRs for the same name with different TTLs.
# These TTLs should be preseved in the AXFR stream.
+ # We'll check some important points as a valid AXFR response:
+ # the first and last RR must be SOA, and these should be the only
+ # SOAs in the response. The total number of response RRs
+ # must be 5 (zone has 4 RRs, SOA is duplicated)
+ actual_records = response.get_section(Message.SECTION_ANSWER)
+ self.assertEqual(5, len(actual_records))
+ self.assertEqual(RRType.SOA(), actual_records[0].get_type())
+ self.assertEqual(RRType.SOA(), actual_records[-1].get_type())
actual_ttls = []
- for rr in response.get_section(Message.SECTION_ANSWER):
+ num_soa = 0
+ for rr in actual_records:
+ if rr.get_type() == RRType.SOA():
+ num_soa += 1
if rr.get_type() == RRType.A() and \
not rr.get_ttl() in actual_ttls:
actual_ttls.append(rr.get_ttl().get_value())
+ self.assertEqual(2, num_soa)
self.assertEqual([3600, 7200], sorted(actual_ttls))
+ def test_axfr_normal_session(self):
+ XfroutSession._handle(self.xfrsess)
+ response = self.sock.read_msg(Message.PRESERVE_ORDER);
+ self.assertEqual(Rcode.NOERROR(), response.get_rcode())
+ self.check_axfr_stream(response)
+
+ def test_ixfr_to_axfr(self):
+ self.xfrsess._request_data = \
+ self.create_request_data(ixfr=IXFR_NG_VERSION)
+ XfroutSession._handle(self.xfrsess)
+ response = self.sock.read_msg(Message.PRESERVE_ORDER);
+ self.assertEqual(Rcode.NOERROR(), response.get_rcode())
+ # This is an AXFR-style IXFR. So the question section should indicate
+ # that it's an IXFR resposne.
+ self.assertEqual(RRType.IXFR(), response.get_question()[0].get_type())
+ self.check_axfr_stream(response)
+
class MyUnixSockServer(UnixSockServer):
def __init__(self):
self._shutdown_event = threading.Event()
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index 1b6c317..fd60a57 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -102,7 +102,7 @@ def format_zone_str(zone_name, zone_class):
zone_name (isc.dns.Name) name to format
zone_class (isc.dns.RRClass) class to format
"""
- return zone_name.to_text() + '/' + str(zone_class)
+ return zone_name.to_text(True) + '/' + str(zone_class)
# borrowed from xfrin.py @ #1298.
def format_addrinfo(addrinfo):
@@ -201,7 +201,8 @@ class XfroutSession():
tsig_record = msg.get_tsig_record()
if tsig_record is not None:
self._tsig_len = tsig_record.get_length()
- self._tsig_ctx = self.create_tsig_ctx(tsig_record, self._tsig_key_ring)
+ self._tsig_ctx = self.create_tsig_ctx(tsig_record,
+ self._tsig_key_ring)
tsig_error = self._tsig_ctx.verify(tsig_record, request_data)
if tsig_error != TSIGError.NOERROR:
return Rcode.NOTAUTH()
@@ -224,10 +225,12 @@ class XfroutSession():
return rcode, msg
# Make sure the question is valid. This should be ensured by
- # the auth server, but since it's far from our xfrout itself,
- # we check it by ourselves.
+ # the auth server, but since it's far from xfrout itself, we check
+ # it by ourselves. A viloation would be an internal bug, so we
+ # raise and stop here rather than returning a FORMERR or SERVFAIL.
if msg.get_rr_count(Message.SECTION_QUESTION) != 1:
- return Rcode.FORMERR(), msg
+ raise RuntimeError('Invalid number of question for XFR: ' +
+ str(msg.get_rr_count(Message.SECTION_QUESTION)))
question = msg.get_question()[0]
# Identify the request type
@@ -237,9 +240,9 @@ class XfroutSession():
elif self._request_type == RRType.IXFR():
self._request_typestr = 'IXFR'
else:
- # Likewise, this should be impossible. (TBD: to be tested)
- raise RuntimeError('Unexpected XFR type: ' + \
- str(self._request_type))
+ # Likewise, this should be impossible.
+ raise RuntimeError('Unexpected XFR type: ' +
+ str(self._request_type))
# ACL checks
zone_name = question.get_name()
@@ -336,7 +339,7 @@ class XfroutSession():
return (Rcode.SERVFAIL(), None)
return (Rcode.NOERROR(), soa_rrset)
- def __setup_axfr(self, zone_name):
+ def __axfr_setup(self, zone_name):
'''Setup a zone iterator for AXFR or AXFR-style IXFR.
'''
@@ -364,7 +367,7 @@ class XfroutSession():
return Rcode.NOERROR()
- def __setup_ixfr(self, request_msg, zone_name):
+ def __ixfr_setup(self, request_msg, zone_name, zone_class):
'''Setup a zone journal reader for IXFR.
If the underlying data source does not know the requested range
@@ -372,31 +375,58 @@ class XfroutSession():
IXFR by setting up a zone iterator instead of a journal reader.
'''
- # TODO: more error case handling
+ # Check the authority section. Look for a SOA record with
+ # the same name and class as the question.
remote_soa = None
for auth_rrset in request_msg.get_section(Message.SECTION_AUTHORITY):
- if auth_rrset.get_type() != RRType.SOA():
+ # Ignore data whose owner name is not the zone apex, and
+ # ignore non-SOA or different class of records.
+ if auth_rrset.get_name() != zone_name or \
+ auth_rrset.get_type() != RRType.SOA() or \
+ auth_rrset.get_class() != zone_class:
continue
+ if auth_rrset.get_rdata_count() != 1:
+ logger.info(XFROUT_IXFR_MULTIPLE_SOA,
+ format_addrinfo(self._remote))
+ return Rcode.FORMERR()
remote_soa = auth_rrset
+ if remote_soa is None:
+ logger.info(XFROUT_IXFR_NO_SOA, format_addrinfo(self._remote))
+ return Rcode.FORMERR()
+
+ # Retrieve the local SOA
rcode, self._soa = self._get_zone_soa(zone_name)
if rcode != Rcode.NOERROR():
return rcode
- code, self._jnl_reader = self._datasrc_client.get_journal_reader(
- zone_name, get_soa_serial(remote_soa.get_rdata()[0]),
- get_soa_serial(self._soa.get_rdata()[0]))
+ try:
+ begin_serial = get_soa_serial(remote_soa.get_rdata()[0])
+ end_serial = get_soa_serial(self._soa.get_rdata()[0])
+ code, self._jnl_reader = self._datasrc_client.get_journal_reader(
+ zone_name, begin_serial, end_serial)
+ except isc.datasrc.NotImplemented as ex:
+ # The underlying data source doesn't support journaling.
+ # Fall back to AXFR-style IXFR.
+ logger.info(XFROUT_IXFR_NO_JOURNAL_SUPPORT,
+ format_addrinfo(self._remote),
+ format_zone_str(zone_name, zone_class))
+ return self.__axfr_setup(zone_name)
if code == ZoneJournalReader.NO_SUCH_VERSION:
- # fallback to AXFR-style IXFR
- return self.__setup_axfr(zone_name)
+ logger.info(XFROUT_IXFR_NO_VERSION, format_addrinfo(self._remote),
+ format_zone_str(zone_name, zone_class),
+ begin_serial, end_serial)
+ return self.__axfr_setup(zone_name)
if code == ZoneJournalReader.NO_SUCH_ZONE:
# this is quite unexpected as we know zone's SOA exists.
# It might be a bug or the data source is somehow broken,
# but it can still happen if someone has removed the zone
# between these two operations. We treat it as NOTAUTH.
+ logger.warn(XFROUT_IXFR_NO_ZONE, format_addrinfo(self._remote),
+ format_zone_str(zone_name, zone_class))
return Rcode.NOTAUTH()
return Rcode.NOERROR()
- def _xfrout_setup(self, request_msg, zone_name):
+ def _xfrout_setup(self, request_msg, zone_name, zone_class):
'''Setup a context for xfr responses according to the request type.
This method identifies the most appropriate data source for the
@@ -418,9 +448,9 @@ class XfroutSession():
self._datasrc_client = self.ClientClass('sqlite3', datasrc_config)
if self._request_type == RRType.AXFR():
- return self.__setup_axfr(zone_name)
+ return self.__axfr_setup(zone_name)
else:
- return self.__setup_ixfr(request_msg, zone_name)
+ return self.__ixfr_setup(request_msg, zone_name, zone_class)
def dns_xfrout_start(self, sock_fd, msg_query, quota_ok=True):
rcode_, msg = self._parse_query_message(msg_query)
@@ -444,9 +474,8 @@ class XfroutSession():
zone_class = question.get_class()
zone_str = format_zone_str(zone_name, zone_class) # for logging
- # TODO: we should also include class in the check
try:
- rcode_ = self._xfrout_setup(msg, zone_name)
+ rcode_ = self._xfrout_setup(msg, zone_name, zone_class)
except Exception as ex:
logger.error(XFROUT_XFR_TRANSFER_CHECK_ERROR, self._request_typestr,
format_addrinfo(self._remote), zone_str, ex)
diff --git a/src/bin/xfrout/xfrout_messages.mes b/src/bin/xfrout/xfrout_messages.mes
index 894ade5..ac7487a 100644
--- a/src/bin/xfrout/xfrout_messages.mes
+++ b/src/bin/xfrout/xfrout_messages.mes
@@ -178,3 +178,34 @@ on, but the file is in use. The most likely cause is that another
xfrout daemon process is still running. This xfrout daemon (the one
printing this message) will not start.
+% XFROUT_IXFR_MULTIPLE_SOA IXFR client %1: authority section has multiple SOAs
+An IXFR request was received with more than one SOA RRs in the authority
+section. The xfrout daemon rejects the request with an RCODE of
+FORMERR.
+
+% XFROUT_IXFR_NO_SOA IXFR client %1: missing SOA
+An IXFR request was received with no SOA RR in the authority section.
+The xfrout daemon rejects the request with an RCODE of FORMERR.
+
+% XFROUT_IXFR_NO_JOURNAL_SUPPORT IXFR client %1, %2: journaling not supported in the data source, falling back to AXFR
+An IXFR request was received but the underlying data source did
+not support journaling. The xfrout daemon fell back to AXFR-style
+IXFR.
+
+% XFROUT_IXFR_NO_VERSION IXFR client %1, %2: version (%3 to %4) not in journal, falling back to AXFR
+An IXFR request was received, but the requested range of differences
+were not found in the data source. The xfrout daemon fell back to
+AXFR-style IXFR.
+
+% XFROUT_IXFR_NO_ZONE IXFR client %1, %2: zone not found with journal
+The requested zone in IXFR was not found in the data source
+even though the xfrout daemon sucessfully found the SOA RR of the zone
+in the data source. This can happen if the administrator removed the
+zone from the data source within the small duration between these
+operations, but it's more likely to be a bug or broken data source.
+Unless you know why this message was logged, and especially if it
+happens often, it's advisable to check whether the data source is
+valid for this zone. The xfrout daemon considers it a possible,
+though unlikely, event, and returns a response with an RCODE of
+NOTAUTH.
+
diff --git a/src/lib/python/isc/datasrc/client_python.cc b/src/lib/python/isc/datasrc/client_python.cc
index dd7cbed..6636a92 100644
--- a/src/lib/python/isc/datasrc/client_python.cc
+++ b/src/lib/python/isc/datasrc/client_python.cc
@@ -182,19 +182,32 @@ DataSourceClient_getJournalReader(PyObject* po_self, PyObject* args) {
if (PyArg_ParseTuple(args, "O!kk", &name_type, &name_obj,
&begin_obj, &end_obj)) {
- pair<ZoneJournalReader::Result, ZoneJournalReaderPtr> result =
- self->cppobj->getInstance().getJournalReader(
- PyName_ToName(name_obj), static_cast<uint32_t>(begin_obj),
- static_cast<uint32_t>(end_obj));
- PyObject* po_reader;
- if (result.first == ZoneJournalReader::SUCCESS) {
- po_reader = createZoneJournalReaderObject(result.second, po_self);
- } else {
- po_reader = Py_None;
- Py_INCREF(po_reader); // this will soon be released
+ try {
+ pair<ZoneJournalReader::Result, ZoneJournalReaderPtr> result =
+ self->cppobj->getInstance().getJournalReader(
+ PyName_ToName(name_obj), static_cast<uint32_t>(begin_obj),
+ static_cast<uint32_t>(end_obj));
+ PyObject* po_reader;
+ if (result.first == ZoneJournalReader::SUCCESS) {
+ po_reader = createZoneJournalReaderObject(result.second,
+ po_self);
+ } else {
+ po_reader = Py_None;
+ Py_INCREF(po_reader); // this will soon be released
+ }
+ PyObjectContainer container(po_reader);
+ return (Py_BuildValue("(iO)", result.first, container.get()));
+ } catch (const isc::NotImplemented& ex) {
+ PyErr_SetString(getDataSourceException("NotImplemented"),
+ ex.what());
+ } catch (const DataSourceError& ex) {
+ PyErr_SetString(getDataSourceException("Error"), ex.what());
+ } catch (const std::exception& ex) {
+ PyErr_SetString(getDataSourceException("Error"), ex.what());
+ } catch (...) {
+ PyErr_SetString(getDataSourceException("Error"),
+ "Unexpected exception");
}
- PyObjectContainer container(po_reader);
- return (Py_BuildValue("(iO)", result.first, container.get()));
}
return (NULL);
}
diff --git a/src/lib/python/isc/datasrc/tests/datasrc_test.py b/src/lib/python/isc/datasrc/tests/datasrc_test.py
index 6c969c2..45bc8c1 100644
--- a/src/lib/python/isc/datasrc/tests/datasrc_test.py
+++ b/src/lib/python/isc/datasrc/tests/datasrc_test.py
@@ -783,6 +783,15 @@ class JournalRead(unittest.TestCase):
# ZoneJournalReader can only be constructed via a factory
self.assertRaises(TypeError, ZoneJournalReader)
+ def test_journal_reader_old_schema(self):
+ # The database doesn't have a "diffs" table.
+ dbfile = TESTDATA_PATH + 'test.sqlite3.nodiffs'
+ client = isc.datasrc.DataSourceClient("sqlite3",
+ "{ \"database_file\": \"" + \
+ dbfile + "\" }")
+ self.assertRaises(isc.datasrc.Error, client.get_journal_reader,
+ self.zname, 0, 1)
+
if __name__ == "__main__":
isc.log.init("bind10")
isc.log.resetUnitTestRootLogger()
diff --git a/src/lib/python/isc/datasrc/tests/testdata/test.sqlite3.nodiffs b/src/lib/python/isc/datasrc/tests/testdata/test.sqlite3.nodiffs
new file mode 100644
index 0000000..cc8cfc3
Binary files /dev/null and b/src/lib/python/isc/datasrc/tests/testdata/test.sqlite3.nodiffs differ
More information about the bind10-changes
mailing list