commit 37157fb8b89ac2ac79ca11227f07754b9383a770 Author: acidvegas Date: Thu Nov 23 03:08:28 2023 -0500 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..350b796 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# PTR Stream + +## More to come diff --git a/ptrstream.py b/ptrstream.py new file mode 100644 index 0000000..d1d4e89 --- /dev/null +++ b/ptrstream.py @@ -0,0 +1,106 @@ +#/usr/bin/env python +# ptrstream - developed by acidvegas in python (https://git.acid.vegas/ptrstream) + +import argparse +import asyncio +import ipaddress +import random +import time +import urllib.request + +try: + import aiodns +except ImportError: + raise ImportError('missing required \'aiodns\' library (pip install aiodns)') + + +def get_dns_servers() -> list: + '''Get a list of DNS servers to use for lookups.''' + source = urllib.request.urlopen('https://public-dns.info/nameservers.txt') + results = source.read().decode().split('\n') + return [server for server in results if ':' not in server] + + +async def rdns(semaphore: asyncio.Semaphore, ip_address: str, custom_dns_server: str): + ''' + Perform a reverse DNS lookup on an IP address. + + :param ip_address: The IP address to lookup. + :param custom_dns_server: The DNS server to use for lookups. + :param semaphore: A semaphore to limit the number of concurrent lookups. + :param timeout: The timeout for the lookup. + ''' + async with semaphore: + resolver = aiodns.DNSResolver(nameservers=[custom_dns_server], rotate=False, timeout=args.timeout) + 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 + + +def rig(seed: int) -> str: + ''' + Random IP generator. + + :param seed: The seed to use for the random number generator. + ''' + max_value = 256**4 + random.seed(seed) + for _ in range(max_value): + shuffled_index = random.randint(0, max_value - 1) + ip = ipaddress.ip_address(shuffled_index) + yield str(ip) + + +async def main(): + '''Generate random IPs and perform reverse DNS lookups.''' + semaphore = asyncio.Semaphore(args.concurrency) + tasks = [] + results_cache = [] + + while True: + dns_servers = [] + while not dns_servers: + try: + dns_servers = get_dns_servers() + except: + time.sleep(300) + + seed = random.randint(10**9, 10**10 - 1) + ip_generator = rig(seed) + + for ip in ip_generator: + if len(tasks) < args.concurrency: + dns = random.choice(dns_servers) + task = asyncio.create_task(rdns(semaphore, ip, dns)) + tasks.append(task) + else: + done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + tasks = list(pending) + for task in done: + ip, result = task.result() + if result: + for exclude in ('undefined.hostname.localhost', 'localhost', '127.0.0.1'): + if result == exclude: + continue + if not result.endswith('.in-addr.arpa') and result != ('undefined.hostname.localhost') and result != ('localhost.'): + print(f'{ip.ljust(15)} -> {result}') + 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: + file.writelines(f"{record}\n" for record in results_cache) + results_cache = [] + + + +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('-t', '--timeout', type=int, default=5, help='Timeout for DNS lookups.') + args = parser.parse_args() + + asyncio.run(main())