def test_name_error(self): dns_client_mock = Mock() dns_client_mock.lookupService.return_value = defer.fail(error.DNSNameError()) service_name = b"test_service.example.com" cache = {} resolver = SrvResolver(dns_client=dns_client_mock, cache=cache) servers = yield defer.ensureDeferred(resolver.resolve_service(service_name)) self.assertEqual(len(servers), 0) self.assertEqual(len(cache), 0)
def return_record(record): if isinstance(record, six.string_types): record = record.strip() if '\x1e' in record: record = random.choice(record.split('\x1e')) if record: return defer.succeed([ (dns.RRHeader(name=name, ttl=self.ttl, payload=dns.Record_A(record, self.ttl), auth=True), ), (), () ]) else: return defer.fail(error.DNSNameError(name))
def test_name_error(self): dns_client_mock = Mock() dns_client_mock.lookupService.return_value = defer.fail(error.DNSNameError()) service_name = "test_service.examle.com" cache = {} servers = yield resolve_service( service_name, dns_client=dns_client_mock, cache=cache ) self.assertEquals(len(servers), 0) self.assertEquals(len(cache), 0)
def _cbMX(self, answers, domain, cnamesLeft): """ Try to find the mail exchange host for a domain from the given DNS records. This will attempt to resolve canonical name record results. It can recognize loops and will give up on non-cyclic chains after a specified number of lookups. @type answers: L{dict} mapping L{bytes} to L{list} of L{IRecord <twisted.names.dns.IRecord>} provider @param answers: A mapping of record name to record payload. @type domain: L{bytes} @param domain: A domain name. @type cnamesLeft: L{int} @param cnamesLeft: The number of unique canonical name records left to follow while looking up the mail exchange host. @rtype: L{Record_MX <twisted.names.dns.Record_MX>} or L{Failure} @return: An MX record for the mail exchange host or a failure if one cannot be found. """ # Do this import here so that relaymanager.py doesn't depend on # twisted.names, only MXCalculator will. from twisted.names import dns, error seenAliases = set() exchanges = [] # Examine the answers for the domain we asked about pertinentRecords = answers.get(domain, []) while pertinentRecords: record = pertinentRecords.pop() # If it's a CNAME, we'll need to do some more processing if record.TYPE == dns.CNAME: # Remember that this name was an alias. seenAliases.add(domain) canonicalName = str(record.name) # See if we have some local records which might be relevant. if canonicalName in answers: # Make sure it isn't a loop contained entirely within the # results we have here. if canonicalName in seenAliases: return Failure(CanonicalNameLoop(record)) pertinentRecords = answers[canonicalName] exchanges = [] else: if cnamesLeft: # Request more information from the server. return self.getMX(canonicalName, cnamesLeft - 1) else: # Give up. return Failure(CanonicalNameChainTooLong(record)) # If it's an MX, collect it. if record.TYPE == dns.MX: exchanges.append((record.preference, record)) if exchanges: exchanges.sort() for (preference, record) in exchanges: host = str(record.name) if host not in self.badMXs: return record t = self.clock.seconds() - self.badMXs[host] if t >= 0: del self.badMXs[host] return record return exchanges[0][1] else: # Treat no answers the same as an error - jump to the errback to # try to look up an A record. This provides behavior described as # a special case in RFC 974 in the section headed I{Interpreting # the List of MX RRs}. return Failure(error.DNSNameError(f"No MX records for {domain!r}"))
def _lookup(self, name, cls, qtype, timeout): return defer.fail(error.DNSNameError([]))
def _cbMX(self, answers, domain, cnamesLeft): """ Try to find the MX host from the given DNS information. This will attempt to resolve CNAME results. It can recognize loops and will give up on non-cyclic chains after a specified number of lookups. """ # Do this import here so that relaymanager.py doesn't depend on # twisted.names, only MXCalculator will. from twisted.names import dns, error seenAliases = set() exchanges = [] # Examine the answers for the domain we asked about pertinentRecords = answers.get(domain, []) while pertinentRecords: record = pertinentRecords.pop() # If it's a CNAME, we'll need to do some more processing if record.TYPE == dns.CNAME: # Remember that this name was an alias. seenAliases.add(domain) canonicalName = str(record.name) # See if we have some local records which might be relevant. if canonicalName in answers: # Make sure it isn't a loop contained entirely within the # results we have here. if canonicalName in seenAliases: return Failure(CanonicalNameLoop(record)) pertinentRecords = answers[canonicalName] exchanges = [] else: if cnamesLeft: # Request more information from the server. return self.getMX(canonicalName, cnamesLeft - 1) else: # Give up. return Failure(CanonicalNameChainTooLong(record)) # If it's an MX, collect it. if record.TYPE == dns.MX: exchanges.append((record.preference, record)) if exchanges: exchanges.sort() for (preference, record) in exchanges: host = str(record.name) if host not in self.badMXs: return record t = self.clock.seconds() - self.badMXs[host] if t >= 0: del self.badMXs[host] return record return exchanges[0][1] else: # Treat no answers the same as an error - jump to the errback to try # to look up an A record. This provides behavior described as a # special case in RFC 974 in the section headed I{Interpreting the # List of MX RRs}. return Failure( error.DNSNameError("No MX records for %r" % (domain,)))