Files
FunguyBot/plugins/dnsdumpster.py
T

147 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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 = """<strong>🔍 DNSDumpster Commands:</strong>
<strong>!dnsdumpster &lt;domain_name&gt;</strong> - Get comprehensive DNS reconnaissance for a domain
<strong>!dnsdumpster test</strong> - 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"<strong>🔧 DNSDumpster API Test</strong><br>Status Code: {status}<br>"
if status == 200:
data = await response.json()
debug_info += "<strong>✅ SUCCESS</strong><br>"
if data.get('a'):
debug_info += f"A Records Found: {len(data['a'])}<br>"
elif status == 401:
debug_info += "<strong>❌ Unauthorized - Invalid API key</strong><br>"
elif status == 429:
debug_info += "<strong>⚠️ Rate Limit Exceeded</strong><br>"
else:
debug_info += f"<strong>❌ Error:</strong> {status}<br>"
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__ = """
<details>
<summary><strong>!dnsdumpster</strong> Comprehensive DNS mapping via DNSDumpster</summary>
<ul>
<li><code>!dnsdumpster &lt;domain&gt;</code> Full recon</li>
<li><code>!dnsdumpster test</code> Test API connection</li>
</ul>
<p>Requires <strong>DNSDUMPSTER_KEY</strong> env var.</p>
</details>
"""