Created
September 4, 2025 12:28
-
-
Save 2S1one/6bada56c6a4f859472a030bf2cb53351 to your computer and use it in GitHub Desktop.
Resolves all hostnames from a given file and groups the results as: IP → list of hostnames.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # requires: dnspython | |
| import argparse | |
| import dns.resolver | |
| from collections import defaultdict | |
| def read_hostnames_from_file(path: str) -> list[str]: | |
| with open(path, 'r') as f: | |
| return [line.strip() for line in f if line.strip()] | |
| def resolve_hostname_ipv4_only(hostname: str, resolve_single_ip: bool, timeout: float = 3.0) -> list[str]: | |
| resolver = dns.resolver.Resolver() | |
| resolver.lifetime = timeout | |
| resolver.timeout = timeout | |
| try: | |
| answers = resolver.resolve(hostname, 'A') | |
| ips = [rdata.to_text() for rdata in answers] | |
| return ips[:1] if resolve_single_ip else ips | |
| except dns.exception.DNSException: | |
| return [] | |
| def resolve_hostnames(hostnames: list[str], resolve_single_ip: bool) -> tuple[dict[str, list[str]], list[str]]: | |
| ip_to_hostnames = defaultdict(list) | |
| unresolved = [] | |
| for hostname in hostnames: | |
| ips = resolve_hostname_ipv4_only(hostname, resolve_single_ip) | |
| if not ips: | |
| unresolved.append(hostname) | |
| continue | |
| for ip in ips: | |
| ip_to_hostnames[ip].append(hostname) | |
| return ip_to_hostnames, unresolved | |
| def print_mapping(ip_to_hostnames: dict[str, list[str]]): | |
| for ip in sorted(ip_to_hostnames.keys()): | |
| hostnames = sorted(ip_to_hostnames[ip]) | |
| line = ', '.join(hostnames) | |
| print(f"{ip:<15} {line}") | |
| def print_stats(input_hostnames: list[str], ip_to_hostnames: dict[str, list[str]], unresolved: list[str]): | |
| print("\nStatistics:") | |
| print(f"\tTotalInputHostNames : {len(input_hostnames)}") | |
| print(f"\tSuccessfullyResolvedHostNames : {len(input_hostnames) - len(unresolved)}") | |
| print(f"\tResolvedIPsRawCount : {sum(len(v) for v in ip_to_hostnames.values())}") | |
| print(f"\tResolvedIPsUniqueCount : {len(ip_to_hostnames)}") | |
| def print_unresolved(unresolved: list[str]): | |
| if not unresolved: | |
| return | |
| print("\nUnresolved Hostnames:") | |
| for hostname in sorted(unresolved): | |
| print(f"\t{hostname}") | |
| def main(): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("file", help="File with hostnames") | |
| parser.add_argument("--resolve-single-ip", action="store_true", help="Resolve only one IPv4 per hostname") | |
| args = parser.parse_args() | |
| hostnames = read_hostnames_from_file(args.file) | |
| ip_to_hostnames, unresolved = resolve_hostnames(hostnames, args.resolve_single_ip) | |
| print_mapping(ip_to_hostnames) | |
| print_stats(hostnames, ip_to_hostnames, unresolved) | |
| print_unresolved(unresolved) | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment