diff --git a/hyperglass/api/models/validators.py b/hyperglass/api/models/validators.py index a14ab92..88f24ef 100644 --- a/hyperglass/api/models/validators.py +++ b/hyperglass/api/models/validators.py @@ -5,7 +5,7 @@ import re from ipaddress import ip_network # Project -from hyperglass.util import log +from hyperglass.util import log, get_containing_prefix from hyperglass.exceptions import InputInvalid, InputNotAllowed from hyperglass.configuration import params @@ -134,24 +134,10 @@ def validate_ip(value, query_type, query_vrf): # noqa: C901 # For a host query with bgp_route query type and force_cidr # enabled (the default), convert the host query to a network - # query, using the highest allowed prefix length in the VRF's - # access-list for the address-family. + # query. elif query_type in ("bgp_route",) and vrf_afi.force_cidr: - max_le = max( - ace.le - for ace in query_vrf[ip_version].access_list - if ace.action == "permit" - ) - new_ip = valid_ip.supernet(new_prefix=max_le) - log.debug( - "Converted '{o}' to '{n}' for '{q}' query", - o=valid_ip, - n=new_ip, - q=query_type, - ) - - valid_ip = new_ip + valid_ip = get_containing_prefix(valid_ip.network_address) # For a host query with bgp_route query type and force_cidr # disabled, convert the host query to a single IP address. diff --git a/hyperglass/util.py b/hyperglass/util.py index 2439b28..85e86bd 100644 --- a/hyperglass/util.py +++ b/hyperglass/util.py @@ -668,3 +668,43 @@ def parse_exception(exc): else: parsed.append(cause) return ", caused by ".join(parsed) + + +def get_containing_prefix(valid_ip): + """Get containing prefix for an IP host query from RIPEstat API. + + Arguments: + valid_ip {IPv4Address|IPv6Address} -- Valid IP Address object + + Raises: + InputInvalid: Raised if an http error occurs + InputInvalid: Raised if RIPEstat response doesn't contain a prefix. + + Returns: + {IPv4Network|IPv6Network} -- Valid IP Network object + """ + import httpx + from ipaddress import ip_network + from hyperglass.exceptions import InputInvalid + + log.debug("Attempting to find containing prefix for {ip}", ip=str(valid_ip)) + + try: + response = httpx.get( + "https://stat.ripe.net/data/network-info/data.json", + params={"resource": str(valid_ip)}, + ) + except httpx.HTTPError as error: + msg = parse_exception(error) + raise InputInvalid(msg) + + containing = response.json().get("data", {}).get("prefix") + + if containing is None: + raise InputInvalid(f"{str(valid_ip)} has no containing prefix") + + log.debug( + "Found containing prefix '{p}' for IP '{i}'", p=containing, i=str(valid_ip) + ) + + return ip_network(containing)