Browse Source

Add support for relative target/exchange/nameserver values

allow-relative-values
Ross McFarland 2 years ago
parent
commit
c501d775ba
No known key found for this signature in database GPG Key ID: 943B179E15D3B22A
7 changed files with 100 additions and 20 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +15
    -10
      octodns/record/mx.py
  3. +14
    -9
      octodns/record/srv.py
  4. +5
    -1
      octodns/record/target.py
  5. +15
    -0
      tests/test_octodns_record_mx.py
  6. +20
    -0
      tests/test_octodns_record_srv.py
  7. +30
    -0
      tests/test_octodns_record_target.py

+ 1
- 0
CHANGELOG.md View File

@ -8,6 +8,7 @@
* Correctly handle FQDNs in TinyDNS config files that end with trailing .'s
* Complete rewrite of TinyDnsBaseSource to fully implement the spec and the ipv6
extensions
* Allow relative target, nameserver, or exchange values
## v1.0.0.rc0 - 2023-05-16 - First of the ones


+ 15
- 10
octodns/record/mx.py View File

@ -45,16 +45,21 @@ class MxValue(EqualityTupleMixin, dict):
reasons.append('missing exchange')
continue
exchange = idna_encode(exchange)
if (
exchange != '.'
and not FQDN(exchange, allow_underscores=True).is_valid
):
reasons.append(
f'Invalid MX exchange "{exchange}" is not '
'a valid FQDN.'
)
elif not exchange.endswith('.'):
reasons.append(f'MX value "{exchange}" missing trailing .')
if '.' not in exchange:
reasons.append(f'MX exchange "{exchange}" is relative')
else:
if (
exchange != '.'
and not FQDN(exchange, allow_underscores=True).is_valid
):
reasons.append(
f'Invalid MX exchange "{exchange}" is not '
'a valid FQDN.'
)
elif not exchange.endswith('.'):
reasons.append(
f'MX value "{exchange}" missing trailing .'
)
except KeyError:
reasons.append('missing exchange')
return reasons


+ 14
- 9
octodns/record/srv.py View File

@ -69,15 +69,20 @@ class SrvValue(EqualityTupleMixin, dict):
reasons.append('missing target')
continue
target = idna_encode(target)
if not target.endswith('.'):
reasons.append(f'SRV value "{target}" missing trailing .')
if (
target != '.'
and not FQDN(target, allow_underscores=True).is_valid
):
reasons.append(
f'Invalid SRV target "{target}" is not a valid FQDN.'
)
if '.' not in target:
reasons.append(f'SRV value "{target}" is relative')
else:
if not target.endswith('.'):
reasons.append(
f'SRV value "{target}" missing trailing .'
)
if (
target != '.'
and not FQDN(target, allow_underscores=True).is_valid
):
reasons.append(
f'Invalid SRV target "{target}" is not a valid FQDN.'
)
except KeyError:
reasons.append('missing target')
return reasons


+ 5
- 1
octodns/record/target.py View File

@ -19,6 +19,8 @@ class _TargetValue(str):
reasons.append('empty value')
elif not data:
reasons.append('missing value')
elif '.' not in data:
reasons.append(f'{_type} value "{data}" is relative')
else:
data = idna_encode(data)
if not FQDN(str(data), allow_underscores=True).is_valid:
@ -58,7 +60,9 @@ class _TargetsValue(str):
reasons = []
for value in data:
value = idna_encode(value)
if not FQDN(value, allow_underscores=True).is_valid:
if '.' not in value:
reasons.append(f'{_type} value "{value}" is relative')
elif not FQDN(value, allow_underscores=True).is_valid:
reasons.append(
f'Invalid {_type} value "{value}" is not a valid FQDN.'
)


+ 15
- 0
tests/test_octodns_record_mx.py View File

@ -262,3 +262,18 @@ class TestRecordMx(TestCase):
},
)
self.assertEqual('.', record.values[0].exchange)
# relative exchange
with self.assertRaises(ValidationError) as ctx:
Record.new(
self.zone,
'',
{
'type': 'MX',
'ttl': 600,
'value': {'preference': 10, 'value': 'isrelative'},
},
)
self.assertEqual(
['MX exchange "isrelative" is relative'], ctx.exception.reasons
)

+ 20
- 0
tests/test_octodns_record_srv.py View File

@ -429,3 +429,23 @@ class TestRecordSrv(TestCase):
['Invalid SRV target "100 foo.bar.com." is not a valid FQDN.'],
ctx.exception.reasons,
)
# relative target
with self.assertRaises(ValidationError) as ctx:
Record.new(
self.zone,
'_srv._tcp',
{
'type': 'SRV',
'ttl': 600,
'value': {
'priority': 1,
'weight': 2,
'port': 3,
'target': 'isrelative',
},
},
)
self.assertEqual(
['SRV value "isrelative" is relative'], ctx.exception.reasons
)

+ 30
- 0
tests/test_octodns_record_target.py View File

@ -4,6 +4,7 @@
from unittest import TestCase
from octodns.record import Record, ValidationError
from octodns.record.alias import AliasRecord
from octodns.record.target import _TargetValue
from octodns.zone import Zone
@ -28,3 +29,32 @@ class TestRecordTarget(TestCase):
zone = Zone('unit.tests.', [])
a = AliasRecord(zone, 'a', {'ttl': 42, 'value': 'some.target.'})
self.assertEqual('some.target.', a.value.rdata_text)
def test_relative_target(self):
zone = Zone('unit.tests.', [])
data = {'ttl': 43, 'type': 'CNAME', 'value': 'isrelative'}
with self.assertRaises(ValidationError) as ctx:
Record.new(zone, 'cname', data)
self.assertEqual(
['CNAME value "isrelative" is relative'], ctx.exception.reasons
)
cname = Record.new(zone, 'cname', data, lenient=True)
self.assertEqual(data['value'], cname.value)
data = {
'ttl': 43,
'type': 'NS',
'values': ['isrelative1', 'isrelative2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(zone, 'ns', data)
self.assertEqual(
[
'NS value "isrelative1" is relative',
'NS value "isrelative2" is relative',
],
ctx.exception.reasons,
)
cname = Record.new(zone, 'ns', data, lenient=True)
self.assertEqual(data['values'], cname.values)

Loading…
Cancel
Save