ptrstream

- Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.acid.vegas/-c.git
Log | Files | Refs | Archive | README

commit eb981f795081a0b6a4da3542dbb776dd66c1498d
parent ad6febaf7e56a1ba70e8e5966f9cee1846d769c1
Author: acidvegas <acid.vegas@acid.vegas>
Date: Fri, 1 Dec 2023 19:19:27 -0500

Improved overall code, added more verbosity and memory control

Diffstat:
Dmadness | 35-----------------------------------
Mptrstream.py | 48++++++++++++++++++++++++++++++------------------

2 files changed, 30 insertions(+), 53 deletions(-)

diff --git a/madness b/madness
@@ -1,35 +0,0 @@
-#!/bin/bash
-
-TIMEOUT=2
-
-genip() {
-    num_octets=$((RANDOM % 4 + 1))
-    ip=""
-    for i in $(seq 1 $num_octets); do
-        if [ $i -ne 1 ]; then
-            ip+="."
-        fi
-        ip+=$((RANDOM % 256))
-    done
-    echo $ip
-}
-
-TEMP=$(mktemp -d)
-while true; do
-    ip=$(genip)
-    ns_records=$(dig +time=$TIMEOUT +short $ip.in-addr.arpa NS)
-    for ns in $ns_records; do
-        ns_ips=$(dig +time=$TIMEOUT +short $ns A $ns AAAA)
-        for ns_ip in $ns_ips; do
-            #echo -e "AXFR on \033[36m${ns%.}\033[0m \033[90m($ns_ip)\033[0m for \033[33m$ip.in-addr.arpa\033[0m"
-            dig AXFR @$ns_ip $ip.in-addr.arpa > $TEMP/$ip.in-addr.arpa.txt
-            if [ ! -s "$zone_file" ] || grep -qE "Transfer failed|connection reset|connection refused" "$zone_file"; then
-                echo -e "\033[31m[FAIL]\033[0m AXFR on \033[36m${ns%.}\033[0m \033[90m($ns_ip)\033[0m for \033[33m$ip.in-addr.arpa\033[0m"
-                rm -f "$zone_file"
-            else
-                echo -e "\033[32m[SUCCESS]\033[0m AXFR on \033[36m${ns%.}\033[0m \033[90m($ns_ip)\033[0m for \033[33m$ip.in-addr.arpa\033[0m"
-                break
-            fi
-        done
-    done
-done
diff --git a/ptrstream.py b/ptrstream.py
@@ -14,15 +14,18 @@ try:
 except ImportError:
 	raise ImportError('missing required \'aiodns\' library (pip install aiodns)')
 
+# Do not store these in the results file
+bad_hosts = ['localhost','undefined.hostname.localhost','unknown']
+
 # Colors
 class colors:
 	ip        = '\033[35m'
 	ip_match  = '\033[96m' # IP address mfound within PTR record
 	ptr       = '\033[93m'
-	spooky    = '\033[31m' # .gov or .mil indicator
+	red       = '\033[31m' # .gov or .mil indicator
 	invalid   = '\033[90m'
 	reset     = '\033[0m'
-	separator = '\033[90m'
+	grey      = '\033[90m'
 
 
 def get_dns_servers() -> list:
