From 4cf00bfb7fed8da190361d74b86c783783e15d52 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Tue, 1 Dec 2015 13:25:58 +0000 Subject: [PATCH] Check TXT record length limit Change-Id: Ie423cb7037625d0cfaf4084bf8660790c45cd7c6 Closes-Bug: #1474012 --- designate/objects/rrdata_txt.py | 1 + designate/tests/__init__.py | 6 ++ .../tests/test_api/test_v1/test_records.py | 27 ++++++++ .../tests/test_api/test_v2/test_recordsets.py | 22 +++++++ designate/tests/test_mdns/test_handler.py | 65 +++++++++++++++++++ 5 files changed, 121 insertions(+) diff --git a/designate/objects/rrdata_txt.py b/designate/objects/rrdata_txt.py index 2cd9d7ceb..f9d1c19e6 100644 --- a/designate/objects/rrdata_txt.py +++ b/designate/objects/rrdata_txt.py @@ -25,6 +25,7 @@ class TXT(Record): 'txt_data': { 'schema': { 'type': 'string', + 'maxLength': 255, }, 'required': True } diff --git a/designate/tests/__init__.py b/designate/tests/__init__.py index 0c7b4feb6..1f6663d25 100644 --- a/designate/tests/__init__.py +++ b/designate/tests/__init__.py @@ -159,6 +159,9 @@ class TestCase(base.BaseTestCase): {'name': '_sip._tcp.%s', 'type': 'SRV'}, {'name': '_sip._udp.%s', 'type': 'SRV'}, ], + 'TXT': [ + {'name': 'text.%s', 'type': 'TXT'}, + ], 'CNAME': [ {'name': 'www.%s', 'type': 'CNAME'}, {'name': 'sub1.%s', 'type': 'CNAME'}, @@ -181,6 +184,9 @@ class TestCase(base.BaseTestCase): 'CNAME': [ {'data': 'www.somezone.org.'}, {'data': 'www.someotherzone.com.'}, + ], + 'TXT': [ + {'data': 'footxtdata'} ] } diff --git a/designate/tests/test_api/test_v1/test_records.py b/designate/tests/test_api/test_v1/test_records.py index db71d13f9..b5e911a96 100644 --- a/designate/tests/test_api/test_v1/test_records.py +++ b/designate/tests/test_api/test_v1/test_records.py @@ -832,3 +832,30 @@ class ApiV1RecordsTest(ApiV1Test): self.delete('domains/%s/records/%s' % (self.zone['id'], record['id']), status_code=404) + + +class ApiV1TxtRecordsTest(ApiV1Test): + def setUp(self): + super(ApiV1TxtRecordsTest, self).setUp() + + self.zone = self.create_zone() + self.recordset = self.create_recordset(self.zone, 'TXT') + + def test_create_txt_record(self): + # See bug #1474012 + record = self.create_record(self.zone, self.recordset) + data = {'data': 'a' * 255} + self.put( + 'domains/%s/records/%s' % (self.zone['id'], record['id']), + data=data + ) + + def test_create_txt_record_too_long(self): + # See bug #1474012 + record = self.create_record(self.zone, self.recordset) + data = {'data': 'a' * 256} + self.put( + 'domains/%s/records/%s' % (self.zone['id'], record['id']), + data=data, + status_code=400 + ) diff --git a/designate/tests/test_api/test_v2/test_recordsets.py b/designate/tests/test_api/test_v2/test_recordsets.py index 3ad6bb5aa..a80d82b91 100644 --- a/designate/tests/test_api/test_v2/test_recordsets.py +++ b/designate/tests/test_api/test_v2/test_recordsets.py @@ -545,6 +545,28 @@ class ApiV2RecordSetsTest(ApiV2TestCase): self.assertEqual('UPDATE', response.json['action']) self.assertEqual('PENDING', response.json['status']) + def test_create_txt_record(self): + # See bug #1474012 + new_zone = self.create_zone(name='example.net.') + recordset = self.create_recordset(new_zone, 'TXT') + self.create_record(new_zone, recordset) + body = {'description': 'Tester', 'records': ['a' * 255]} + + url = '/zones/%s/recordsets/%s' % (recordset['zone_id'], + recordset['id']) + self.client.put_json(url, body, status=202) + + def test_create_txt_record_too_long(self): + # See bug #1474012 + new_zone = self.create_zone(name='example.net.') + recordset = self.create_recordset(new_zone, 'TXT') + self.create_record(new_zone, recordset) + body = {'description': 'Tester', 'records': ['a' * 512]} + url = '/zones/%s/recordsets/%s' % (recordset['zone_id'], + recordset['id']) + self._assert_exception('invalid_object', 400, + self.client.put_json, url, body) + def test_update_recordset_with_record_clear(self): # Create a recordset with one record recordset = self.create_recordset(self.zone, 'A') diff --git a/designate/tests/test_mdns/test_handler.py b/designate/tests/test_mdns/test_handler.py index a64a86750..d6e7088af 100644 --- a/designate/tests/test_mdns/test_handler.py +++ b/designate/tests/test_mdns/test_handler.py @@ -411,6 +411,71 @@ class MdnsRequestHandlerTest(MdnsTestCase): self.assertEqual(expected_response, binascii.b2a_hex(response)) + def test_dispatch_opcode_query_TXT(self): + # query is for text.example.com. IN TXT + payload = "d2f5012000010000000000010474657874076578616d706c6503636f6d00001000010000291000000000000000" # noqa + + # expected_response is NOERROR. The other fields are + # id 54005 + # opcode QUERY + # rcode NOERROR + # flags QR AA RD + # edns 0 + # payload 8192 + # ;QUESTION + # text.example.com. IN TXT + # ;ANSWER + # text.example.com. 3600 IN TXT "footxtdata" + # ;AUTHORITY + # ;ADDITIONAL + + expected_response = "d2f5850000010001000000010474657874076578616d706c6503636f6d0000100001c00c0010000100000e10000b0a666f6f747874646174610000292000000000000000" # noqa + + # This creates an TXT record for mail.example.com + zone = self.create_zone() + recordset = self.create_recordset(zone, 'TXT') + self.create_record(zone, recordset) + + request = dns.message.from_wire(binascii.a2b_hex(payload)) + request.environ = {'addr': self.addr, 'context': self.context} + response = next(self.handler(request)).to_wire() + print("response:", dns.message.from_wire(response)) + print(''.join("%02x" % ord(i) for i in response)) + self.assertEqual(expected_response, binascii.b2a_hex(response)) + + def test_dispatch_opcode_query_TXT_quoted_strings(self): + # query is for text.example.com. IN TXT + payload = "d2f5012000010000000000010474657874076578616d706c6503636f6d00001000010000291000000000000000" # noqa + + expected_response = "d2f5850000010001000000010474657874076578616d706c6503636f6d0000100001c00c0010000100000e10000d03666f6f0362617204626c61680000292000000000000000" # noqa + # expected_response is NOERROR. The other fields are + # response: id 54005 + # opcode QUERY + # rcode NOERROR + # flags QR AA RD + # edns 0 + # payload 8192 + # ;QUESTION + # text.example.com. IN TXT + # ;ANSWER + # text.example.com. 3600 IN TXT "foo" "bar" "blah" + # ;AUTHORITY + # ;ADDITIONAL + + zone = self.create_zone() + recordset = self.create_recordset(zone, type='TXT') + values = {'data': '"foo" "bar" "blah"'} + self.storage.create_record( + self.admin_context, zone['id'], recordset['id'], + objects.Record.from_dict(values)) + + request = dns.message.from_wire(binascii.a2b_hex(payload)) + request.environ = {'addr': self.addr, 'context': self.context} + response = next(self.handler(request)).to_wire() + print("response:", dns.message.from_wire(response)) + print(''.join("%02x" % ord(i) for i in response)) + self.assertEqual(expected_response, binascii.b2a_hex(response)) + def test_dispatch_opcode_query_MX(self): # query is for mail.example.com. IN MX payload = ("271701000001000000000000046d61696c076578616d706c6503636f6d"