mdaxfr

- Mass DNS AXFR
git clone git://git.acid.vegas/mdaxfr.git
Log | Files | Refs | Archive | README | LICENSE

commit a4987c644734ebfbfa5ec3258901520bfcad518c
parent 31b36e68b4d9ceef7c522d91a53e389b143cba51
Author: acidvegas <acid.vegas@acid.vegas>
Date: Sat, 28 Oct 2023 21:40:06 -0400

Finalized code more, README cleaned up

Diffstat:
MREADME.md | 22+++++++++++++++-------
Maxfr.py | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------

2 files changed, 82 insertions(+), 25 deletions(-)

diff --git a/README.md b/README.md
@@ -1,17 +1,25 @@
 # Mass DNS AXFR (Zone Transfer)
 
-# STILL FINISHING THIS - JUST UPLOADING PROGRESS
+###### This script will attempt a [Zone Transfer](https://en.wikipedia.org/wiki/DNS_zone_transfer) on all of the [Root Nameservers](https://en.wikipedia.org/wiki/Root_name_server) and [Top-level Domains](https://en.wikipedia.org/wiki/Top-level_domain) *(TLDs)*.
+
+## Expectations & Legalities
+Please set realistic expectations when using this tool. In contemporary network configurations, AXFR requests are typically restricted, reflecting best practices in DNS security. While many nameservers now disallow AXFR requests, there may still be occasional instances where configurations permit them. Always exercise due diligence and ensure ethical use.
 
 ## Requirements
