Improve NAPTR support

This patchset adds support for fields (e.g flags, services, regexp)
to be quoted and empty as described in RFC 2915. While unquoted
fields are NOT optional, the previous behaviour remains for
backward compatibility. The regular expressions have been adjusted
to allow empty string values for quoted fields. Additional tests
added to cover more cases.

https://datatracker.ietf.org/doc/html/rfc2915
https://github.com/isc-projects/bind9/blob/main/bin/tests/system/xfer/dig1.good

Change-Id: I44bc7d2a231ed8d63cba69ec95f06358687aa914
This commit is contained in:
Rossen Popov 2023-05-19 13:45:54 +01:00
parent 590064e8d9
commit aa151b4d00
3 changed files with 50 additions and 6 deletions

View File

@ -96,9 +96,9 @@ class StringFields(ovoo_fields.StringField):
RE_SRV_HOST_NAME = r'^(?:(?!\-)(?:\_[A-Za-z0-9_\-]{1,63}\.){2})(?!.{255,})(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)\.)+\Z' # noqa
RE_SSHFP_FINGERPRINT = r'^([0-9A-Fa-f]{10,40}|[0-9A-Fa-f]{64})\Z'
RE_TLDNAME = r'^(?!.{255,})(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-))(?:\.(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)))*\Z' # noqa
RE_NAPTR_FLAGS = r'^(?!.*(.).*\1)[APSU]+$'
RE_NAPTR_SERVICE = r'^([A-Za-z]([A-Za-z0-9]*)(\+[A-Za-z]([A-Za-z0-9]{0,31}))*)?' # noqa
RE_NAPTR_REGEXP = r'^([^0-9i\\])(.*)\1((.+)|(\\[1-9]))\1(i?)'
RE_NAPTR_FLAGS = r'^[APSUapsu]*$'
RE_NAPTR_SERVICE = r'^([A-Za-z]([A-Za-z0-9]*)(\+[A-Za-z]([A-Za-z0-9]{0,31}))*)?$' # noqa
RE_NAPTR_REGEXP = r'^(([^0-9i\\])(.*)\2((.+)|(\\[1-9]))?\2(i?))?$'
RE_KVP = r'^\s[A-Za-z0-9]+=[A-Za-z0-9]+'
RE_URL_MAIL = r'^mailto:[A-Za-z0-9_\-]+(\+[A-Za-z0-9_\-]+)?@.*'
RE_URL_HTTP = r'^http(s)?://.*/'

View File

@ -35,15 +35,22 @@ class NAPTR(Record):
'replacement': fields.DomainField(maxLength=255)
}
@staticmethod
def _strip_double_quotes(value):
if value.startswith('"') and value.endswith('"'):
return value[1:-1]
else:
return value
def from_string(self, value):
order, preference, flags, service, regexp, replacement = (
value.split(' ')
)
self.order = int(order)
self.preference = int(preference)
self.flags = flags
self.service = service
self.regexp = regexp
self.flags = self._strip_double_quotes(flags)
self.service = self._strip_double_quotes(service)
self.regexp = self._strip_double_quotes(regexp)
self.replacement = replacement
# The record type is defined in the RFC. This will be used when the record

View File

@ -34,3 +34,40 @@ class RRDataNAPTRTest(oslotest.base.BaseTestCase):
self.assertEqual('!^.*$!sip:customer-service@example.com!',
naptr_record.regexp)
self.assertEqual('_sip._udp.example.com.', naptr_record.replacement)
def test_parse_naptr_quoted(self):
naptr_record = objects.NAPTR()
naptr_record.from_string(
'0 0 "S" "SIP+D2U" "!^.*$!sip:support@example.com!" _sip._udp.example.com.') # noqa
self.assertEqual(0, naptr_record.order)
self.assertEqual(0, naptr_record.preference)
self.assertEqual('S', naptr_record.flags)
self.assertEqual('SIP+D2U', naptr_record.service)
self.assertEqual('!^.*$!sip:support@example.com!',
naptr_record.regexp)
self.assertEqual('_sip._udp.example.com.', naptr_record.replacement)
def test_parse_naptr_empty_fields(self):
naptr_record = objects.NAPTR()
naptr_record.from_string('0 0 "" "" "" test.') # noqa
self.assertEqual(0, naptr_record.order)
self.assertEqual(0, naptr_record.preference)
self.assertEqual('', naptr_record.flags)
self.assertEqual('', naptr_record.service)
self.assertEqual('',
naptr_record.regexp)
self.assertEqual('test.', naptr_record.replacement)
def test_parse_naptr_valid_exampe1(self):
naptr_record = objects.NAPTR()
naptr_record.from_string('65535 65535 "SAUP" "bloop" ":beep::" test.') # noqa
self.assertEqual(65535, naptr_record.order)
self.assertEqual(65535, naptr_record.preference)
self.assertEqual('SAUP', naptr_record.flags)
self.assertEqual('bloop', naptr_record.service)
self.assertEqual(':beep::',
naptr_record.regexp)
self.assertEqual('test.', naptr_record.replacement)