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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user