@@ -43,9 +46,19 @@ async def rdns(semaphore: asyncio.Semaphore, ip_address: str, resolver: aiodns.D
 		reverse_name = ipaddress.ip_address(ip_address).reverse_pointer
 		try:
 			answer = await resolver.query(reverse_name, 'PTR')
-			return ip_address, answer.name
-		except:
-			return ip_address, None
+			if answer.name not in bad_hosts and answer.name != ip_address and answer.name != reverse_name:
+				return ip_address, answer.name, True
+			else:
+				return ip_address, answer.name, False
+		except aiodns.error.DNSError as e:
+			if e.args[0] == aiodns.error.ARES_ENOTFOUND:
+				return ip_address, f'{colors.red}No rDNS found{colors.reset}', False
+			elif e.args[0] == aiodns.error.ARES_ETIMEOUT:
+				return ip_address, f'{colors.red}DNS query timed out{colors.reset}', False
+			else:
+				return ip_address, f'{colors.red}DNS error{colors.grey} ({e.args[1]}){colors.reset}', False
+		except Exception as e:
+			return ip_address, f'{colors.red}Unknown error{colors.grey} ({str(e)}){colors.reset}', False
 
 
 def rig(seed: int) -> str:
@@ -61,6 +74,7 @@ def rig(seed: int) -> str:
 		ip = ipaddress.ip_address(shuffled_index)
 		yield str(ip)
 
+
 def fancy_print(ip: str, result: str):
 	'''
 	Print the IP address and PTR record in a fancy way.
@@ -68,8 +82,8 @@ def fancy_print(ip: str, result: str):
 	:param ip: The IP address.
 	:param result: The PTR record.
 	'''
-	if result in ('127.0.0.1', 'localhost'):
-		print(f'{colors.ip}{ip.ljust(15)}{colors.reset} {colors.separator}-> {result}{colors.reset}')
+	if result in ('127.0.0.1', 'localhost','undefined.hostname.localhost','unknown'):
+		print(f'{colors.ip}{ip.ljust(15)}{colors.reset} {colors.grey}-> {result}{colors.reset}')
 	else:
 		if ip in result:
 			result = result.replace(ip, f'{colors.ip_match}{ip}{colors.ptr}')
@@ -77,13 +91,9 @@ def fancy_print(ip: str, result: str):
 			result = result.replace(daship, f'{colors.ip_match}{daship}{colors.ptr}')
 		elif (revip := '.'.join(ip.split('.')[::-1])) in result:
 			result = result.replace(revip, f'{colors.ip_match}{revip}{colors.ptr}')
-		elif result.endswith('.gov') or result.endswith('.mil'):
-			result = result.replace('.gov', f'{colors.spooky}.gov{colors.reset}')
-			result = result.replace('.mil', f'{colors.spooky}.mil{colors.reset}')
-		elif '.gov.' in result or '.mil.' in result:
-			result = result.replace('.gov.', f'{colors.spooky}.gov.{colors.ptr}')
-			result = result.replace('.mil.', f'{colors.spooky}.mil.{colors.ptr}')
-	print(f'{colors.ip}{ip.ljust(15)}{colors.reset} {colors.separator}->{colors.reset} {colors.ptr}{result}{colors.reset}')
+		elif (revip := '.'.join(ip.split('.')[::-1]).replace('.','-')) in result:
+			result = result.replace(revip, f'{colors.ip_match}{revip}{colors.ptr}')
+	print(f'{colors.ip}{ip.ljust(15)}{colors.reset} {colors.grey}->{colors.reset} {colors.ptr}{result}{colors.reset}')
 
 
 async def main(args: argparse.Namespace):
@@ -108,7 +118,7 @@ async def main(args: argparse.Namespace):
 	tasks = []
 	results_cache = []
 
-	seed = random.randint(10**9, 10**10 - 1)
+	seed = random.randint(10**9, 10**10 - 1) if not args.seed else args.seed
 	ip_generator = rig(seed)
 
 	for ip in ip_generator:
@@ -119,10 +129,11 @@ async def main(args: argparse.Namespace):
 			done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
 			tasks = list(pending)
 			for task in done:
-				ip, result = task.result()
+				ip, result, success = task.result()
 				if result:
 					fancy_print(ip, result)
-					results_cache.append(f'{ip}:{result}')
+					if success:
+						results_cache.append(f'{ip}:{result}')
 				if len(results_cache) >= 1000:
 					stamp = time.strftime('%Y%m%d')
 					with open(f'ptr_{stamp}_{seed}.txt', 'a') as file:
@@ -133,10 +144,11 @@ async def main(args: argparse.Namespace):
 
 if __name__ == '__main__':
 	parser = argparse.ArgumentParser(description='Perform asynchronous reverse DNS lookups.')
-	parser.add_argument('-c', '--concurrency', type=int, default=50, help='Control the speed of lookups.')
+	parser.add_argument('-c', '--concurrency', type=int, default=100, help='Control the speed of lookups.')
 	parser.add_argument('-t', '--timeout', type=int, default=5, help='Timeout for DNS lookups.')
 	parser.add_argument('-r', '--resolvers', type=str, help='File containing DNS servers to use for lookups.')
 	parser.add_argument('-rt', '--retries', type=int, default=3, help='Number of times to retry a DNS lookup.')
+	parser.add_argument('-s', '--seed', type=int, help='Seed to use for random number generator.')
 	args = parser.parse_args()
 
 	asyncio.run(main(args))