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_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_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_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_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_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_REGEXP = r'^(([^0-9i\\])(.*)\2((.+)|(\\[1-9]))?\2(i?))?$'
RE_KVP = r'^\s[A-Za-z0-9]+=[A-Za-z0-9]+' 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_MAIL = r'^mailto:[A-Za-z0-9_\-]+(\+[A-Za-z0-9_\-]+)?@.*'
RE_URL_HTTP = r'^http(s)?://.*/' RE_URL_HTTP = r'^http(s)?://.*/'

View File

@ -35,15 +35,22 @@ class NAPTR(Record):
'replacement': fields.DomainField(maxLength=255) '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): def from_string(self, value):
order, preference, flags, service, regexp, replacement = ( order, preference, flags, service, regexp, replacement = (
value.split(' ') value.split(' ')
) )
self.order = int(order) self.order = int(order)
self.preference = int(preference) self.preference = int(preference)
self.flags = flags self.flags = self._strip_double_quotes(flags)
self.service = service self.service = self._strip_double_quotes(service)
self.regexp = regexp self.regexp = self._strip_double_quotes(regexp)
self.replacement = replacement self.replacement = replacement
# The record type is defined in the RFC. This will be used when the record # 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!', self.assertEqual('!^.*$!sip:customer-service@example.com!',
naptr_record.regexp) naptr_record.regexp)
self.assertEqual('_sip._udp.example.com.', naptr_record.replacement) 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)