1
0
Fork 1
mirror of https://github.com/thatmattlove/hyperglass.git synced 2026-02-07 17:58:24 +00:00
thatmattlove-hyperglass/hyperglass/external/rpki.py

78 lines
2.5 KiB
Python

"""Validate RPKI state via Cloudflare GraphQL API."""
# Standard Library
import typing as t
import requests
# Project
from hyperglass.log import log
from hyperglass.state import use_state
from hyperglass.external._base import BaseExternal
if t.TYPE_CHECKING:
from ipaddress import IPv4Address, IPv6Address
RPKI_STATE_MAP = {
"Invalid": 0,
"invalid": 0,
"Valid": 1,
"valid": 1,
"NotFound": 2,
"notfound": 2,
"not_found": 2,
"not-found": 2,
"Unknown": 2,
"unknown": 2,
"DEFAULT": 3,
}
RPKI_NAME_MAP = {v: k for k, v in RPKI_STATE_MAP.items()}
CACHE_KEY = "hyperglass.external.rpki"
def rpki_state(
prefix: t.Union["IPv4Address", "IPv6Address", str],
asn: t.Union[int, str],
backend: str = "cloudflare",
rpki_server_url: str = "",
) -> int:
"""Get RPKI state and map to expected integer."""
_log = log.bind(prefix=prefix, asn=asn)
_log.debug("Validating RPKI State")
cache = use_state("cache")
state = 3
ro = f"{prefix!s}@{asn!s}"
cached = cache.get_map(CACHE_KEY, ro)
if cached is not None:
state = cached
else:
try:
if backend == "cloudflare":
ql = 'query GetValidation {{ validation(prefix: "{}", asn: {}) {{ state }} }}'
query = ql.format(prefix, asn)
_log.bind(query=query).debug("Cloudflare RPKI GraphQL Query")
with BaseExternal(base_url="https://rpki.cloudflare.com") as client:
response = client._post("/api/graphql", data={"query": query})
validation_state = response["data"]["validation"]["state"]
elif backend == "routinator":
url = f"{rpki_server_url.rstrip('/')}/validity?asn={asn}&prefix={prefix}"
_log.bind(url=url).debug("Routinator RPKI HTTP Query")
response = requests.get(url, timeout=5)
response.raise_for_status()
data = response.json()
validation_state = data["validated_route"]["validity"]["state"]
else:
raise ValueError(f"Unknown RPKI backend: {backend}")
state = RPKI_STATE_MAP.get(validation_state, 3)
cache.set_map_item(CACHE_KEY, ro, state)
except Exception as err:
log.error(err)
state = 3
msg = "RPKI Validation State for {} via AS{} is {}".format(prefix, asn, RPKI_NAME_MAP[state])
if cached is not None:
msg += " [CACHED]"
log.debug(msg)
return state