import argparse from typing import List import dns.message import dns.query from dns.resolver import resolve, NXDOMAIN from dns.rcode import Rcode def get_resolvers(tld: str) -> List[str] | None: try: answers = resolve(tld, 'NS') except NXDOMAIN: return return [resolve(i.target, 'A')[0].address for i in answers] def name_exists(name: str, resolver: str) -> bool: msg = dns.message.make_query(name, 'NS') answer_msg = dns.query.udp(msg, resolver) return answer_msg.rcode() == Rcode.NOERROR def main(tld: str, min_num: int, max_num: int) -> int: resolvers = get_resolvers(tld) if resolvers is None: print(f"Unknown TLD: {tld}") return 0 print(f"Scanning TLD '{tld}' with {len(resolvers)} rootservers") run_loop(tld, min_num, max_num, resolvers) def run_loop(tld: str, min_num: int, max_num: int, resolvers: List[str]): global name for i in range(min_num, max_num): name = f'{i}.{tld}' resolver = resolvers[i % len(resolvers)] if not name_exists(name, resolver): print(name) try: input('Press Enter to continue, or Ctrl+C to skip TLD') except KeyboardInterrupt: print('') return print(f"No free domains found in range {min_num} - {max_num} for TLD: {tld}") if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('-m', '--min', help='Min number', type=int, default=10) parser.add_argument('--max', help='Max number', type=int, default=10000) parser.add_argument('tld', help='TLD', nargs='+') args = parser.parse_args() try: for tld in args.tld: if main(tld, args.min, args.max) == 1: break except KeyboardInterrupt: print(f"You interrupted at {name}")