import ipaddress from urllib.parse import urlsplit import dns.exception import dns.resolver class AddressResolutionError(Exception): pass class NonPublicAddressError(Exception): pass def ensure_public_url(url: str) -> None: hostname = urlsplit(url).hostname if hostname is None: raise NonPublicAddressError("URL has no hostname") try: answers = dns.resolver.resolve_name(hostname) except dns.exception.DNSException as exc: raise AddressResolutionError( f"Could not resolve hostname {hostname!r}" ) from exc addresses = {ipaddress.ip_address(address) for address in answers.addresses()} if not addresses: raise AddressResolutionError(f"Hostname {hostname!r} did not resolve") if any(not address.is_global for address in addresses): raise NonPublicAddressError( f"Hostname {hostname!r} resolves to a non-public address" )