Fix multi messages AXFR with TSIG
TSIG sign for multi messages AXFR was using the wrong dnspython signing function which does not support sequence messages in response which cause the AXFR error below WARNING -- Some TSIG could not be validated Change-Id: I7ce84ac9cf5bc5f6fca47dc79c51fe0becf96ac6 Closes-Bug: 1886685
This commit is contained in:

committed by
Erik Olof Gunnar Andersson

parent
45cb4376a2
commit
1fa892ea5a
@@ -239,6 +239,10 @@ class RequestHandler(xfr.XFRMixin):
|
||||
records.insert(0, soa_records[0])
|
||||
records.append(soa_records[0])
|
||||
|
||||
# Handle multi message response with tsig
|
||||
multi_messages = False
|
||||
multi_messages_context = None
|
||||
|
||||
# Render the results, yielding a packet after each TooBig exception.
|
||||
renderer = None
|
||||
while records:
|
||||
@@ -260,6 +264,9 @@ class RequestHandler(xfr.XFRMixin):
|
||||
renderer.add_rrset(dns.renderer.ANSWER, rrset)
|
||||
break
|
||||
except dns.exception.TooBig:
|
||||
# The response will span multiple messages since one
|
||||
# message is not enough
|
||||
multi_messages = True
|
||||
if renderer.counts[dns.renderer.ANSWER] == 0:
|
||||
# We've received a TooBig from the first attempted
|
||||
# RRSet in this packet. Log a warning and abort the
|
||||
@@ -280,11 +287,16 @@ class RequestHandler(xfr.XFRMixin):
|
||||
)
|
||||
return
|
||||
|
||||
yield self._finalize_packet(renderer, request)
|
||||
renderer, multi_messages_context = self._finalize_packet(
|
||||
renderer, request, multi_messages,
|
||||
multi_messages_context)
|
||||
yield renderer
|
||||
renderer = None
|
||||
|
||||
if renderer:
|
||||
yield self._finalize_packet(renderer, request)
|
||||
renderer, multi_messages_context = self._finalize_packet(
|
||||
renderer, request, multi_messages, multi_messages_context)
|
||||
yield renderer
|
||||
return
|
||||
|
||||
def _handle_record_query(self, request):
|
||||
@@ -396,22 +408,26 @@ class RequestHandler(xfr.XFRMixin):
|
||||
recordset.name, ttl, dns.rdataclass.IN, recordset.type, rdata)
|
||||
|
||||
@staticmethod
|
||||
def _finalize_packet(renderer, request):
|
||||
def _finalize_packet(renderer, request, multi_messages=False,
|
||||
multi_messages_context=None):
|
||||
renderer.write_header()
|
||||
if request.had_tsig:
|
||||
# Make the space we reserved for TSIG available for use
|
||||
renderer.max_size += TSIG_RRSIZE
|
||||
renderer.add_tsig(
|
||||
request.keyname,
|
||||
request.keyring[request.keyname],
|
||||
request.fudge,
|
||||
request.original_id,
|
||||
request.tsig_error,
|
||||
request.other_data,
|
||||
request.mac,
|
||||
request.keyalgorithm
|
||||
)
|
||||
return renderer
|
||||
if multi_messages:
|
||||
# The first message context will be None then the
|
||||
# context for the prev message is used for the next
|
||||
multi_messages_context = renderer.add_multi_tsig(
|
||||
multi_messages_context, request.keyname,
|
||||
request.keyring[request.keyname], request.fudge,
|
||||
request.original_id, request.tsig_error,
|
||||
request.other_data, request.mac, request.keyalgorithm)
|
||||
else:
|
||||
renderer.add_tsig(request.keyname,
|
||||
request.keyring[request.keyname], request.fudge,
|
||||
request.original_id, request.tsig_error,
|
||||
request.other_data, request.mac, request.keyalgorithm)
|
||||
return renderer, multi_messages_context
|
||||
|
||||
@staticmethod
|
||||
def _get_max_message_size(had_tsig):
|
||||
|
@@ -642,6 +642,84 @@ class MdnsRequestHandlerTest(MdnsTestCase):
|
||||
self.assertEqual(
|
||||
expected_response[1], binascii.b2a_hex(response_two))
|
||||
|
||||
@mock.patch.object(dns.renderer.Renderer, 'add_multi_tsig')
|
||||
def test_dispatch_opcode_query_AXFR_multiple_messages_with_tsig(self,
|
||||
mock_multi_tsig):
|
||||
# Query is for example.com. IN AXFR
|
||||
# id 18883
|
||||
# opcode QUERY
|
||||
# rcode NOERROR
|
||||
# flags AD
|
||||
# edns 0
|
||||
# payload 4096
|
||||
# ;QUESTION
|
||||
# example.com. IN AXFR
|
||||
# ;ANSWER
|
||||
# ;AUTHORITY
|
||||
# ;ADDITIONAL
|
||||
payload = ("49c300200001000000000001076578616d706c6503636f6d0000fc0001"
|
||||
"0000291000000000000000")
|
||||
|
||||
expected_response = [
|
||||
(b"49c384000001000300000000076578616d706c6503636f6d0000fc0001c00c"
|
||||
b"0006000100000e10002f036e7331076578616d706c65036f726700076578616"
|
||||
b"d706c65c00c551c063900000e10000002580001518000000e10c00c0002000"
|
||||
b"100000e100002c029046d61696cc00c0001000100000e100004c0000201"),
|
||||
|
||||
(b"49c384000001000100000000076578616d706c6503636f6d0000fc0001c00c"
|
||||
b"0006000100000e10002f036e7331076578616d706c65036f72670007657861"
|
||||
b"6d706c65c00c551c063900000e10000002580001518000000e10"),
|
||||
]
|
||||
|
||||
# Set the max-message-size to 363
|
||||
self.config(max_message_size=363, group='service:mdns')
|
||||
|
||||
zone = objects.Zone.from_dict({
|
||||
'name': 'example.com.',
|
||||
'ttl': 3600,
|
||||
'serial': 1427899961,
|
||||
'email': 'example@example.com',
|
||||
})
|
||||
|
||||
def _find_recordsets_axfr(context, criterion):
|
||||
if criterion['type'] == 'SOA':
|
||||
return [['UUID1', 'SOA', '3600', 'example.com.',
|
||||
'ns1.example.org. example.example.com. 1427899961 '
|
||||
'3600 600 86400 3600', 'ACTION']]
|
||||
|
||||
elif criterion['type'] == '!SOA':
|
||||
return [
|
||||
['UUID2', 'NS', '3600', 'example.com.', 'ns1.example.org.',
|
||||
'ACTION'],
|
||||
['UUID3', 'A', '3600', 'mail.example.com.', '192.0.2.1',
|
||||
'ACTION'],
|
||||
]
|
||||
|
||||
with mock.patch.object(self.storage, 'find_zone',
|
||||
return_value=zone):
|
||||
with mock.patch.object(self.storage, 'find_recordsets_axfr',
|
||||
side_effect=_find_recordsets_axfr):
|
||||
request = dns.message.from_wire(binascii.a2b_hex(payload))
|
||||
request.environ = {'addr': self.addr, 'context': self.context}
|
||||
request.keyring = {request.keyname: ''}
|
||||
request.had_tsig = True
|
||||
args = [request.keyname, request.keyring[request.keyname],
|
||||
request.fudge, request.original_id, request.tsig_error,
|
||||
request.other_data, request.mac, request.keyalgorithm]
|
||||
response_generator = self.handler(request)
|
||||
# Validate the first response
|
||||
response_one = next(response_generator).get_wire()
|
||||
mock_multi_tsig.assert_called_with(None, *args)
|
||||
self.assertEqual(
|
||||
expected_response[0], binascii.b2a_hex(response_one))
|
||||
|
||||
# Validate the second response
|
||||
response_two = next(response_generator).get_wire()
|
||||
first_msg_ctx = mock_multi_tsig.return_value
|
||||
mock_multi_tsig.assert_called_with(first_msg_ctx, *args)
|
||||
self.assertEqual(
|
||||
expected_response[1], binascii.b2a_hex(response_two))
|
||||
|
||||
def test_dispatch_opcode_query_AXFR_rrset_over_max_size(self):
|
||||
# Query is for example.com. IN AXFR
|
||||
# id 18883
|
||||
|
Reference in New Issue
Block a user