""" DNSDumpster.com integration for domain reconnaissance and DNS mapping. Output uses shared code_block for aligned columns. """ import logging import os import aiohttp import simplematrixbotlib as botlib from plugins.common import html_escape, code_block, collapsible_summary DNSDUMPSTER_API_KEY = os.getenv("DNSDUMPSTER_KEY", "") DNSDUMPSTER_API_BASE = "https://api.dnsdumpster.com" async def handle_command(room, message, bot, prefix, config): match = botlib.MessageMatch(room, message, bot, prefix) if match.is_not_from_this_bot() and match.prefix() and match.command("dnsdumpster"): if not DNSDUMPSTER_API_KEY: await bot.api.send_text_message(room.room_id, "DNSDumpster API key not configured. Set DNSDUMPSTER_KEY in .env.") return args = match.args() if len(args) < 1: await show_usage(room, bot) return if args[0].lower() == "test": await test_dnsdumpster_connection(room, bot) else: domain = args[0].lower().strip() await dnsdumpster_domain_lookup(room, bot, domain) async def show_usage(room, bot): usage = """🔍 DNSDumpster Commands: !dnsdumpster <domain_name> - Get comprehensive DNS reconnaissance for a domain !dnsdumpster test - Test API connection """ await bot.api.send_markdown_message(room.room_id, usage) async def test_dnsdumpster_connection(room, bot): test_domain = "google.com" try: url = f"{DNSDUMPSTER_API_BASE}/domain/{test_domain}" headers = {"X-API-Key": DNSDUMPSTER_API_KEY} async with aiohttp.ClientSession() as session: async with session.get(url, headers=headers, timeout=15) as response: status = response.status debug_info = f"🔧 DNSDumpster API Test
Status Code: {status}
" if status == 200: data = await response.json() debug_info += "✅ SUCCESS
" if data.get('a'): debug_info += f"A Records Found: {len(data['a'])}
" elif status == 401: debug_info += "❌ Unauthorized - Invalid API key
" elif status == 429: debug_info += "⚠️ Rate Limit Exceeded
" else: debug_info += f"❌ Error: {status}
" await bot.api.send_markdown_message(room.room_id, debug_info) except Exception as e: await bot.api.send_text_message(room.room_id, f"Test failed: {str(e)}") async def dnsdumpster_domain_lookup(room, bot, domain): safe_domain = html_escape(domain) try: await bot.api.send_text_message(room.room_id, f"🔍 Processing DNS reconnaissance for {safe_domain}...") url = f"{DNSDUMPSTER_API_BASE}/domain/{domain}" headers = {"X-API-Key": DNSDUMPSTER_API_KEY} async with aiohttp.ClientSession() as session: async with session.get(url, headers=headers, timeout=30) as response: if response.status != 200: await bot.api.send_text_message(room.room_id, f"API error: {response.status}") return data = await response.json() sections = [] # A Records if data.get('a'): rows = [] for rec in data['a']: host = rec.get('host', 'N/A') ips = ', '.join(ip.get('ip', '') for ip in rec.get('ips', [])) rows.append(("📍", host, ips)) sections.append({"title": "A Records (IPv4)", "rows": rows}) # NS Records if data.get('ns'): rows = [] for rec in data['ns']: host = rec.get('host', 'N/A') ips = ', '.join(ip.get('ip', '') for ip in rec.get('ips', [])) rows.append(("🖧", host, ips)) sections.append({"title": "NS Records", "rows": rows}) # MX Records if data.get('mx'): rows = [] for rec in data['mx']: host = rec.get('host', 'N/A') ips = ', '.join(ip.get('ip', '') for ip in rec.get('ips', [])) rows.append(("📧", host, ips)) sections.append({"title": "MX Records", "rows": rows}) # CNAME if data.get('cname'): rows = [] for rec in data['cname']: host = rec.get('host', 'N/A') target = rec.get('target', 'N/A') rows.append(("🔀", host, target)) sections.append({"title": "CNAME Records", "rows": rows}) # TXT if data.get('txt'): rows = [] for txt in data['txt']: rows.append(("📄", "TXT", txt[:150] if len(txt) > 150 else txt)) sections.append({"title": "TXT Records", "rows": rows}) if not sections: await bot.api.send_text_message(room.room_id, "No DNS records found.") return block = code_block(f"🔍 DNSDumpster Report: {safe_domain}", sections) output = collapsible_summary(f"🔍 DNSDumpster Report: {safe_domain}", block) await bot.api.send_markdown_message(room.room_id, output) except aiohttp.ClientError as e: await bot.api.send_text_message(room.room_id, f"Error: {e}") # --------------------------------------------------------------------------- # Plugin Metadata # --------------------------------------------------------------------------- __version__ = "1.0.2" __author__ = "Funguy Bot" __description__ = "DNSDumpster domain reconnaissance" __help__ = """
!dnsdumpster – Comprehensive DNS mapping via DNSDumpster

Requires DNSDUMPSTER_KEY env var.

"""