1
0
mirror of https://github.com/github/octodns.git synced 2024-05-11 05:55:00 +00:00

Count extra lookups for the include mechanism

Co-authored-by: Jon Nangle <jon.nangle@ft.com>
This commit is contained in:
Samuel Parkinson
2023-02-15 16:45:50 +00:00
parent dc446eefb9
commit dfc0760adf
2 changed files with 71 additions and 27 deletions

View File

@@ -4,6 +4,10 @@
from logging import getLogger
import dns.resolver
from octodns.record.base import Record
from .base import BaseProcessor, ProcessorException
@@ -22,6 +26,47 @@ class SpfDnsLookupProcessor(BaseProcessor):
self.log.debug(f"SpfDnsLookupProcessor: {name}")
super().__init__(name)
def _lookup(
self, record: Record, values: list[str], lookups: int = 0
) -> int:
# SPF values must begin with 'v=spf1 '
spf = [value for value in values if value.startswith('v=spf1 ')]
if len(spf) == 0:
return lookups
if len(spf) > 1:
raise SpfValueException(
f"{record.fqdn} has more than one SPF value"
)
spf = spf[0]
terms = spf.removeprefix('v=spf1 ').split(' ')
for term in terms:
if lookups > 10:
raise SpfDnsLookupException(
f"{record.fqdn} exceeds the 10 DNS lookup limit in the SPF record"
)
# These mechanisms cost one DNS lookup each
if term.startswith(
('a', 'mx', 'exists:', 'redirect', 'include:', 'ptr')
):
lookups += 1
# The include mechanism can result in further lookups after resolving the DNS record
if term.startswith('include:'):
answer = dns.resolver.resolve(
term.removeprefix('include:'), 'TXT'
)
lookups = self._lookup(
record, [value.to_text()[1:-1] for value in answer], lookups
)
return lookups
def process_source_zone(self, zone, *args, **kwargs):
for record in zone.records:
if record._type != 'TXT':
@@ -30,29 +75,6 @@ class SpfDnsLookupProcessor(BaseProcessor):
if record._octodns.get('lenient'):
continue
# SPF values must begin with 'v=spf1 '
values = [
value for value in record.values if value.startswith('v=spf1 ')
]
if len(values) == 0:
continue
if len(values) > 1:
raise SpfValueException(
f"{record.fqdn} has more than one SPF value"
)
lookups = 0
terms = values[0].removeprefix('v=spf1 ').split(' ')
for term in terms:
if lookups > 10:
raise SpfDnsLookupException(
f"{record.fqdn} has too many SPF DNS lookups"
)
if term in ['a', 'mx', 'exists', 'redirect']:
lookups += 1
self._lookup(record, record.values)
return zone