def get_subdomains_bruteforcer(self, subdomain): """ Try to discover subdomains using bruteforce. This function is prepared to run in parallel. To try to make as less as possible connections, discovered_domains contains a list with already discovered domains. :param base_domain: string with de domain to make the test. :type base_domain: str :param updater_func: function to update the state of the process. :type updater_func: update_status :param subdomain: string with the domain to process. :type subdomain: str """ m_domain = "%s.%s" % (subdomain, self.base_domain) completed = self.completed.inc() progress = (float(completed) / float(self.total)) * 100.0 self.update_status(progress=progress) Logger.log_more_verbose("Looking for subdomain: %s" % m_domain) l_oks = DNS.get_a(m_domain, also_CNAME=True) l_oks.extend(DNS.get_aaaa(m_domain, also_CNAME=True)) return l_oks
def run(self, info): # Skip localhost. if info.root == "localhost": return # Get the domain name. domain = info.hostname Logger.log_more_verbose("Querying domain: %s" % domain) # We have as many steps as DNS register types there are. self.progress.set_total( len(DnsRegister.DNS_TYPES) ) # Only show progress updates every 10%. self.progress.min_delta = 10 # Try to get a DNS record of each type. results = [] for step, rtype in enumerate(DnsRegister.DNS_TYPES): results.extend( DNS.resolve(domain, rtype) ) self.progress.add_completed() Logger.log_more_verbose( "Found %d DNS registers for domain: %s" % (len(results), domain)) # Link all DNS records to the domain. map(info.add_information, results) # Return the results. return results
def recv_info(self, info): # Skip localhost. if info.root == "localhost": return # Get the domain name. domain = info.hostname # We have as many steps as DNS register types there are. self.progress.set_total(len(DnsRegister.DNS_TYPES)) # Only show progress updates every 10%. self.progress.min_delta = 10 # Try to get a DNS record of each type. results = [] for step, rtype in enumerate(DnsRegister.DNS_TYPES): Logger.log_more_verbose("Querying %r register for domain: %s" % (rtype, domain)) results.extend(DNS.resolve(domain, rtype)) self.progress.add_completed() Logger.log_verbose("Found %d DNS registers for domain: %s" % (len(results), domain)) # Link all DNS records to the domain. map(info.add_information, results) # Return the results. return results
def test_scope_example(): print "Testing scope with: www.example.com" main_config = OrchestratorConfig() main_config.ui_mode = "disabled" main_config.use_colors = False audit_config = AuditConfig() audit_config.targets = ["http://www.example.com"] audit_config.include_subdomains = True with PluginTester(main_config, audit_config) as t: print Config.audit_scope for token, flag in ( (None, False), ("", False), ("www.example.com", True), ("example.com", True), ("com", False), ("subdomain.example.com", True), ("subdomain.www.example.com", True), ("www.example.org", False), ("wwwexample.com", False), ("www.wrong.com", False), ("127.0.0.1", False), ("::1", False), ("[::1]", False), ("http://www.example.com", True), ("https://example.com", True), ("ftp://ftp.example.com", True), ("mailto://[email protected]", True), ##("*****@*****.**", True), ): assert ((token in Config.audit_scope) == flag), repr(token) assert gethostbyname("www.example.com") in Config.audit_scope for address in gethostbyname_ex("www.example.com")[2]: assert address in Config.audit_scope for register in DNS.get_a("www.example.com"): assert register.address in Config.audit_scope for register in DNS.get_aaaa("www.example.com"): assert register.address in Config.audit_scope assert "[%s]" % register.address in Config.audit_scope for register in DNS.get_a("www.google.com"): assert register.address not in Config.audit_scope for register in DNS.get_aaaa("www.google.com"): assert register.address not in Config.audit_scope assert "[%s]" % register.address not in Config.audit_scope
def test_scope_example(): print "Testing scope with: www.example.com" main_config = OrchestratorConfig() main_config.ui_mode = "disabled" main_config.use_colors = False audit_config = AuditConfig() audit_config.targets = ["www.example.com"] audit_config.include_subdomains = True with PluginTester(main_config, audit_config) as t: assert None not in Config.audit_scope assert "" not in Config.audit_scope assert "www.example.com" in Config.audit_scope assert "example.com" in Config.audit_scope assert "com" not in Config.audit_scope assert "subdomain.example.com" in Config.audit_scope assert "subdomain.www.example.com" in Config.audit_scope assert "www.example.org" not in Config.audit_scope assert "wwwexample.com" not in Config.audit_scope assert "www.wrong.com" not in Config.audit_scope assert "127.0.0.1" not in Config.audit_scope assert "::1" not in Config.audit_scope assert "[::1]" not in Config.audit_scope assert "http://www.example.com" in Config.audit_scope assert "https://example.com" in Config.audit_scope assert "ftp://ftp.example.com" in Config.audit_scope assert "mailto://[email protected]" in Config.audit_scope ## assert "*****@*****.**" in Config.audit_scope assert gethostbyname("www.example.com") in Config.audit_scope for address in gethostbyname_ex("www.example.com")[2]: assert address in Config.audit_scope for register in DNS.get_a("www.example.com"): assert register.address in Config.audit_scope for register in DNS.get_aaaa("www.example.com"): assert register.address in Config.audit_scope assert "[%s]" % register.address in Config.audit_scope for register in DNS.get_a("www.google.com"): assert register.address not in Config.audit_scope for register in DNS.get_aaaa("www.google.com"): assert register.address not in Config.audit_scope assert "[%s]" % register.address not in Config.audit_scope
def recv_info(self, info): m_domain = info.root # Skips localhost if m_domain == "localhost": return m_return = None # Checks if the hostname has been already processed if not self.state.check(m_domain): Logger.log_verbose("Starting DNS analyzer plugin") m_return = [] m_reg_len = len(DnsRegister.DNS_TYPES) for l_step, l_type in enumerate(DnsRegister.DNS_TYPES): # Update status progress = (float(l_step) / float(m_reg_len)) * 100.0 self.update_status(progress=progress) Logger.log_more_verbose("Making %r DNS query" % l_type) # Make the query m_return.extend(DNS.resolve(m_domain, l_type)) # Set the domain parsed self.state.set(m_domain, True) # Add the information to the host map(info.add_information, m_return) Logger.log_verbose( "Ending DNS analyzer plugin, found %d registers" % len(m_return)) return m_return
def recv_info(self, info): m_domain = info.root # Skips localhost if m_domain == "localhost": return m_return = None # Checks if the hostname has been already processed if not self.state.check(m_domain): Logger.log_verbose("Starting DNS analyzer plugin") m_return = [] m_reg_len = len(DnsRegister.DNS_TYPES) for l_step, l_type in enumerate(DnsRegister.DNS_TYPES): # Update status progress = (float(l_step) / float(m_reg_len)) * 100.0 self.update_status(progress=progress) Logger.log_more_verbose("Making %r DNS query" % l_type) # Make the query m_return.extend(DNS.resolve(m_domain, l_type)) # Set the domain parsed self.state.set(m_domain, True) # Add the information to the host map(info.add_information, m_return) Logger.log_verbose("Ending DNS analyzer plugin, found %d registers" % len(m_return)) return m_return
def run(self, info): # Get the root domain only. root = info.root # Skip localhost. if root == "localhost": return # Skip if the root domain is out of scope. if root not in Config.audit_scope: return # Skip root domains we've already processed. if self.state.put(root, True): return # Attempt a DNS zone transfer. ns_servers, resolv = DNS.zone_transfer( root, ns_allowed_zone_transfer = True) # On failure, skip. if not resolv: Logger.log_verbose( "DNS zone transfer failed, server %r not vulnerable" % root) return # Create a Domain object for the root domain. domain = Domain(root) # Associate all the results with the root domain. for r in resolv: map(domain.add_information, r) # Add the root domain to the results. results = [] results.append(domain) # We have a vulnerability on each of the nameservers involved. msg = "DNS zone transfer successful, " if len(ns_servers) > 1: msg += "%d nameservers for %r are vulnerable!" msg %= (len(ns_servers), root) else: msg += "nameserver for %r is vulnerable!" % root Logger.log(msg) # If we don't have the name servers... if not ns_servers: # Assume the root domain also points to the nameserver. vulnerability = DNSZoneTransfer(domain, root) results.append(vulnerability) # If we have the name servers... else: # Create a vulnerability for each nameserver in scope. for ns in ns_servers: vulnerability = DNSZoneTransfer(domain, ns) results.append(vulnerability) # Return the results. return results
def recv_info(self, info): # Get the root domain only. root = info.root # Skip localhost. if root == "localhost": return # Skip root domains we've already processed. if self.state.put(root, True): return # Load the subdomains wordlist. try: wordlist = WordListLoader.get_advanced_wordlist_as_list(Config.plugin_args["wordlist"]) except WordlistNotFound: Logger.log_error_verbose("Wordlist '%s' not found.." % Config.plugin_args["wordlist"]) return except TypeError: Logger.log_error_verbose("Wordlist '%s' is not a file." % Config.plugin_args["wordlist"]) return # Load the subdomains whitelist. try: whitelist = WordListLoader.get_advanced_wordlist_as_list(Config.plugin_config["wordlist"]) except WordlistNotFound: Logger.log_error_verbose("Wordlist '%s' not found.." % Config.plugin_config["wordlist"]) return except TypeError: Logger.log_error_verbose("Wordlist '%s' is not a file." % Config.plugin_config["wordlist"]) return # # Set a base line for dinamyc sub-domains # m_virtual_domains = [] for v in (generate_random_string(40) for x in xrange(3)): l_subdomain = ".".join((v, root)) records = DNS.get_a(l_subdomain, also_CNAME=True) for rec in records: if rec.type == "CNAME": m_virtual_domains.append(rec.target) # If 3 subdomains are the same, set the base domain m_base_domain = None if len(set(m_virtual_domains)) == 1: m_base_domain = m_virtual_domains[0] # Configure the progress notifier. self.progress.set_total(len(wordlist)) self.progress.min_delta = 1 # notify every 1% # For each subdomain in the wordlist... found = 0 results = [] visited = set() for prefix in wordlist: # Mark as completed before actually trying. # We can't put this at the end of the loop where it belongs, # because the "continue" statements would skip over this too. self.progress.add_completed() # Build the domain name. name = ".".join((prefix, root)) # Skip if out of scope. if name not in Config.audit_scope: continue # Resolve the subdomain. records = DNS.get_a(name, also_CNAME=True) records.extend( DNS.get_aaaa(name, also_CNAME=True) ) # If no DNS records were found, skip. if not records: continue # If CNAME is the base domain, skip chk = [True for x in records if x.type == "CNAME" and x.target == m_base_domain] if len(chk) > 0 and all(chk): continue # We found a subdomain! found += 1 Logger.log_more_verbose( "Subdomain found: %s" % name) # Create the Domain object for the subdomain. domain = Domain(name) results.append(domain) # # Check for Domain disclosure # if prefix not in whitelist: d = DomainDisclosure(name, risk = 0, level = "low", title = "Possible subdomain leak", description = "A subdomain was discovered which may be an unwanted information disclosure." ) d.add_resource(domain) results.append(d) # For each DNs record, grab the address or name. # Skip duplicated records. for rec in records: if rec.type == "CNAME": location = rec.target elif rec.type in ("A", "AAAA"): location = rec.address else: # should not happen... results.append(rec) domain.add_information(rec) continue if location not in visited: visited.add(location) results.append(rec) domain.add_information(rec) # Log the results. if found: Logger.log( "Found %d subdomains for root domain: %s" % (found, root)) else: Logger.log_verbose( "No subdomains found for root domain: %s" % root) # Return the results. return results
def recv_info(self, info): # Get the root domain only. root = info.root # Skip localhost. if root == "localhost": return # Skip if the root domain is out of scope. if root not in Config.audit_scope: return # Skip root domains we've already processed. if self.state.put(root, True): return # Attempt a DNS zone transfer. ns_servers, results = DNS.zone_transfer( root, ns_allowed_zone_transfer = True) # On failure, skip. if not results: Logger.log_verbose( "DNS zone transfer failed, server %r not vulnerable" % root) return # Create a Domain object for the root domain. domain = Domain(root) # Associate all the results with the root domain. map(domain.add_information, results) # Add the root domain to the results. results.append(domain) # We have a vulnerability on each of the nameservers involved. msg = "DNS zone transfer successful, " if len(ns_servers) > 1: msg += "%d nameservers for %r are vulnerable!" msg %= (len(ns_servers), root) else: msg += "nameserver for %r is vulnerable!" % root Logger.log(msg) # If we don't have the name servers... if not ns_servers: # Link the vulnerability to the root domain instead. vulnerability = DNSZoneTransfer(root) vulnerability.add_resource(domain) results.append(vulnerability) # If we have the name servers... else: # Create a vulnerability for each nameserver in scope. for ns in ns_servers: # Instance the vulnerability object. vulnerability = DNSZoneTransfer(ns) # Instance a Domain or IP object. try: resource = IP(ns) except ValueError: resource = Domain(ns) # Associate the resource to the root domain. domain.add_resource(resource) # Associate the nameserver to the vulnerability. vulnerability.add_resource(resource) # Add both to the results. results.append(resource) results.append(vulnerability) # Return the results. return results
def recv_info(self, info): # Get the root domain only. root = info.root # Skip localhost. if root == "localhost": return # Skip root domains we've already processed. if self.state.put(root, True): return # Load the subdomains wordlist. try: wordlist = WordListLoader.get_advanced_wordlist_as_list(Config.plugin_args["wordlist"]) except WordlistNotFound: Logger.log_error_verbose("Wordlist '%s' not found.." % Config.plugin_args["wordlist"]) return except TypeError: Logger.log_error_verbose("Wordlist '%s' is not a file." % Config.plugin_args["wordlist"]) return # Configure the progress notifier. self.progress.set_total(len(wordlist)) self.progress.min_delta = 1 # notify every 1% # For each subdomain in the wordlist... found = 0 results = [] visited = set() for prefix in wordlist: # Mark as completed before actually trying. # We can't put this at the end of the loop where it belongs, # because the "continue" statements would skip over this too. self.progress.add_completed() # Build the domain name. name = ".".join((prefix, root)) # Skip if out of scope. if name not in Config.audit_scope: continue # Resolve the subdomain. records = DNS.get_a(name, also_CNAME=True) records.extend( DNS.get_aaaa(name, also_CNAME=True) ) # If no DNS records were found, skip. if not records: continue # We found a subdomain! found += 1 Logger.log_more_verbose( "Subdomain found: %s" % name) # Create the Domain object for the subdomain. domain = Domain(name) results.append(domain) # For each DNs record, grab the address or name. # Skip duplicated records. for rec in records: if rec.type == "CNAME": location = rec.target elif rec.type in ("A", "AAAA"): location = rec.address else: # should not happen... results.append(rec) domain.add_information(rec) continue if location not in visited: visited.add(location) results.append(rec) domain.add_information(rec) # Log the results. if found: Logger.log( "Found %d subdomains for root domain: %s" % (found, root)) else: Logger.log_verbose( "No subdomains found for root domain: %s" % root) # Return the results. return results
def run(self, info): # Get the root domain only. root = info.root # Skip localhost. if root == "localhost": return # Skip root domains we've already processed. if self.state.put(root, True): return # Load the subdomains wordlist. try: wordlist = WordListLoader.get_wordlist_as_list(Config.plugin_args["wordlist"]) except WordlistNotFound: Logger.log_error_verbose("Wordlist '%s' not found.." % Config.plugin_args["wordlist"]) return except TypeError: Logger.log_error_verbose("Wordlist '%s' is not a file." % Config.plugin_args["wordlist"]) return # Load the subdomains whitelist. try: whitelist = WordListLoader.get_wordlist_as_list(Config.plugin_config["wordlist"]) except WordlistNotFound: Logger.log_error_verbose("Wordlist '%s' not found.." % Config.plugin_config["wordlist"]) return except TypeError: Logger.log_error_verbose("Wordlist '%s' is not a file." % Config.plugin_config["wordlist"]) return # # Set a base line for dinamyc sub-domains # m_virtual_domains = [] for v in (generate_random_string(40) for x in xrange(3)): l_subdomain = ".".join((v, root)) records = DNS.get_a(l_subdomain, also_CNAME=True) for rec in records: if rec.type == "CNAME": m_virtual_domains.append(rec.target) # If 3 subdomains are the same, set the base domain m_base_domain = None if len(set(m_virtual_domains)) == 1: m_base_domain = m_virtual_domains[0] # Configure the progress notifier. self.progress.set_total(len(wordlist)) self.progress.min_delta = 1 # notify every 1% # For each subdomain in the wordlist... found = 0 results = [] visited = set() for prefix in wordlist: # Mark as completed before actually trying. # We can't put this at the end of the loop where it belongs, # because the "continue" statements would skip over this too. self.progress.add_completed() # Build the domain name. name = ".".join((prefix, root)) # Skip if out of scope. if name not in Config.audit_scope: continue # Resolve the subdomain. records = DNS.get_a(name, also_CNAME=True) records.extend( DNS.get_aaaa(name, also_CNAME=True) ) # If no DNS records were found, skip. if not records: continue # If CNAME is the base domain, skip chk = [True for x in records if x.type == "CNAME" and x.target == m_base_domain] if len(chk) > 0 and all(chk): continue # We found a subdomain! found += 1 Logger.log_more_verbose( "Subdomain found: %s" % name) # Create the Domain object for the subdomain. domain = Domain(name) results.append(domain) # # Check for Domain disclosure # if prefix not in whitelist: d = DomainDisclosure(domain, risk = 0, level = "low", title = "Possible subdomain leak", description = "A subdomain was discovered which may be an unwanted information disclosure." ) results.append(d) # For each DNs record, grab the address or name. # Skip duplicated records. for rec in records: if rec.type == "CNAME": location = rec.target elif rec.type in ("A", "AAAA"): location = rec.address else: # should not happen... results.append(rec) domain.add_information(rec) continue if location not in visited: visited.add(location) results.append(rec) domain.add_information(rec) # Log the results. if found: Logger.log( "Found %d subdomains for root domain: %s" % (found, root)) else: Logger.log_verbose( "No subdomains found for root domain: %s" % root) # Return the results. return results
def recv_info(self, info): m_domain = info.root # Skips localhost if m_domain == "localhost": return m_return = None # Checks if the hostname has been already processed if not self.state.check(m_domain): Logger.log_more_verbose("Starting DNS zone transfer plugin") m_return = [] # # Make the zone transfer # m_ns_servers, m_zone_transfer = DNS.zone_transfer(m_domain, ns_allowed_zone_transfer=True) m_return_append = m_return.append if m_zone_transfer: Logger.log_more_verbose("DNS zone transfer successful") m_return.extend(m_zone_transfer) for l_ns in m_ns_servers: # Create the vuln l_v = DNSZoneTransfer(l_ns) l_resource = None # Is a IPaddress? try: ip = IPAddress(l_ns) except Exception: ip = None if ip is not None: # Create the IP resource l_resource = IP(l_ns) else: # Create the Domain resource l_resource = Domain(l_ns) # Associate the resource to the vuln l_v.add_resource(l_resource) # Append to the results: the resource and the vuln m_return_append(l_v) m_return_append(l_resource) else: Logger.log_more_verbose("DNS zone transfer failed, server not vulnerable") m_return.extend(m_ns_servers) # Set the domain parsed self.state.set(m_domain, True) return m_return
def recv_info(self, info): m_domain = info.root # Skips localhost if m_domain == "localhost": return m_return = None # Checks if the hostname has been already processed if not self.state.check(m_domain): Logger.log_more_verbose("Starting DNS zone transfer plugin") m_return = [] # # Make the zone transfer # m_ns_servers, m_zone_transfer = DNS.zone_transfer( m_domain, ns_allowed_zone_transfer=True) m_return_append = m_return.append if m_zone_transfer: Logger.log_more_verbose("DNS zone transfer successful") m_return.extend(m_zone_transfer) for l_ns in m_ns_servers: # Create the vuln l_v = DNSZoneTransfer(l_ns) l_resource = None # Is a IPaddress? try: ip = IPAddress(l_ns) except Exception: ip = None if ip is not None: # Create the IP resource l_resource = IP(l_ns) else: # Create the Domain resource l_resource = Domain(l_ns) # Associate the resource to the vuln l_v.add_resource(l_resource) # Append to the results: the resource and the vuln m_return_append(l_v) m_return_append(l_resource) else: Logger.log_more_verbose( "DNS zone transfer failed, server not vulnerable") m_return.extend(m_ns_servers) # Set the domain parsed self.state.set(m_domain, True) return m_return
def run(self, info): # Get the root domain only. root = info.root # Skip localhost. if root == "localhost": return # Skip if the root domain is out of scope. if root not in Config.audit_scope: return # Skip root domains we've already processed. if self.state.put(root, True): return # Attempt a DNS zone transfer. ns_servers, resolv = DNS.zone_transfer(root, ns_allowed_zone_transfer=True) # On failure, skip. if not resolv: Logger.log_verbose( "DNS zone transfer failed, server %r not vulnerable" % root) return # Create a Domain object for the root domain. domain = Domain(root) # Associate all the results with the root domain. for r in resolv: map(domain.add_information, r) # Add the root domain to the results. results = [] results.append(domain) # We have a vulnerability on each of the nameservers involved. msg = "DNS zone transfer successful, " if len(ns_servers) > 1: msg += "%d nameservers for %r are vulnerable!" msg %= (len(ns_servers), root) else: msg += "nameserver for %r is vulnerable!" % root Logger.log(msg) # If we don't have the name servers... if not ns_servers: # Assume the root domain also points to the nameserver. vulnerability = DNSZoneTransfer(domain, root) results.append(vulnerability) # If we have the name servers... else: # Create a vulnerability for each nameserver in scope. for ns in ns_servers: vulnerability = DNSZoneTransfer(domain, ns) results.append(vulnerability) # Return the results. return results
def recv_info(self, info): # Get the root domain only. root = info.root # Skip localhost. if root == "localhost": return # Skip if the root domain is out of scope. if root not in Config.audit_scope: return # Skip root domains we've already processed. if self.state.put(root, True): return # Attempt a DNS zone transfer. ns_servers, results = DNS.zone_transfer(root, ns_allowed_zone_transfer=True) # On failure, skip. if not results: Logger.log_verbose( "DNS zone transfer failed, server %r not vulnerable" % root) return # Create a Domain object for the root domain. domain = Domain(root) # Associate all the results with the root domain. map(domain.add_information, results) # Add the root domain to the results. results.append(domain) # We have a vulnerability on each of the nameservers involved. msg = "DNS zone transfer successful, " if len(ns_servers) > 1: msg += "%d nameservers for %r are vulnerable!" msg %= (len(ns_servers), root) else: msg += "nameserver for %r is vulnerable!" % root Logger.log(msg) # If we don't have the name servers... if not ns_servers: # Link the vulnerability to the root domain instead. vulnerability = DNSZoneTransfer(root) vulnerability.add_resource(domain) results.append(vulnerability) # If we have the name servers... else: # Create a vulnerability for each nameserver in scope. for ns in ns_servers: # Instance the vulnerability object. vulnerability = DNSZoneTransfer(ns) # Instance a Domain or IP object. try: resource = IP(ns) except ValueError: resource = Domain(ns) # Associate the resource to the root domain. domain.add_resource(resource) # Associate the nameserver to the vulnerability. vulnerability.add_resource(resource) # Add both to the results. results.append(resource) results.append(vulnerability) # Return the results. return results
def recv_info(self, info): # Get the root domain only. root = info.root # Skip localhost. if root == "localhost": return # Skip root domains we've already processed. if self.state.put(root, True): return # Load the subdomains wordlist. try: wordlist = WordListLoader.get_advanced_wordlist_as_list( Config.plugin_args["wordlist"]) except WordlistNotFound: Logger.log_error_verbose("Wordlist '%s' not found.." % Config.plugin_args["wordlist"]) return except TypeError: Logger.log_error_verbose("Wordlist '%s' is not a file." % Config.plugin_args["wordlist"]) return # Configure the progress notifier. self.progress.set_total(len(wordlist)) self.progress.min_delta = 1 # notify every 1% # For each subdomain in the wordlist... found = 0 results = [] visited = set() for prefix in wordlist: # Mark as completed before actually trying. # We can't put this at the end of the loop where it belongs, # because the "continue" statements would skip over this too. self.progress.add_completed() # Build the domain name. name = ".".join((prefix, root)) # Skip if out of scope. if name not in Config.audit_scope: continue # Resolve the subdomain. records = DNS.get_a(name, also_CNAME=True) records.extend(DNS.get_aaaa(name, also_CNAME=True)) # If no DNS records were found, skip. if not records: continue # We found a subdomain! found += 1 Logger.log_more_verbose("Subdomain found: %s" % name) # Create the Domain object for the subdomain. domain = Domain(name) results.append(domain) # For each DNs record, grab the address or name. # Skip duplicated records. for rec in records: if rec.type == "CNAME": location = rec.target elif rec.type in ("A", "AAAA"): location = rec.address else: # should not happen... results.append(rec) domain.add_information(rec) continue if location not in visited: visited.add(location) results.append(rec) domain.add_information(rec) # Log the results. if found: Logger.log("Found %d subdomains for root domain: %s" % (found, root)) else: Logger.log_verbose("No subdomains found for root domain: %s" % root) # Return the results. return results