diff --git a/madness b/madness deleted file mode 100755 index 011325f..0000000 --- a/madness +++ /dev/null @@ -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 index b77661a..1ca309b 100644 --- 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))