diff --git a/octodns/processor/spf.py b/octodns/processor/spf.py index 2d3b4a2..fbecc7e 100644 --- a/octodns/processor/spf.py +++ b/octodns/processor/spf.py @@ -73,10 +73,13 @@ class SpfDnsLookupProcessor(BaseProcessor): f"{record.fqdn} exceeds the 10 DNS lookup limit in the SPF record" ) + if term.startswith('ptr'): + raise SpfValueException( + f"{record.fqdn} uses the deprecated ptr mechanism" + ) + # These mechanisms cost one DNS lookup each - if term.startswith( - ('a', 'mx', 'exists:', 'redirect', 'include:', 'ptr') - ): + if term.startswith(('a', 'mx', 'exists:', 'redirect', 'include:')): lookups += 1 # The include mechanism can result in further lookups after resolving the DNS record diff --git a/tests/test_octodns_processor_spf.py b/tests/test_octodns_processor_spf.py index efb59e8..a9b9828 100644 --- a/tests/test_octodns_processor_spf.py +++ b/tests/test_octodns_processor_spf.py @@ -245,3 +245,69 @@ class TestSpfDnsLookupProcessor(TestCase): with self.assertRaises(SpfValueException): processor.process_source_zone(zone) + + @patch('dns.resolver.resolve') + def test_processor_errors_ptr_mechanisms(self, resolver_mock): + processor = SpfDnsLookupProcessor('test') + zone = Zone('unit.tests.', []) + + zone.add_record( + Record.new( + zone, + '', + {'type': 'TXT', 'ttl': 86400, 'values': ['v=spf1 ptr ~all']}, + ) + ) + + with self.assertRaises(SpfValueException) as context: + processor.process_source_zone(zone) + self.assertEqual( + 'unit.tests. uses the deprecated ptr mechanism', + str(context.exception), + ) + + zone = Zone('unit.tests.', []) + + zone.add_record( + Record.new( + zone, + '', + { + 'type': 'TXT', + 'ttl': 86400, + 'values': ['v=spf1 ptr:example.com ~all'], + }, + ) + ) + + with self.assertRaises(SpfValueException) as context: + processor.process_source_zone(zone) + self.assertEqual( + 'unit.tests. uses the deprecated ptr mechanism', + str(context.exception), + ) + + zone = Zone('unit.tests.', []) + + zone.add_record( + Record.new( + zone, + '', + { + 'type': 'TXT', + 'ttl': 86400, + 'values': ['v=spf1 include:example.com ~all'], + }, + ) + ) + + txt_value_mock = MagicMock() + txt_value_mock.to_text.return_value = '"v=spf1 ptr -all"' + resolver_mock.return_value = [txt_value_mock] + + with self.assertRaises(SpfValueException) as context: + processor.process_source_zone(zone) + self.assertEqual( + 'unit.tests. uses the deprecated ptr mechanism', + str(context.exception), + )