finalize
This commit is contained in:
		
							parent
							
								
									5d0e095a81
								
							
						
					
					
						commit
						88017edbeb
					
				
							
								
								
									
										573
									
								
								dnsrecon.py
									
									
									
									
									
								
							
							
						
						
									
										573
									
								
								dnsrecon.py
									
									
									
									
									
								
							@ -66,9 +66,9 @@ class DNSReconTool:
 | 
			
		||||
    
 | 
			
		||||
    def get_dns_records(self, domain: str, record_type: str, 
 | 
			
		||||
                       server: Optional[str] = None) -> Dict[str, Any]:
 | 
			
		||||
        """Fetch DNS records with comprehensive error handling."""
 | 
			
		||||
        """Fetch DNS records with comprehensive error handling and proper parsing."""
 | 
			
		||||
        server_flag = f"@{server}" if server else ""
 | 
			
		||||
        cmd = f"dig {domain} {record_type} {server_flag} +noall +answer +nottlid"
 | 
			
		||||
        cmd = f"dig {domain} {record_type} {server_flag} +noall +answer"
 | 
			
		||||
        
 | 
			
		||||
        output = self.run_command(cmd)
 | 
			
		||||
        
 | 
			
		||||
@ -78,24 +78,35 @@ class DNSReconTool:
 | 
			
		||||
            for line in output.split('\n'):
 | 
			
		||||
                line = line.strip()
 | 
			
		||||
                if line and not line.startswith(';') and not line.startswith('>>'):
 | 
			
		||||
                    # Split on whitespace, but preserve quoted strings
 | 
			
		||||
                    parts = line.split(None, 4)
 | 
			
		||||
                    if len(parts) >= 5:  # name, ttl, class, type, data
 | 
			
		||||
                        records.append({
 | 
			
		||||
                            'name': parts[0].rstrip('.'),  # Remove trailing dot
 | 
			
		||||
                            'ttl': parts[1],
 | 
			
		||||
                            'class': parts[2], 
 | 
			
		||||
                            'type': parts[3],
 | 
			
		||||
                            'data': parts[4]
 | 
			
		||||
                        })
 | 
			
		||||
                    elif len(parts) == 4:  # Sometimes no data field
 | 
			
		||||
                        records.append({
 | 
			
		||||
                            'name': parts[0].rstrip('.'),
 | 
			
		||||
                            'ttl': parts[1],
 | 
			
		||||
                            'class': parts[2],
 | 
			
		||||
                            'type': parts[3],
 | 
			
		||||
                            'data': ''
 | 
			
		||||
                        })
 | 
			
		||||
                    # Split on any whitespace (handles both tabs and spaces)
 | 
			
		||||
                    parts = line.split()
 | 
			
		||||
                    
 | 
			
		||||
                    if len(parts) >= 4:
 | 
			
		||||
                        name = parts[0].rstrip('.')
 | 
			
		||||
                        
 | 
			
		||||
                        # Check if second field is numeric (TTL)
 | 
			
		||||
                        if len(parts) >= 5 and parts[1].isdigit():
 | 
			
		||||
                            # Format: name TTL class type data
 | 
			
		||||
                            ttl = parts[1]
 | 
			
		||||
                            dns_class = parts[2]
 | 
			
		||||
                            dns_type = parts[3]
 | 
			
		||||
                            data = ' '.join(parts[4:])
 | 
			
		||||
                        else:
 | 
			
		||||
                            # Format: name class type data (no TTL shown)
 | 
			
		||||
                            ttl = ''
 | 
			
		||||
                            dns_class = parts[1]
 | 
			
		||||
                            dns_type = parts[2]
 | 
			
		||||
                            data = ' '.join(parts[3:]) if len(parts) > 3 else ''
 | 
			
		||||
                        
 | 
			
		||||
                        # Validate that we have the expected record type
 | 
			
		||||
                        if dns_type.upper() == record_type.upper():
 | 
			
		||||
                            records.append({
 | 
			
		||||
                                'name': name,
 | 
			
		||||
                                'ttl': ttl,
 | 
			
		||||
                                'class': dns_class,
 | 
			
		||||
                                'type': dns_type,
 | 
			
		||||
                                'data': data
 | 
			
		||||
                            })
 | 
			
		||||
        
 | 
			
		||||
        return {
 | 
			
		||||
            'query': f"{domain} {record_type}",
 | 
			
		||||
@ -124,15 +135,23 @@ class DNSReconTool:
 | 
			
		||||
        dns_results = {}
 | 
			
		||||
        
 | 
			
		||||
        for record_type in record_types:
 | 
			
		||||
            print(f"  Querying {record_type} records...")
 | 
			
		||||
            dns_results[record_type] = {}
 | 
			
		||||
            for server in dns_servers:
 | 
			
		||||
                server_name = server or 'system'
 | 
			
		||||
                dns_results[record_type][server_name] = self.get_dns_records(
 | 
			
		||||
                    domain, record_type, server
 | 
			
		||||
                )
 | 
			
		||||
                result = self.get_dns_records(domain, record_type, server)
 | 
			
		||||
                dns_results[record_type][server_name] = result
 | 
			
		||||
                
 | 
			
		||||
                # Debug output for troubleshooting
 | 
			
		||||
                if result['records']:
 | 
			
		||||
                    print(f"    {server_name}: Found {len(result['records'])} {record_type} records")
 | 
			
		||||
                elif result['raw_output'].startswith('Error:'):
 | 
			
		||||
                    print(f"    {server_name}: {result['raw_output']}")
 | 
			
		||||
                
 | 
			
		||||
                time.sleep(0.1)  # Rate limiting
 | 
			
		||||
        
 | 
			
		||||
        # Try DNSSEC validation
 | 
			
		||||
        print("  Querying DNSSEC information...")
 | 
			
		||||
        dnssec_cmd = f"dig {domain} +dnssec +noall +answer"
 | 
			
		||||
        dns_results['DNSSEC'] = {
 | 
			
		||||
            'system': {
 | 
			
		||||
@ -146,7 +165,7 @@ class DNSReconTool:
 | 
			
		||||
        return dns_results
 | 
			
		||||
    
 | 
			
		||||
    def get_whois_data(self, domain: str) -> Dict[str, Any]:
 | 
			
		||||
        """Fetch and parse WHOIS data."""
 | 
			
		||||
        """Fetch and parse WHOIS data with improved parsing."""
 | 
			
		||||
        print("📋 Fetching WHOIS data...")
 | 
			
		||||
        
 | 
			
		||||
        raw_whois = self.run_command(f"whois {domain}")
 | 
			
		||||
@ -161,12 +180,26 @@ class DNSReconTool:
 | 
			
		||||
            lines = raw_whois.split('\n')
 | 
			
		||||
            for line in lines:
 | 
			
		||||
                line = line.strip()
 | 
			
		||||
                if ':' in line and not line.startswith('%') and not line.startswith('#'):
 | 
			
		||||
                    key, value = line.split(':', 1)
 | 
			
		||||
                    key = key.strip().lower().replace(' ', '_')
 | 
			
		||||
                if ':' in line and not line.startswith('%') and not line.startswith('#') and not line.startswith('>>>'):
 | 
			
		||||
                    # Handle different WHOIS formats
 | 
			
		||||
                    if line.count(':') == 1:
 | 
			
		||||
                        key, value = line.split(':', 1)
 | 
			
		||||
                    else:
 | 
			
		||||
                        # Multiple colons - take first as key, rest as value
 | 
			
		||||
                        parts = line.split(':', 2)
 | 
			
		||||
                        key, value = parts[0], ':'.join(parts[1:])
 | 
			
		||||
                    
 | 
			
		||||
                    key = key.strip().lower().replace(' ', '_').replace('-', '_')
 | 
			
		||||
                    value = value.strip()
 | 
			
		||||
                    if value:
 | 
			
		||||
                        whois_data['parsed'][key] = value
 | 
			
		||||
                    if value and key:
 | 
			
		||||
                        # Handle multiple values for same key (like name servers)
 | 
			
		||||
                        if key in whois_data['parsed']:
 | 
			
		||||
                            # Convert to list if not already
 | 
			
		||||
                            if not isinstance(whois_data['parsed'][key], list):
 | 
			
		||||
                                whois_data['parsed'][key] = [whois_data['parsed'][key]]
 | 
			
		||||
                            whois_data['parsed'][key].append(value)
 | 
			
		||||
                        else:
 | 
			
		||||
                            whois_data['parsed'][key] = value
 | 
			
		||||
        
 | 
			
		||||
        return whois_data
 | 
			
		||||
    
 | 
			
		||||
@ -280,33 +313,52 @@ class DNSReconTool:
 | 
			
		||||
    def _write_dns_server_comparison(self, f, dns_data: Dict):
 | 
			
		||||
        """Compare responses from different DNS servers."""
 | 
			
		||||
        servers = ['system', '1.1.1.1', '8.8.8.8', '9.9.9.9']
 | 
			
		||||
        record_types = ['A', 'AAAA', 'MX', 'NS']
 | 
			
		||||
        record_types = ['A', 'AAAA', 'MX', 'NS', 'TXT']
 | 
			
		||||
        
 | 
			
		||||
        discrepancies_found = False
 | 
			
		||||
        
 | 
			
		||||
        for record_type in record_types:
 | 
			
		||||
            if record_type in dns_data:
 | 
			
		||||
                f.write(f"\n{record_type} Records:\n")
 | 
			
		||||
                server_results = {}
 | 
			
		||||
                errors = {}
 | 
			
		||||
                
 | 
			
		||||
                for server in servers:
 | 
			
		||||
                    if server in dns_data[record_type]:
 | 
			
		||||
                        records = dns_data[record_type][server].get('records', [])
 | 
			
		||||
                        server_results[server] = set(r.get('data', '') for r in records if r.get('data'))
 | 
			
		||||
                        server_data = dns_data[record_type][server]
 | 
			
		||||
                        records = server_data.get('records', [])
 | 
			
		||||
                        raw_output = server_data.get('raw_output', '')
 | 
			
		||||
                        
 | 
			
		||||
                        if raw_output.startswith('Error:'):
 | 
			
		||||
                            errors[server] = raw_output
 | 
			
		||||
                            server_results[server] = set()
 | 
			
		||||
                        else:
 | 
			
		||||
                            server_results[server] = set(r.get('data', '') for r in records if r.get('data'))
 | 
			
		||||
                    else:
 | 
			
		||||
                        server_results[server] = set()
 | 
			
		||||
                
 | 
			
		||||
                # Show results for each server
 | 
			
		||||
                for server in servers:
 | 
			
		||||
                    records = server_results.get(server, set())
 | 
			
		||||
                    if server in errors:
 | 
			
		||||
                        f.write(f"  {server:<12}: {errors[server]}\n")
 | 
			
		||||
                    elif records:
 | 
			
		||||
                        f.write(f"  {server:<12}: {', '.join(sorted(records))}\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {server:<12}: No records\n")
 | 
			
		||||
                
 | 
			
		||||
                # Check for discrepancies
 | 
			
		||||
                if len(server_results) > 1:
 | 
			
		||||
                    all_results = list(server_results.values())
 | 
			
		||||
                    if not all(result == all_results[0] for result in all_results):
 | 
			
		||||
                        if not discrepancies_found:
 | 
			
		||||
                            discrepancies_found = True
 | 
			
		||||
                        f.write(f"  ⚠️  {record_type} records differ between DNS servers:\n")
 | 
			
		||||
                        for server, records in server_results.items():
 | 
			
		||||
                            f.write(f"    {server}: {', '.join(sorted(records)) if records else 'No records'}\n")
 | 
			
		||||
                    unique_results = set(frozenset(result) for result in server_results.values())
 | 
			
		||||
                    if len(unique_results) > 1:
 | 
			
		||||
                        f.write(f"  ⚠️ INCONSISTENCY DETECTED between servers!\n")
 | 
			
		||||
                        discrepancies_found = True
 | 
			
		||||
        
 | 
			
		||||
        if not discrepancies_found:
 | 
			
		||||
            f.write("  ✅ All DNS servers return consistent results\n")
 | 
			
		||||
            f.write(f"\n✅ All DNS servers return consistent results\n")
 | 
			
		||||
 | 
			
		||||
    def create_summary_report(self, results: Dict[str, Any], filename: str) -> None:
 | 
			
		||||
        """Create comprehensive human-readable summary report."""
 | 
			
		||||
        """Create comprehensive human-readable summary report including ALL collected data."""
 | 
			
		||||
        with open(filename, 'w', encoding='utf-8') as f:
 | 
			
		||||
            f.write(f"DNS Reconnaissance Report\n")
 | 
			
		||||
            f.write(f"{'='*50}\n")
 | 
			
		||||
@ -319,201 +371,438 @@ class DNSReconTool:
 | 
			
		||||
            def get_system_records(record_type):
 | 
			
		||||
                return dns_data.get(record_type, {}).get('system', {}).get('records', [])
 | 
			
		||||
            
 | 
			
		||||
            # A Records (IPv4)
 | 
			
		||||
            self._write_dns_section(f, "A Records (IPv4)", get_system_records('A'), 
 | 
			
		||||
                                   lambda r: r.get('data', 'N/A'))
 | 
			
		||||
            # Helper function to get all server records for a type
 | 
			
		||||
            def get_all_server_records(record_type):
 | 
			
		||||
                servers = ['system', '1.1.1.1', '8.8.8.8', '9.9.9.9']
 | 
			
		||||
                results = {}
 | 
			
		||||
                for server in servers:
 | 
			
		||||
                    if record_type in dns_data and server in dns_data[record_type]:
 | 
			
		||||
                        server_data = dns_data[record_type][server]
 | 
			
		||||
                        results[server] = {
 | 
			
		||||
                            'records': server_data.get('records', []),
 | 
			
		||||
                            'raw_output': server_data.get('raw_output', ''),
 | 
			
		||||
                            'record_count': server_data.get('record_count', 0)
 | 
			
		||||
                        }
 | 
			
		||||
                return results
 | 
			
		||||
            
 | 
			
		||||
            # AAAA Records (IPv6)  
 | 
			
		||||
            self._write_dns_section(f, "AAAA Records (IPv6)", get_system_records('AAAA'),
 | 
			
		||||
                                   lambda r: r.get('data', 'N/A'))
 | 
			
		||||
            # A Records (IPv4) with TTL and all servers
 | 
			
		||||
            f.write(f"\nA Records (IPv4):\n")
 | 
			
		||||
            f.write("-" * 16 + "\n")
 | 
			
		||||
            a_servers = get_all_server_records('A')
 | 
			
		||||
            if any(server_data['records'] for server_data in a_servers.values()):
 | 
			
		||||
                for server, server_data in a_servers.items():
 | 
			
		||||
                    records = server_data['records']
 | 
			
		||||
                    if records:
 | 
			
		||||
                        f.write(f"  {server}:\n")
 | 
			
		||||
                        for record in records:
 | 
			
		||||
                            ip = record.get('data', 'N/A')
 | 
			
		||||
                            ttl = record.get('ttl', 'N/A') if record.get('ttl') else 'Not shown'
 | 
			
		||||
                            f.write(f"    {ip} (TTL: {ttl})\n")
 | 
			
		||||
                    elif server_data['raw_output'].startswith('Error:'):
 | 
			
		||||
                        f.write(f"  {server}: {server_data['raw_output']}\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {server}: No records found\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write("  No A records found on any server\n")
 | 
			
		||||
            
 | 
			
		||||
            # MX Records (Mail Servers)
 | 
			
		||||
            # AAAA Records (IPv6) with TTL and all servers
 | 
			
		||||
            f.write(f"\nAAAA Records (IPv6):\n")
 | 
			
		||||
            f.write("-" * 17 + "\n")
 | 
			
		||||
            aaaa_servers = get_all_server_records('AAAA')
 | 
			
		||||
            if any(server_data['records'] for server_data in aaaa_servers.values()):
 | 
			
		||||
                for server, server_data in aaaa_servers.items():
 | 
			
		||||
                    records = server_data['records']
 | 
			
		||||
                    if records:
 | 
			
		||||
                        f.write(f"  {server}:\n")
 | 
			
		||||
                        for record in records:
 | 
			
		||||
                            ipv6 = record.get('data', 'N/A')
 | 
			
		||||
                            ttl = record.get('ttl', 'N/A') if record.get('ttl') else 'Not shown'
 | 
			
		||||
                            f.write(f"    {ipv6} (TTL: {ttl})\n")
 | 
			
		||||
                    elif server_data['raw_output'].startswith('Error:'):
 | 
			
		||||
                        f.write(f"  {server}: {server_data['raw_output']}\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {server}: No records found\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write("  No AAAA records found on any server\n")
 | 
			
		||||
            
 | 
			
		||||
            # MX Records (Mail Servers) with TTL
 | 
			
		||||
            mx_records = get_system_records('MX')
 | 
			
		||||
            f.write(f"\nMX Records (Mail Servers):\n")
 | 
			
		||||
            f.write("-" * 26 + "\n")
 | 
			
		||||
            if mx_records:
 | 
			
		||||
                f.write(f"\nMX Records (Mail Servers):\n")
 | 
			
		||||
                for record in mx_records:
 | 
			
		||||
                    data_parts = record.get('data', '').split()
 | 
			
		||||
                    priority = data_parts[0] if data_parts else 'N/A'
 | 
			
		||||
                    server = ' '.join(data_parts[1:]) if len(data_parts) > 1 else 'N/A'
 | 
			
		||||
                    f.write(f"  Priority {priority}: {server}\n")
 | 
			
		||||
                    ttl = record.get('ttl', 'N/A') if record.get('ttl') else 'Not shown'
 | 
			
		||||
                    f.write(f"  Priority {priority}: {server} (TTL: {ttl})\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nMX Records (Mail Servers): None found\n")
 | 
			
		||||
                f.write("  No MX records found\n")
 | 
			
		||||
            
 | 
			
		||||
            # NS Records (Name Servers)
 | 
			
		||||
            self._write_dns_section(f, "NS Records (Name Servers)", get_system_records('NS'),
 | 
			
		||||
                                   lambda r: r.get('data', 'N/A'))
 | 
			
		||||
            # NS Records (Name Servers) with TTL
 | 
			
		||||
            ns_records = get_system_records('NS')
 | 
			
		||||
            f.write(f"\nNS Records (Name Servers):\n")
 | 
			
		||||
            f.write("-" * 26 + "\n")
 | 
			
		||||
            if ns_records:
 | 
			
		||||
                for record in ns_records:
 | 
			
		||||
                    ns = record.get('data', 'N/A')
 | 
			
		||||
                    ttl = record.get('ttl', 'N/A') if record.get('ttl') else 'Not shown'
 | 
			
		||||
                    f.write(f"  {ns} (TTL: {ttl})\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write("  No NS records found\n")
 | 
			
		||||
            
 | 
			
		||||
            # CNAME Records
 | 
			
		||||
            self._write_dns_section(f, "CNAME Records", get_system_records('CNAME'),
 | 
			
		||||
                                   lambda r: f"{r.get('name', 'N/A')} -> {r.get('data', 'N/A')}")
 | 
			
		||||
            # CNAME Records with TTL
 | 
			
		||||
            cname_records = get_system_records('CNAME')
 | 
			
		||||
            f.write(f"\nCNAME Records:\n")
 | 
			
		||||
            f.write("-" * 14 + "\n")
 | 
			
		||||
            if cname_records:
 | 
			
		||||
                for record in cname_records:
 | 
			
		||||
                    name = record.get('name', 'N/A')
 | 
			
		||||
                    target = record.get('data', 'N/A')
 | 
			
		||||
                    ttl = record.get('ttl', 'N/A') if record.get('ttl') else 'Not shown'
 | 
			
		||||
                    f.write(f"  {name} -> {target} (TTL: {ttl})\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write("  No CNAME records found\n")
 | 
			
		||||
            
 | 
			
		||||
            # TXT Records
 | 
			
		||||
            # TXT Records with categorization and TTL
 | 
			
		||||
            txt_records = get_system_records('TXT')
 | 
			
		||||
            f.write(f"\nTXT Records:\n")
 | 
			
		||||
            f.write("-" * 12 + "\n")
 | 
			
		||||
            if txt_records:
 | 
			
		||||
                f.write(f"\nTXT Records:\n")
 | 
			
		||||
                for record in txt_records:
 | 
			
		||||
                    txt_data = record.get('data', '').strip()
 | 
			
		||||
                    ttl = record.get('ttl', 'N/A') if record.get('ttl') else 'Not shown'
 | 
			
		||||
                    
 | 
			
		||||
                    # Clean up quoted text
 | 
			
		||||
                    if txt_data.startswith('"') and txt_data.endswith('"'):
 | 
			
		||||
                        txt_data = txt_data[1:-1]
 | 
			
		||||
                    
 | 
			
		||||
                    # Identify common TXT record types
 | 
			
		||||
                    if txt_data.startswith('v=spf1'):
 | 
			
		||||
                        f.write(f"  [SPF] {txt_data}\n")
 | 
			
		||||
                        f.write(f"  [SPF] {txt_data} (TTL: {ttl})\n")
 | 
			
		||||
                    elif txt_data.startswith('v=DMARC1'):
 | 
			
		||||
                        f.write(f"  [DMARC] {txt_data}\n")
 | 
			
		||||
                        f.write(f"  [DMARC] {txt_data} (TTL: {ttl})\n")
 | 
			
		||||
                    elif txt_data.startswith('v=DKIM1'):
 | 
			
		||||
                        f.write(f"  [DKIM] {txt_data}\n")
 | 
			
		||||
                        f.write(f"  [DKIM] {txt_data} (TTL: {ttl})\n")
 | 
			
		||||
                    elif 'google-site-verification' in txt_data:
 | 
			
		||||
                        f.write(f"  [Google Verification] {txt_data[:50]}...\n")
 | 
			
		||||
                        f.write(f"  [Google Verification] {txt_data[:50]}... (TTL: {ttl})\n")
 | 
			
		||||
                    elif '_domainkey' in txt_data:
 | 
			
		||||
                        f.write(f"  [Domain Key] {txt_data} (TTL: {ttl})\n")
 | 
			
		||||
                    elif 'facebook-domain-verification' in txt_data:
 | 
			
		||||
                        f.write(f"  [Facebook Verification] {txt_data[:50]}... (TTL: {ttl})\n")
 | 
			
		||||
                    elif txt_data.startswith('MS='):
 | 
			
		||||
                        f.write(f"  [Microsoft Verification] {txt_data} (TTL: {ttl})\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {txt_data}\n")
 | 
			
		||||
                        f.write(f"  {txt_data} (TTL: {ttl})\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nTXT Records: None found\n")
 | 
			
		||||
                f.write("  No TXT records found\n")
 | 
			
		||||
            
 | 
			
		||||
            # CAA Records (Certificate Authority Authorization)
 | 
			
		||||
            # CAA Records (Certificate Authority Authorization) with TTL
 | 
			
		||||
            caa_records = get_system_records('CAA')
 | 
			
		||||
            f.write(f"\nCAA Records (Certificate Authority Authorization):\n")
 | 
			
		||||
            f.write("-" * 48 + "\n")
 | 
			
		||||
            if caa_records:
 | 
			
		||||
                f.write(f"\nCAA Records (Certificate Authority Authorization):\n")
 | 
			
		||||
                for record in caa_records:
 | 
			
		||||
                    data_parts = record.get('data', '').split()
 | 
			
		||||
                    ttl = record.get('ttl', 'N/A') if record.get('ttl') else 'Not shown'
 | 
			
		||||
                    if len(data_parts) >= 3:
 | 
			
		||||
                        flags = data_parts[0]
 | 
			
		||||
                        tag = data_parts[1]
 | 
			
		||||
                        value = ' '.join(data_parts[2:]).strip('"')
 | 
			
		||||
                        f.write(f"  {flags} {tag} {value}\n")
 | 
			
		||||
                        f.write(f"  {flags} {tag} {value} (TTL: {ttl})\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {record.get('data', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"  {record.get('data', 'N/A')} (TTL: {ttl})\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nCAA Records: None found\n")
 | 
			
		||||
                f.write("  No CAA records found\n")
 | 
			
		||||
            
 | 
			
		||||
            # SRV Records
 | 
			
		||||
            # SRV Records with TTL
 | 
			
		||||
            srv_records = get_system_records('SRV')
 | 
			
		||||
            f.write(f"\nSRV Records (Service Records):\n")
 | 
			
		||||
            f.write("-" * 30 + "\n")
 | 
			
		||||
            if srv_records:
 | 
			
		||||
                f.write(f"\nSRV Records (Service Records):\n")
 | 
			
		||||
                for record in srv_records:
 | 
			
		||||
                    data_parts = record.get('data', '').split()
 | 
			
		||||
                    ttl = record.get('ttl', 'N/A') if record.get('ttl') else 'Not shown'
 | 
			
		||||
                    if len(data_parts) >= 4:
 | 
			
		||||
                        priority, weight, port, target = data_parts[:4]
 | 
			
		||||
                        f.write(f"  {record.get('name', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"    Priority: {priority}, Weight: {weight}\n")
 | 
			
		||||
                        f.write(f"    Port: {port}, Target: {target}\n")
 | 
			
		||||
                        f.write(f"    TTL: {ttl}\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {record.get('data', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"  {record.get('data', 'N/A')} (TTL: {ttl})\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nSRV Records: None found\n")
 | 
			
		||||
                f.write("  No SRV records found\n")
 | 
			
		||||
            
 | 
			
		||||
            # SOA Record (Start of Authority)
 | 
			
		||||
            # PTR Records (Reverse DNS) - MISSING FROM ORIGINAL
 | 
			
		||||
            ptr_records = get_system_records('PTR')
 | 
			
		||||
            f.write(f"\nPTR Records (Reverse DNS):\n")
 | 
			
		||||
            f.write("-" * 26 + "\n")
 | 
			
		||||
            if ptr_records:
 | 
			
		||||
                for record in ptr_records:
 | 
			
		||||
                    ptr_data = record.get('data', 'N/A')
 | 
			
		||||
                    ttl = record.get('ttl', 'N/A') if record.get('ttl') else 'Not shown'
 | 
			
		||||
                    name = record.get('name', 'N/A')
 | 
			
		||||
                    f.write(f"  {name} -> {ptr_data} (TTL: {ttl})\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write("  No PTR records found\n")
 | 
			
		||||
            
 | 
			
		||||
            # SOA Record (Start of Authority) with detailed parsing
 | 
			
		||||
            soa_records = get_system_records('SOA')
 | 
			
		||||
            f.write(f"\nSOA Record (Zone Authority):\n")
 | 
			
		||||
            f.write("-" * 27 + "\n")
 | 
			
		||||
            if soa_records:
 | 
			
		||||
                f.write(f"\nSOA Record (Zone Authority):\n")
 | 
			
		||||
                for record in soa_records:
 | 
			
		||||
                    data_parts = record.get('data', '').split()
 | 
			
		||||
                    ttl = record.get('ttl', 'N/A') if record.get('ttl') else 'Not shown'
 | 
			
		||||
                    if len(data_parts) >= 7:
 | 
			
		||||
                        primary_ns, admin_email = data_parts[:2]
 | 
			
		||||
                        serial, refresh, retry, expire, minimum = data_parts[2:7]
 | 
			
		||||
                        f.write(f"  Primary Name Server: {primary_ns}\n")
 | 
			
		||||
                        f.write(f"  Admin Email: {admin_email}\n")
 | 
			
		||||
                        f.write(f"  Serial: {serial}\n")
 | 
			
		||||
                        f.write(f"  Refresh: {refresh}s, Retry: {retry}s\n")
 | 
			
		||||
                        f.write(f"  Expire: {expire}s, Minimum TTL: {minimum}s\n")
 | 
			
		||||
                        f.write(f"  Serial Number: {serial}\n")
 | 
			
		||||
                        f.write(f"  Refresh Interval: {refresh} seconds\n")
 | 
			
		||||
                        f.write(f"  Retry Interval: {retry} seconds\n")
 | 
			
		||||
                        f.write(f"  Expire Time: {expire} seconds\n")
 | 
			
		||||
                        f.write(f"  Minimum TTL: {minimum} seconds\n")
 | 
			
		||||
                        f.write(f"  Record TTL: {ttl}\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {record.get('data', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"  {record.get('data', 'N/A')} (TTL: {ttl})\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nSOA Record: None found\n")
 | 
			
		||||
                f.write("  No SOA record found\n")
 | 
			
		||||
            
 | 
			
		||||
            # DNSSEC Information
 | 
			
		||||
            # DNSSEC Information with detailed analysis
 | 
			
		||||
            dnssec_data = dns_data.get('DNSSEC', {}).get('system', {})
 | 
			
		||||
            dnssec_output = dnssec_data.get('raw_output', '')
 | 
			
		||||
            f.write(f"\nDNSSEC Status:\n")
 | 
			
		||||
            f.write("-" * 14 + "\n")
 | 
			
		||||
            if dnssec_output and not dnssec_output.startswith('Error:') and dnssec_output.strip():
 | 
			
		||||
                f.write(f"\nDNSSEC Status:\n")
 | 
			
		||||
                f.write("-" * 14 + "\n")
 | 
			
		||||
                if 'RRSIG' in dnssec_output or 'DNSKEY' in dnssec_output:
 | 
			
		||||
                    f.write(f"  ✅ DNSSEC is enabled\n")
 | 
			
		||||
                if 'RRSIG' in dnssec_output:
 | 
			
		||||
                    f.write("  ✅ DNSSEC is enabled (RRSIG records found)\n")
 | 
			
		||||
                elif 'DNSKEY' in dnssec_output:
 | 
			
		||||
                    f.write("  ✅ DNSSEC keys present (DNSKEY records found)\n")
 | 
			
		||||
                elif 'NSEC' in dnssec_output or 'NSEC3' in dnssec_output:
 | 
			
		||||
                    f.write("  ✅ DNSSEC authenticated denial (NSEC/NSEC3 found)\n")
 | 
			
		||||
                else:
 | 
			
		||||
                    f.write(f"  ❌ DNSSEC not detected\n")
 | 
			
		||||
                    f.write("  ❓ DNSSEC query returned data but no signatures detected\n")
 | 
			
		||||
                
 | 
			
		||||
                # Show sample DNSSEC records (first few lines)
 | 
			
		||||
                dnssec_lines = [line.strip() for line in dnssec_output.split('\n') if line.strip()]
 | 
			
		||||
                if dnssec_lines:
 | 
			
		||||
                    f.write("  Sample DNSSEC records:\n")
 | 
			
		||||
                    for line in dnssec_lines[:3]:  # Show first 3 lines
 | 
			
		||||
                        f.write(f"    {line}\n")
 | 
			
		||||
                    if len(dnssec_lines) > 3:
 | 
			
		||||
                        f.write(f"    ... and {len(dnssec_lines) - 3} more\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nDNSSEC Status: Unable to determine\n")
 | 
			
		||||
                f.write("  ❌ DNSSEC not detected or query failed\n")
 | 
			
		||||
                if dnssec_output.startswith('Error:'):
 | 
			
		||||
                    f.write(f"  Error: {dnssec_output}\n")
 | 
			
		||||
            
 | 
			
		||||
            # DNS Server Comparison (show discrepancies)
 | 
			
		||||
            f.write(f"\nDNS Server Comparison:\n")
 | 
			
		||||
            f.write("-" * 21 + "\n")
 | 
			
		||||
            # Complete DNS Server Comparison Table
 | 
			
		||||
            f.write(f"\nComplete DNS Server Comparison:\n")
 | 
			
		||||
            f.write("-" * 33 + "\n")
 | 
			
		||||
            self._write_dns_server_comparison(f, dns_data)
 | 
			
		||||
            
 | 
			
		||||
            # Enhanced WHOIS Information
 | 
			
		||||
            # Enhanced WHOIS Information with ALL parsed fields
 | 
			
		||||
            whois_data = results.get('whois', {})
 | 
			
		||||
            f.write(f"\nWHOIS Information (Complete):\n")
 | 
			
		||||
            f.write("-" * 29 + "\n")
 | 
			
		||||
            if whois_data.get('parsed'):
 | 
			
		||||
                f.write(f"\nWHOIS Information\n")
 | 
			
		||||
                f.write("-" * 17 + "\n")
 | 
			
		||||
                parsed = whois_data['parsed']
 | 
			
		||||
                
 | 
			
		||||
                # Domain info
 | 
			
		||||
                for field in ['domain_name', 'domain']:
 | 
			
		||||
                # Group fields by category for better organization
 | 
			
		||||
                domain_fields = ['domain_name', 'domain']
 | 
			
		||||
                registrar_fields = ['registrar', 'sponsoring_registrar', 'registrar_whois_server', 'registrar_url']
 | 
			
		||||
                date_fields = ['creation_date', 'created', 'expiration_date', 'registry_expiry_date', 'expires', 'updated_date', 'changed', 'last_updated']
 | 
			
		||||
                status_fields = ['status', 'domain_status']
 | 
			
		||||
                ns_fields = [k for k in parsed.keys() if 'name_server' in k.lower() or k.lower().startswith('nserver')]
 | 
			
		||||
                contact_fields = [k for k in parsed.keys() if any(x in k.lower() for x in ['registrant', 'admin', 'tech', 'billing'])]
 | 
			
		||||
                
 | 
			
		||||
                # Display organized sections
 | 
			
		||||
                for field in domain_fields:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Domain: {parsed[field]}\n")
 | 
			
		||||
                        f.write(f"  Domain: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                
 | 
			
		||||
                # Registrar info
 | 
			
		||||
                for field in ['registrar', 'sponsoring_registrar']:
 | 
			
		||||
                for field in registrar_fields:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Registrar: {parsed[field]}\n")
 | 
			
		||||
                        f.write(f"  Registrar: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                
 | 
			
		||||
                # Important dates
 | 
			
		||||
                for field in ['creation_date', 'created']:
 | 
			
		||||
                # Show all date fields found
 | 
			
		||||
                for field in date_fields:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Created: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                        
 | 
			
		||||
                for field in ['expiration_date', 'registry_expiry_date', 'expires']:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Expires: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                        
 | 
			
		||||
                for field in ['updated_date', 'changed', 'last_updated']:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Last Updated: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                        field_display = field.replace('_', ' ').title()
 | 
			
		||||
                        f.write(f"  {field_display}: {parsed[field]}\n")
 | 
			
		||||
                
 | 
			
		||||
                # Status
 | 
			
		||||
                for field in ['status', 'domain_status']:
 | 
			
		||||
                for field in status_fields:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Status: {parsed[field]}\n")
 | 
			
		||||
                        f.write(f"  Status: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                
 | 
			
		||||
                # Name servers from WHOIS
 | 
			
		||||
                ns_fields = [k for k in parsed.keys() if 'name_server' in k.lower() or k.lower().startswith('nserver')]
 | 
			
		||||
                if ns_fields:
 | 
			
		||||
                    f.write(f"WHOIS Name Servers:\n")
 | 
			
		||||
                    for field in sorted(ns_fields)[:10]:  # Limit to 10
 | 
			
		||||
                        f.write(f"  {parsed[field]}\n")
 | 
			
		||||
                    f.write(f"  WHOIS Name Servers:\n")
 | 
			
		||||
                    for field in sorted(ns_fields):
 | 
			
		||||
                        value = parsed[field]
 | 
			
		||||
                        if isinstance(value, list):
 | 
			
		||||
                            for ns in value:
 | 
			
		||||
                                f.write(f"    {ns}\n")
 | 
			
		||||
                        else:
 | 
			
		||||
                            f.write(f"    {value}\n")
 | 
			
		||||
                
 | 
			
		||||
                # Show any other significant fields not covered above
 | 
			
		||||
                covered_fields = set(domain_fields + registrar_fields + date_fields + status_fields + ns_fields + contact_fields)
 | 
			
		||||
                other_fields = [k for k in parsed.keys() if k not in covered_fields and not k.startswith('nserver')]
 | 
			
		||||
                if other_fields:
 | 
			
		||||
                    f.write(f"  Other WHOIS Data:\n")
 | 
			
		||||
                    for field in sorted(other_fields)[:10]:  # Limit to prevent spam
 | 
			
		||||
                        field_display = field.replace('_', ' ').title()
 | 
			
		||||
                        value = parsed[field]
 | 
			
		||||
                        if isinstance(value, list):
 | 
			
		||||
                            value = ', '.join(value[:3])  # Show first 3 if list
 | 
			
		||||
                        value_display = value[:100] + '...' if len(str(value)) > 100 else str(value)
 | 
			
		||||
                        f.write(f"    {field_display}: {value_display}\n")
 | 
			
		||||
            
 | 
			
		||||
            # Certificate transparency section
 | 
			
		||||
            raw_whois = whois_data.get('raw', '')
 | 
			
		||||
            if raw_whois.startswith('Error:'):
 | 
			
		||||
                f.write(f"  WHOIS Error: {raw_whois}\n")
 | 
			
		||||
            elif not whois_data.get('parsed'):
 | 
			
		||||
                f.write("  No WHOIS data could be parsed\n")
 | 
			
		||||
            
 | 
			
		||||
            # Certificate Transparency with comprehensive details
 | 
			
		||||
            cert_data = results.get('certificate_transparency', {})
 | 
			
		||||
            f.write(f"\nCertificate Transparency Logs:\n")
 | 
			
		||||
            f.write("-" * 30 + "\n")
 | 
			
		||||
            if cert_data.get('success'):
 | 
			
		||||
                total_certs = cert_data.get('total_certificates', 0)
 | 
			
		||||
                subdomain_count = cert_data.get('subdomain_count', 0)
 | 
			
		||||
                f.write(f"\nSubdomains from Certificate Logs ({subdomain_count} total):\n")
 | 
			
		||||
                f.write("-" * 45 + "\n")
 | 
			
		||||
                f.write(f"  Total Certificates Found: {total_certs}\n")
 | 
			
		||||
                f.write(f"  Unique Subdomains Discovered: {subdomain_count}\n\n")
 | 
			
		||||
                
 | 
			
		||||
                # Show certificate statistics by issuer
 | 
			
		||||
                certificates = cert_data.get('certificates', [])
 | 
			
		||||
                if certificates:
 | 
			
		||||
                    issuers = {}
 | 
			
		||||
                    for cert in certificates:
 | 
			
		||||
                        issuer = cert.get('issuer', 'Unknown')
 | 
			
		||||
                        issuers[issuer] = issuers.get(issuer, 0) + 1
 | 
			
		||||
                    
 | 
			
		||||
                    f.write("  Certificate Issuers:\n")
 | 
			
		||||
                    for issuer, count in sorted(issuers.items(), key=lambda x: x[1], reverse=True):
 | 
			
		||||
                        f.write(f"    {issuer}: {count} certificates\n")
 | 
			
		||||
                    f.write("\n")
 | 
			
		||||
                
 | 
			
		||||
                # Show recent certificates with more details
 | 
			
		||||
                if certificates:
 | 
			
		||||
                    f.write("  Recent SSL Certificates (detailed):\n")
 | 
			
		||||
                    for i, cert in enumerate(certificates[:10]):  # Show top 10
 | 
			
		||||
                        f.write(f"    Certificate #{i+1}:\n")
 | 
			
		||||
                        f.write(f"      ID: {cert.get('id', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      Common Name: {cert.get('common_name', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      Issuer: {cert.get('issuer', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      Valid From: {cert.get('not_before', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      Valid Until: {cert.get('not_after', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      Serial: {cert.get('serial_number', 'N/A')}\n")
 | 
			
		||||
                        
 | 
			
		||||
                        # Show domains covered by this certificate
 | 
			
		||||
                        name_value = cert.get('name_value', '')
 | 
			
		||||
                        if name_value:
 | 
			
		||||
                            domains_in_cert = [d.strip() for d in name_value.split('\n')]
 | 
			
		||||
                            if len(domains_in_cert) > 1:
 | 
			
		||||
                                f.write(f"      Covers {len(domains_in_cert)} domains: {', '.join(domains_in_cert[:5])}")
 | 
			
		||||
                                if len(domains_in_cert) > 5:
 | 
			
		||||
                                    f.write(f" and {len(domains_in_cert) - 5} more")
 | 
			
		||||
                                f.write("\n")
 | 
			
		||||
                        f.write("\n")
 | 
			
		||||
                
 | 
			
		||||
                # Show all discovered subdomains
 | 
			
		||||
                subdomains = cert_data.get('unique_subdomains', [])
 | 
			
		||||
                
 | 
			
		||||
                display_count = min(50, len(subdomains))
 | 
			
		||||
                for subdomain in subdomains[:display_count]:
 | 
			
		||||
                    f.write(f"  {subdomain}\n")
 | 
			
		||||
                
 | 
			
		||||
                if len(subdomains) > display_count:
 | 
			
		||||
                    f.write(f"  ... and {len(subdomains) - display_count} more\n")
 | 
			
		||||
                if subdomains:
 | 
			
		||||
                    f.write(f"  All Discovered Subdomains ({len(subdomains)} total):\n")
 | 
			
		||||
                    for subdomain in subdomains:
 | 
			
		||||
                        f.write(f"    {subdomain}\n")
 | 
			
		||||
            else:
 | 
			
		||||
                error_msg = cert_data.get('message', 'Unknown error')
 | 
			
		||||
                error_detail = cert_data.get('error', '')
 | 
			
		||||
                f.write(f"  Certificate Transparency Query Failed\n")
 | 
			
		||||
                f.write(f"  Error: {error_msg}\n")
 | 
			
		||||
                if error_detail:
 | 
			
		||||
                    f.write(f"  Details: {error_detail}\n")
 | 
			
		||||
            
 | 
			
		||||
            # Shodan section
 | 
			
		||||
            # Enhanced Shodan Results with all available data
 | 
			
		||||
            shodan_data = results.get('shodan', {})
 | 
			
		||||
            if shodan_data.get('success') and shodan_data.get('total_results', 0) > 0:
 | 
			
		||||
                f.write(f"\nShodan Results ({shodan_data.get('total_results', 0)} total):\n")
 | 
			
		||||
                f.write("-" * 25 + "\n")
 | 
			
		||||
                for match in shodan_data.get('matches', [])[:5]:
 | 
			
		||||
                    f.write(f"  IP: {match.get('ip_str', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  Port: {match.get('port', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  Service: {match.get('product', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  Organization: {match.get('org', 'N/A')}\n")
 | 
			
		||||
                    f.write("  ---\n")
 | 
			
		||||
            f.write(f"\nShodan Intelligence:\n")
 | 
			
		||||
            f.write("-" * 19 + "\n")
 | 
			
		||||
            if shodan_data.get('success'):
 | 
			
		||||
                total_results = shodan_data.get('total_results', 0)
 | 
			
		||||
                f.write(f"  Total Shodan Results: {total_results}\n\n")
 | 
			
		||||
                
 | 
			
		||||
                matches = shodan_data.get('matches', [])
 | 
			
		||||
                if matches:
 | 
			
		||||
                    f.write(f"  Detailed Host Information:\n")
 | 
			
		||||
                    for i, match in enumerate(matches):
 | 
			
		||||
                        f.write(f"    Host #{i+1}:\n")
 | 
			
		||||
                        f.write(f"      IP Address: {match.get('ip_str', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      Port: {match.get('port', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      Protocol: {match.get('transport', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      Service: {match.get('product', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      Version: {match.get('version', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      Organization: {match.get('org', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      ISP: {match.get('isp', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"      ASN: {match.get('asn', 'N/A')}\n")
 | 
			
		||||
                        
 | 
			
		||||
                        # Location information
 | 
			
		||||
                        location = match.get('location', {})
 | 
			
		||||
                        if location:
 | 
			
		||||
                            city = location.get('city', 'N/A')
 | 
			
		||||
                            region = location.get('region_code', 'N/A')
 | 
			
		||||
                            country = location.get('country_name', 'N/A')
 | 
			
		||||
                            f.write(f"      Location: {city}, {region}, {country}\n")
 | 
			
		||||
                        
 | 
			
		||||
                        # SSL certificate information
 | 
			
		||||
                        if 'ssl' in match and match['ssl'].get('cert'):
 | 
			
		||||
                            cert = match['ssl']['cert']
 | 
			
		||||
                            f.write(f"      SSL Certificate:\n")
 | 
			
		||||
                            f.write(f"        Subject: {cert.get('subject', {}).get('CN', 'N/A')}\n")
 | 
			
		||||
                            f.write(f"        Issuer: {cert.get('issuer', {}).get('CN', 'N/A')}\n")
 | 
			
		||||
                            f.write(f"        Expires: {cert.get('expires', 'N/A')}\n")
 | 
			
		||||
                        
 | 
			
		||||
                        # HTTP information if available
 | 
			
		||||
                        if 'http' in match:
 | 
			
		||||
                            http = match['http']
 | 
			
		||||
                            if 'title' in http:
 | 
			
		||||
                                f.write(f"      HTTP Title: {http['title'][:100]}{'...' if len(http['title']) > 100 else ''}\n")
 | 
			
		||||
                            if 'server' in http:
 | 
			
		||||
                                f.write(f"      HTTP Server: {http['server']}\n")
 | 
			
		||||
                        
 | 
			
		||||
                        # Hostnames
 | 
			
		||||
                        hostnames = match.get('hostnames', [])
 | 
			
		||||
                        if hostnames:
 | 
			
		||||
                            f.write(f"      Hostnames: {', '.join(hostnames)}\n")
 | 
			
		||||
                        
 | 
			
		||||
                        f.write(f"      Last Updated: {match.get('timestamp', 'N/A')}\n")
 | 
			
		||||
                        f.write("      ---\n")
 | 
			
		||||
                
 | 
			
		||||
                # Show facets if available
 | 
			
		||||
                facets = shodan_data.get('facets', {})
 | 
			
		||||
                if facets:
 | 
			
		||||
                    f.write(f"  Shodan Facets (aggregated data):\n")
 | 
			
		||||
                    for facet_name, facet_data in facets.items():
 | 
			
		||||
                        f.write(f"    {facet_name}:\n")
 | 
			
		||||
                        for item in facet_data:
 | 
			
		||||
                            f.write(f"      {item.get('value', 'N/A')}: {item.get('count', 'N/A')} occurrences\n")
 | 
			
		||||
            else:
 | 
			
		||||
                error_msg = shodan_data.get('message', 'Unknown error')
 | 
			
		||||
                f.write(f"  Shodan Query Status: Failed\n")
 | 
			
		||||
                f.write(f"  Reason: {error_msg}\n")
 | 
			
		||||
                if 'error' in shodan_data:
 | 
			
		||||
                    f.write(f"  Error Details: {shodan_data['error']}\n")
 | 
			
		||||
            
 | 
			
		||||
            f.write(f"\n{'='*50}\n")
 | 
			
		||||
            f.write(f"Report Generation Complete\n")
 | 
			
		||||
            f.write(f"Total sections analyzed: DNS Records, WHOIS, Certificate Transparency, Shodan Intelligence\n")
 | 
			
		||||
 | 
			
		||||
    def save_results(self, domain: str, results: Dict[str, Any]) -> None:
 | 
			
		||||
        """Save results in multiple formats."""
 | 
			
		||||
@ -596,7 +885,7 @@ def main():
 | 
			
		||||
        print("\n⏹️  Reconnaissance interrupted by user")
 | 
			
		||||
        sys.exit(0)
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        print(f"\n❌ Error during reconnaissance: {e}")
 | 
			
		||||
        print(f"❌ Error during reconnaissance: {e}")
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user