Commit 83769196 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[master] [1299] (not directly related fix): be sure to check the AA flag of SOA response

parent 4e636c3e
......@@ -36,11 +36,9 @@ TEST_RRCLASS_STR = 'IN'
TEST_DB_FILE = 'db_file'
TEST_MASTER_IPV4_ADDRESS = '127.0.0.1'
TEST_MASTER_IPV4_ADDRINFO = (socket.AF_INET, socket.SOCK_STREAM,
socket.IPPROTO_TCP, '',
(TEST_MASTER_IPV4_ADDRESS, 53))
TEST_MASTER_IPV6_ADDRESS = '::1'
TEST_MASTER_IPV6_ADDRINFO = (socket.AF_INET6, socket.SOCK_STREAM,
socket.IPPROTO_TCP, '',
(TEST_MASTER_IPV6_ADDRESS, 53))
TESTDATA_SRCDIR = os.getenv("TESTDATASRCDIR")
......@@ -274,7 +272,7 @@ class MockXfrinConnection(XfrinConnection):
self.response_generator()
return len(data)
def create_response_data(self, response=True, bad_qid=False,
def create_response_data(self, response=True, auth=True, bad_qid=False,
rcode=Rcode.NOERROR(),
questions=default_questions,
answers=default_answers,
......@@ -288,6 +286,8 @@ class MockXfrinConnection(XfrinConnection):
resp.set_rcode(rcode)
if response:
resp.set_header_flag(Message.HEADERFLAG_QR)
if auth:
resp.set_header_flag(Message.HEADERFLAG_AA)
[resp.add_question(q) for q in questions]
[resp.add_rrset(Message.SECTION_ANSWER, a) for a in answers]
......@@ -599,6 +599,7 @@ class TestXfrinConnection(unittest.TestCase):
'questions': [example_soa_question],
'bad_qid': False,
'response': True,
'auth': True,
'rcode': Rcode.NOERROR(),
'tsig': False,
'axfr_after_soa': self._create_normal_response_data
......@@ -656,6 +657,7 @@ class TestXfrinConnection(unittest.TestCase):
self.conn.reply_data = self.conn.create_response_data(
bad_qid=self.soa_response_params['bad_qid'],
response=self.soa_response_params['response'],
auth=self.soa_response_params['auth'],
rcode=self.soa_response_params['rcode'],
questions=self.soa_response_params['questions'],
tsig_ctx=verify_ctx)
......@@ -941,6 +943,11 @@ class TestAXFR(TestXfrinConnection):
self.conn.response_generator = self._create_soa_response_data
self.assertRaises(XfrinException, self.conn._check_soa_serial)
def test_soacheck_notauth(self):
self.soa_response_params['auth'] = False
self.conn.response_generator = self._create_soa_response_data
self.assertRaises(XfrinException, self.conn._check_soa_serial)
def test_soacheck_with_tsig(self):
# Use a mock tsig context emulating a validly signed response
self.conn._tsig_key = TSIG_KEY
......
......@@ -618,14 +618,19 @@ class XfrinConnection(asyncore.dispatcher):
msg.set_opcode(Opcode.QUERY())
msg.set_rcode(Rcode.NOERROR())
msg.add_question(Question(self._zone_name, self._rrclass, query_type))
# Remember our serial, if known
self._request_serial = get_soa_serial(self._zone_soa.get_rdata()[0]) \
if self._zone_soa is not None else None
# Set the authority section with our SOA for IXFR
if query_type == RRType.IXFR():
if self._zone_soa is None:
# (incremental) IXFR doesn't work without known SOA
raise XfrinException('Failed to create IXFR query due to no ' +
'SOA for ' + self.zone_str())
msg.add_rrset(Message.SECTION_AUTHORITY, self._zone_soa)
self._request_serial = \
get_soa_serial(self._zone_soa.get_rdata()[0])
return msg
def _send_data(self, data):
......@@ -707,9 +712,11 @@ class XfrinConnection(asyncore.dispatcher):
# TSIG related checks, including an unexpected signed response
self._check_response_tsig(msg, soa_response)
# perform some minimal level validation. It's an open issue how
# strict we should be (see the comment in _check_response_header())
# Validate the header. Unlike AXFR/IXFR, we should be more strict
# for SOA queries and check the AA flag, too.
self._check_response_header(msg)
if not msg.get_header_flag(Message.HEADERFLAG_AA):
raise XfrinException('non-authoritative answer to SOA query')
# TODO, need select soa record from data source then compare the two
# serial, current just return OK, since this function hasn't been used
......@@ -739,7 +746,8 @@ class XfrinConnection(asyncore.dispatcher):
except (XfrinException, XfrinProtocolError) as e:
logger.error(XFRIN_XFR_TRANSFER_FAILURE, request_str,
self.zone_str(), str(e))
self.zone_str(),
format_addrinfo(self._master_addrinfo), str(e))
ret = XFRIN_FAIL
except Exception as e:
# Catching all possible exceptions like this is generally not a
......@@ -828,8 +836,8 @@ class XfrinConnection(asyncore.dispatcher):
return False
def __process_xfrin(server, zone_name, rrclass, db_file,
shutdown_event, master_addrinfo, check_soa, tsig_key,
request_type, conn_class):
shutdown_event, master_addrinfo, check_soa, tsig_key,
request_type, conn_class):
conn = None
exception = None
ret = XFRIN_FAIL
......
......@@ -50,7 +50,7 @@ The XFR transfer for the given zone has failed due to a problem outside
of the xfrin module. Possible reasons are a broken DNS message or failure
in database connection. The error is shown in the log message.
% XFRIN_XFR_TRANSFER_FAILURE %1 transfer of zone %2 failed: %3
% XFRIN_XFR_TRANSFER_FAILURE %1 transfer of zone %2 with %3 failed: %4
The XFR transfer for the given zone has failed due to a protocol error.
The error is shown in the log message.
......
Markdown is supported
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