Skip to content

Instantly share code, notes, and snippets.

@2S1one
Created September 4, 2025 12:28
Show Gist options
  • Select an option

  • Save 2S1one/6bada56c6a4f859472a030bf2cb53351 to your computer and use it in GitHub Desktop.

Select an option

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.
# 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