import sqlite3 from pathlib import Path from html import escape DB_PATH = "dns.db" OUT_PATH = "dns_report.html" SECTIONS = [ ("domains", "Domains", "SELECT id, name, created_at FROM domains ORDER BY id"), ("dns_a", "A Records", "SELECT id, domain_id, ipv4, ttl FROM dns_a ORDER BY id"), ("dns_aaaa", "AAAA Records", "SELECT id, domain_id, ipv6, ttl FROM dns_aaaa ORDER BY id"), ("dns_cname", "CNAME Records", "SELECT id, domain_id, alias, ttl FROM dns_cname ORDER BY id"), ("dns_mx", "MX Records", "SELECT id, domain_id, priority, mail_server, ttl FROM dns_mx ORDER BY id"), ("dns_ns", "NS Records", "SELECT id, domain_id, nameserver, ttl FROM dns_ns ORDER BY id"), ("dns_txt", "TXT Records", "SELECT id, domain_id, text_value, ttl FROM dns_txt ORDER BY id"), ("dns_srv", "SRV Records", "SELECT id, domain_id, service, protocol, priority, weight, port, target, ttl FROM dns_srv ORDER BY id"), ("dns_ptr", "PTR Records", "SELECT id, domain_id, pointer, ttl FROM dns_ptr ORDER BY id"), ("dns_soa", "SOA Records", "SELECT id, domain_id, primary_ns, admin_email, serial, refresh, retry, expire, minimum, ttl FROM dns_soa ORDER BY id"), ("dns_caa", "CAA Records", "SELECT id, domain_id, flag, tag, value, ttl FROM dns_caa ORDER BY id"), ("dns_spf", "SPF Records", "SELECT id, domain_id, spf_rule, ttl FROM dns_spf ORDER BY id"), ("dns_naptr", "NAPTR Records", "SELECT id, domain_id, order_val, preference, flags, service, regexp, replacement, ttl FROM dns_naptr ORDER BY id"), ("dns_ds", "DS Records", "SELECT id, domain_id, key_tag, algorithm, digest_type, digest, ttl FROM dns_ds ORDER BY id"), ("dns_dnskey", "DNSKEY Records", "SELECT id, domain_id, flags, protocol, algorithm, public_key, ttl FROM dns_dnskey ORDER BY id"), ("dns_tlsa", "TLSA Records", "SELECT id, domain_id, usage, selector, matching_type, certificate_data, ttl FROM dns_tlsa ORDER BY id"), ("dns_svcb", "SVCB/HTTPS", "SELECT id, domain_id, priority, target, params, ttl FROM dns_svcb ORDER BY id"), ] def fetch_table(cursor, query): cursor.execute(query) rows = cursor.fetchall() col_names = [desc[0] for desc in cursor.description] return col_names, rows def render_table_html(title, col_names, rows): if not rows: return f"""

{escape(title)}

No records found.

""" header_cells = "".join(f"{escape(col)}" for col in col_names) body_rows = [] for r in rows: tds = "".join(f"{escape(str(v))}" for v in r) body_rows.append(f"{tds}") body_html = "\n".join(body_rows) return f"""

{escape(title)}

{header_cells} {body_html}
""" def main(): if not Path(DB_PATH).exists(): raise SystemExit(f"Database not found: {DB_PATH}") conn = sqlite3.connect(DB_PATH) cur = conn.cursor() sections_html = [] for table_name, title, query in SECTIONS: try: col_names, rows = fetch_table(cur, query) sections_html.append(render_table_html(title, col_names, rows)) except sqlite3.Error as e: sections_html.append(f"""

{escape(title)}

Error reading table {escape(table_name)}: {escape(str(e))}

""") conn.close() full_html = f""" DNS Database Report

DNS Database Report

Snapshot of all DNS record tables from {escape(DB_PATH)}.

Backend: SQLite Tables: domains + DNS record families Generated: static HTML snapshot
{''.join(sections_html)}
""" Path(OUT_PATH).write_text(full_html, encoding="utf-8") print(f"✅ DNS report written to {OUT_PATH}") if __name__ == "__main__": main()