Files

64 lines
2.0 KiB
Python
Raw Permalink Normal View History

2025-11-18 03:36:49 +08:00
from typing import Dict, List, Any
from dns import resolver, exception
def resolve_cname(hostname: str) -> List[str]:
"""Resolve CNAME records for a hostname and return targets without trailing dots.
If there is no CNAME record, this returns an empty list.
Raises dns.exception.DNSException on resolver errors.
"""
answers = resolver.resolve(hostname, "CNAME")
targets: List[str] = []
for rdata in answers:
# rdata.target may be a Name object; to_text() yields with trailing dot
target = getattr(rdata, "target", None)
if target is None:
# some dnspython versions use .to_text() directly on rdata
text = rdata.to_text()
else:
text = target.to_text()
targets.append(text.rstrip("."))
return targets
def check_cname_map(cname_map: Dict[str, str]) -> List[Dict[str, Any]]:
"""Check a mapping of hostname -> expected CNAME target.
Returns a list of result dicts: {
'hostname': str,
'expected': str,
'actual': List[str],
'ok': bool,
'error': Optional[str]
}
"""
results: List[Dict[str, Any]] = []
for hostname, expected in cname_map.items():
expected_norm = expected.rstrip(".").lower()
try:
actual_targets = resolve_cname(hostname)
actual_norm = [t.lower() for t in actual_targets]
ok = expected_norm in actual_norm
results.append({
"hostname": hostname,
"expected": expected,
"actual": actual_targets,
"ok": ok,
"error": None,
})
except exception.DNSException as e:
results.append({
"hostname": hostname,
"expected": expected,
"actual": [],
"ok": False,
"error": str(e),
})
return results
def bytes_to_gb(num_bytes: int) -> float:
"""Convert bytes to gigabytes (GB, 1024^3)."""
return round(num_bytes / (1024 ** 3), 3)