-- [dnspython](https://pypi.org/project/dnspython/)
+- [dnspython](https://pypi.org/project/dnspython/) *(`pip install dnspython`)*
 
-## Information
-This script will attempt a [Zone Transfer](https://en.wikipedia.org/wiki/DNS_zone_transfer) on all of the [Root Nameservers](https://en.wikipedia.org/wiki/Root_name_server) and [Top-level Domains](https://en.wikipedia.org/wiki/Top-level_domain) *(TLDs)*.
+## Usage
+| Argument         | Description                                          |
+| ---------------- | ---------------------------------------------------- |
+| `-r`, `--root`   | Perform zone transfer on root nameservers.           |
+| `-t`, `--tld`    | Perform zone transfer on a specific TLD.             |
+| `-ts`, `--tlds`  | Perform zone transfer on all TLDs.                   |
+| `-o`, `--output` | Specify the output directory *(default is axfrout)*. |
 
-Really, I only wrote this to shit on **[this idiot](https://github.com/flotwig/TLDR-2/tree/main)** who took a dead project & brought it back to life by making it even worse. Rather than making a pull request to give this bloke more credit in his "tenure" as a developer, I decided to just rewrite it all from scratch so people can fork off of *clean* code instead.
+## Information
+I only wrote this to shit on **[this bozo](https://github.com/flotwig/TLDR-2/tree/main)** who took a dead project & brought it back to life by making it even worse. Rather than making a pull request to give this bloke more credit in his "tenure" as a developer, I decided to just rewrite it all from scratch so people can fork off of *clean* code instead.
 
-## Notice
-Do not expect insane results. For the most part, AXFR's are not very commonly allowed on nameservers anymore, by you will always catch a few that are not configured to block AXFR requests...
+As a little added bonus, I have began working on a pure POSIX version of this script for protability, which is included in this repository.
 
 ___
 
diff --git a/axfr.py b/axfr.py
@@ -1,7 +1,9 @@
 #!/usr/bin/env python
 # Mass DNS AXFR - developed by acidvegas in python (https://git.acid.vegas/mdaxfr)
 
+import os
 import urllib.request
+import logging
 
 try:
     import dns.rdatatype
@@ -11,32 +13,48 @@ try:
 except ImportError:
     raise SystemExit('missing required \'dnspython\' module (pip install dnspython)')
 
-def tld_axfr(tld: str, nameserver: str):
+def attempt_axfr(tld: str, nameserver: str, filename: str):
     '''
     Perform a DNS zone transfer on a target domain.
     
     :param target: The target domain to perform the zone transfer on.
     :param nameserver: The nameserver to perform the zone transfer on.
+    :param filename: The filename to store the zone transfer results in.
     '''
-    xfr = dns.query.xfr(nameserver, tld+'.', timeout=15)
-    for msg in xfr:
-        for rrset in msg.answer:
-            for rdata in rrset:
-                print(f'{rrset.name}.{tld} {rrset.ttl} {rdata}')
+    temp_file = filename + '.temp'
+    try:
+        nameserver = resolve_nameserver(nameserver)
+    except Exception as ex:
+        logging.error(f'Failed to resolve nameserver {nameserver}: {ex}')
+    else:
+        try:
+            with open(temp_file, 'w') as file:
+                xfr = dns.query.xfr(nameserver, tld+'.', timeout=15)
+                for msg in xfr:
+                    for rrset in msg.answer:
+                        for rdata in rrset:
+                            file.write(f'{rrset.name}.{tld} {rrset.ttl} {rdata}')
+            os.rename(temp_file, filename)
+        except Exception as ex:
+            if os.path.exists(temp_file):
+                os.remove(temp_file)
+            logging.error(f'Failed to perform zone transfer from {nameserver} for {tld}: {ex}')
 
-def get_root_nameservers() -> list: # https://www.internic.net/domain/named.root
+def get_root_nameservers() -> list:
     '''Generate a list of the root nameservers.'''
-    return [f'{root}.rootservers.net' for root in ('abcdefghijklm')]
+    root_ns_records = dns.resolver.resolve('.', 'NS')
+    root_servers = [str(rr.target)[:-1] for rr in root_ns_records]
+    return root_servers
 
 def get_root_tlds() -> list:
     '''Get the root TLDs from IANA.'''
     return urllib.request.urlopen('https://data.iana.org/TLD/tlds-alpha-by-domain.txt').read().decode('utf-8').lower().split('\n')[1:]
 
-def get_tld_nameservers(tld: str) -> list: # https://www.internic.net/domain/root.zone
+def get_tld_nameservers(tld: str) -> list:
     '''Get the nameservers for a TLD.'''    
     return [nameserver for nameserver in dns.resolver.query(tld+'.', 'NS' )]
 
-def resolve_nameserver(nameserver: str):
+def resolve_nameserver(nameserver: str) -> str:
     '''
     Resolve a nameserver to its IP address.
     
@@ -51,16 +69,47 @@ def resolve_nameserver(nameserver: str):
     
 
 if __name__ == '__main__':
+    import argparse
+
+    parser = argparse.ArgumentParser(description='Mass DNS AXFR')
+    parser.add_argument('-r', '--root', action='store_true', help='perform zone transfer on root nameservers')
+    parser.add_argument('-t', '--tld', help='perform zone transfer on a specific TLD')
+    parser.add_argument('-ts', '--tlds', help='perform zone transfer on all TLDs')
+    parser.add_argument('-o', '--output', default='axfrout', help='output directory')
+    args = parser.parse_args()
+
+    os.makedirs(args.output, exist_ok=True) # Create output directory if it doesn't exist
+
+    if args.root:
+        try:
+            for root in get_root_nameservers():
+                try:
+                    attempt_axfr('', root+'.root-servers.net', os.path.join(args.output, root+'-root.txt'))
+                except Exception as e:
+                    logging.error(f'Failed to perform zone transfer from the {root} root server: {e}')
+        except Exception as e:
+            logging.error(f'Failed to get root nameservers: {e}')
 
-    for root in get_root_nameservers():
+    if args.tlds:
         try:
-            xfr = tld_axfr('', root+'.root-servers.net') # Need to store to file in chunks
+            for tld in get_root_tlds():
+                try:
+                    for ns in get_tld_nameservers(tld):
+                        try:
+                            attempt_axfr(tld, ns, os.path.join(args.output, tld+'.txt'))
+                        except Exception as e:
+                            logging.error(f'Failed to perform zone transfer from {ns} for {tld}: {e}')
+                except Exception as e:
+                    logging.error(f'Failed to get nameservers for {tld}: {e}')
         except Exception as e:
-            print(f"Failed to perform zone transfer from the {root} root server: {e}")
+            logging.error(f'Failed to get root TLDs: {e}')
 
-    for tld in get_root_tlds():
+    elif args.tld:
         try:
-            for ns in get_tld_nameservers(tld):
-                xfr = tld_axfr(tld, resolve_nameserver(str(ns))) # Need to store to file in chunks
+            for ns in get_tld_nameservers(args.tld):
+                try:
+                    attempt_axfr(args.tld, ns, os.path.join(args.output, args.tld+'.txt'))
+                except Exception as e:
+                    logging.error(f'Failed to perform zone transfer from {ns} for {args.tld}: {e}')
         except Exception as e:
-            print(f"Failed to resolve {tld}: {e}")
-\ No newline at end of file
+            logging.error(f'Failed to get nameservers for {args.tld}: {e}')
+\ No newline at end of file