Browse Source

TinyDNS SRV support and test coverage

pull/1020/head
Ross McFarland 2 years ago
parent
commit
80adcc5d9b
No known key found for this signature in database GPG Key ID: 943B179E15D3B22A
3 changed files with 122 additions and 12 deletions
  1. +77
    -10
      octodns/source/tinydns.py
  2. +39
    -2
      tests/test_octodns_source_tinydns.py
  3. +6
    -0
      tests/zones/tinydns/example.com

+ 77
- 10
octodns/source/tinydns.py View File

@ -16,12 +16,16 @@ from .base import BaseSource
class TinyDnsBaseSource(BaseSource):
SUPPORTS_GEO = False
SUPPORTS_DYNAMIC = False
SUPPORTS = set(('A', 'CNAME', 'MX', 'NS', 'TXT', 'AAAA'))
def __init__(self, id, default_ttl=3600):
super().__init__(id)
self.default_ttl = default_ttl
@property
def SUPPORTS(self):
# All record types, including those registered by 3rd party modules
return set(Record.registered_types().keys())
def _records_for_at(self, zone, name, lines, arpa=False):
# @fqdn:ip:x:dist:ttl:timestamp:lo
# MX (and optional A)
@ -38,7 +42,7 @@ class TinyDnsBaseSource(BaseSource):
ttl = self.default_ttl
for line in lines:
try:
ttl = int(lines[0][4])
ttl = int(line[4])
break
except IndexError:
pass
@ -61,7 +65,7 @@ class TinyDnsBaseSource(BaseSource):
# if we have an IP then we need to create an A for the MX
ip = line[1]
if ip:
if ip and zone.owns('A', mx):
yield 'A', mx, ttl, [ip]
values.append({'preference': dist, 'exchange': mx})
@ -88,7 +92,7 @@ class TinyDnsBaseSource(BaseSource):
ttl = self.default_ttl
for line in lines:
try:
ttl = int(lines[0][2])
ttl = int(line[2])
break
except IndexError:
pass
@ -163,7 +167,7 @@ class TinyDnsBaseSource(BaseSource):
ttl = self.default_ttl
for line in lines:
try:
ttl = int(lines[0][3])
ttl = int(line[3])
break
except IndexError:
pass
@ -180,7 +184,7 @@ class TinyDnsBaseSource(BaseSource):
# if we have an IP then we need to create an A for the MX
ip = line[1]
if ip:
if ip and zone.owns('A', ns):
yield 'A', ns, ttl, [ip]
values.append(ns)
@ -212,7 +216,7 @@ class TinyDnsBaseSource(BaseSource):
ttl = self.default_ttl
for line in lines:
try:
ttl = int(lines[0][2])
ttl = int(line[2])
break
except IndexError:
pass
@ -241,7 +245,7 @@ class TinyDnsBaseSource(BaseSource):
ttl = self.default_ttl
for line in lines:
try:
ttl = int(lines[0][2])
ttl = int(line[2])
break
except IndexError:
pass
@ -272,13 +276,76 @@ class TinyDnsBaseSource(BaseSource):
ttl = self.default_ttl
for line in lines:
try:
ttl = int(lines[0][2])
ttl = int(line[2])
break
except IndexError:
pass
yield 'AAAA', name, ttl, ips
def _records_for_S(self, zone, name, lines, arpa=False):
# Sfqdn:ip:x:port:priority:weight:ttl:timestamp:lo
# SRV
if arpa:
# no arpa
return []
if not zone.owns('SRV', name):
# if name doesn't live under our zone there's nothing for us to do
return
# see if we can find a ttl on any of the lines, first one wins
ttl = self.default_ttl
for line in lines:
try:
ttl = int(line[6])
break
except IndexError:
pass
values = []
for line in lines:
target = line[2]
# if there's a . in the mx we hit a special case and use it as-is
if '.' not in target:
# otherwise we treat it as the MX hostnam and construct the rest
target = f'{target}.srv.{zone.name}'
elif target[-1] != '.':
target = f'{target}.'
# if we have an IP then we need to create an A for the SRV
# has to be present, but can be empty
ip = line[1]
if ip and zone.owns('A', target):
yield 'A', target, ttl, [ip]
# required
port = int(line[3])
# optional, default 0
try:
priority = int(line[4] or 0)
except IndexError:
priority = 0
# optional, default 0
try:
weight = int(line[5] or 0)
except IndexError:
weight = 0
values.append(
{
'priority': priority,
'weight': weight,
'port': port,
'target': target,
}
)
yield 'SRV', name, ttl, values
def _records_for_six(self, zone, name, lines, arpa=False):
# 6fqdn:ip:ttl:timestamp:lo
# AAAA (arpa False) & PTR (arpa True)
@ -297,9 +364,9 @@ class TinyDnsBaseSource(BaseSource):
'&': _records_for_amp, # NS
'\'': _records_for_quote, # TXT
'3': _records_for_three, # AAAA
'S': _records_for_S, # SRV
'6': _records_for_six, # AAAA
# TODO:
#'S': _records_for_S, # SRV
# Sfqdn:ip:x:port:priority:weight:ttl:timestamp:lo
#':': _record_for_semicolon # arbitrary
# :fqdn:n:rdata:ttl:timestamp:lo


+ 39
- 2
tests/test_octodns_source_tinydns.py View File

@ -17,7 +17,7 @@ class TestTinyDnsFileSource(TestCase):
def test_populate_normal(self):
got = Zone('example.com.', [])
self.source.populate(got)
self.assertEqual(25, len(got.records))
self.assertEqual(28, len(got.records))
expected = Zone('example.com.', [])
for name, data in (
@ -140,6 +140,43 @@ class TestTinyDnsFileSource(TestCase):
'values': ['ns5.ns.example.com.', 'ns6.ns.example.com.'],
},
),
(
'_a._tcp',
{
'type': 'SRV',
'ttl': 43,
'values': [
{
'priority': 0,
'weight': 0,
'port': 8888,
'target': 'target.srv.example.com.',
},
{
'priority': 10,
'weight': 50,
'port': 8080,
'target': 'target.somewhere.else.',
},
],
},
),
('target.srv', {'type': 'A', 'ttl': 43, 'value': '56.57.58.59'}),
(
'_b._tcp',
{
'type': 'SRV',
'ttl': 3600,
'values': [
{
'priority': 0,
'weight': 0,
'port': 9999,
'target': 'target.srv.example.com.',
}
],
},
),
):
record = Record.new(expected, name, data)
expected.add_record(record)
@ -216,4 +253,4 @@ class TestTinyDnsFileSource(TestCase):
got = Zone('example.com.', ['sub'])
self.source.populate(got)
# we don't see one www.sub.example.com. record b/c it's in a sub
self.assertEqual(24, len(got.records))
self.assertEqual(27, len(got.records))

+ 6
- 0
tests/zones/tinydns/example.com View File

@ -61,3 +61,9 @@ Ccname.other.foo:www.other.foo
6ipv6-6.example.com:2a021348017cd5d0002419fffef35743
'semicolon.example.com:v=DKIM1; k=rsa; p=blah:300
# SRV
S_a._tcp.example.com:56.57.58.59:target:8888
S_a._tcp.example.com::target.somewhere.else:8080:10:50:43
# TODO: add an IP so it tries to create a record that already exists
S_b._tcp.example.com::target.srv.example.com.:9999

Loading…
Cancel
Save