An API to query historical RPKI data, more specifically, Validated ROA Payloads (VRPs).
Links:
We obtain VRP data from the RPKI Views project and store
it in a compact form for fast access. From each dump we extract the
output/rpki-client.csv
file, which contains just the VRPs, and update our database.
A VRP entry consists of five fields:
ASN,IP Prefix,Max Length,Trust Anchor,Expires
AS13335,1.0.0.0/24,24,apnic,1753280249
We ignore the expiry time and only work on dump-time granularity. For each ingested dump
we compare the set of VRPs (in form of asn, prefix, max_length
) with the previous
dump. Each VRP has a visible
time range, during which is was continuously visible.
Since most VRPs are stable, this allows us to update just the time range, keeping the
database size compact.
Data limitations:
-
High-frequency updates are invisible. Currently, dumps are created roughly every 20 minutes. If a VRP expires / is removed and potentially recreated between dumps, this will not be reflected in the database.
-
Data is at dump-time granularity. If a VRP is created, expires, or is removed between dumps, the exact point in time is lost. For example, if there are two dumps at time
A
andC
, a VRP expires at timeB
(A < B < C
), and a user queries for timestampD
(A < D < B
) then the query will not find the VRP, since its visibility ended atA
. Similarly, VRPs that are only visible in one dump will have equal values for the start and end visibility time. -
Queryable time range is limited. Naturally, we are limited by the amount of available data. Trying queries outside of the available time range will result in an error (to distinguish from non-existent VRPs).
Data sources:
- 2020-12-06 16:37:23 UTC to 2022-06-14 14:54:59 UTC: josephine.sobornost.net
- 2022-06-14 15:08:09 UTC to now: dango.attn.jp
Returns the list of covering VRPs for a prefix at a specific time, time range, or at the latest dump time if no time parameter is specified.
Mandatory:
prefix
: The prefix for which to return covering VRPs.
There are two types of time parameters, which are mutually exclusive: Point-in-time and time range. For a time range only one bound can be specified, in which case the returned list will include all earlier/later data available.
Point-in-time:
timestamp
: The timestamp (in%Y-%m-%dT%H:%M:%S
[assumes UTC] or unix epoch format) for which to return VRPs.
Time range:
timestamp__gte
: The start of the time range (inclusive; in%Y-%m-%dT%H:%M:%S
[assumes UTC] or unix epoch format) for which to return VRPs.timestamp__lte
: The end of the time range (inclusive; in%Y-%m-%dT%H:%M:%S
[assumes UTC] or unix epoch format) for which to return VRPs.
// https://www.ihr.live/rpki-history/api/vrp?prefix=8.8.8.0/24
[
{
"prefix": "8.8.8.0/24",
"asn": 15169,
"max_length": 24,
"visible": {
"from": "2023-12-29T17:30:54+00:00",
"to": "2025-08-13T06:29:10+00:00"
}
}
]
visible
refers to the timespan during which the VRP was continuously visible, i.e.,
present in the dumps. Thus, if a VRP is missing from a dump, a new entry with a separate
visible
range is created. This time is unrelated to the validity time (Not before
/Not after
) of the ROA!
Returns the RPKI status for the specified prefix/ASN combination at the specified time, or at the latest dump time if no timestamp is specified.
Mandatory:
prefix
: The prefix to be checked.asn
: The origin ASN of the prefix.
Optional:
timestamp
: The timestamp (in%Y-%m-%dT%H:%M:%S
[assumes UTC] or unix epoch format) for which to check the status. If omitted, use the latest available dump time.
// https://www.ihr.live/rpki-history/api/status?prefix=8.8.8.0/24&asn=15169
{
"status": "Valid"
}
// https://www.ihr.live/rpki-history/api/status?prefix=8.8.8.0/25&asn=15169
{
"status": "Invalid",
"reason": {
"code": "moreSpecific",
"description": "Covering VRP with matching origin ASN found, but queried prefix is more specific than maxLength attribute allows."
}
}
status
is one of [Valid, Invalid, NotFound]
.
reason
(only for Invalid
status) gives more detailed information about why the
status is invalid. code
is for automatic processing, while description
provides a
human-readable explanation.
Returns the list of dumps contained in the database. Since this list is very long, this endpoint is paginated and returns at most 10000 results per page.
Mandatory: None
Optional:
timestamp__gte
: The start of the time range (inclusive; in%Y-%m-%dT%H:%M:%S
[assumes UTC] or unix epoch format) for which to return data.timestamp__lte
: The end of the time range (inclusive; in%Y-%m-%dT%H:%M:%S
[assumes UTC] or unix epoch format) for which to return data.page
: The page number to load (defaults to 1).page_size
: The number of results to include in one page (defaults to 10000).
// https://www.ihr.live/rpki-history/api/metadata
{
"next": "https://www.ihr.live/rpki-history/api/metadata?page_size=1000&page=2",
"results": [
{
"timestamp": "2020-12-06T16:37:23+00:00",
"deleted_vrps": 0,
"unchanged_vrps": 0,
"new_vrps": 205850
},
// ...
]
}
next
is the URL to the next page. It will be an empty string if there are no results
left.
timestamp
refers to the dump time (taken from the filename).
[deleted|updated|new]_vrps
indicates the number of VRPs differing from the previous
dump. Note that deleted
refers to a VRP that was present in the previous dump, but not
in the current one.
For easier analysis of the dataset, or self-hosting, a dump of the database (updated weekly) is available.
If for some reason you want to host your own version of this page, here is how.
Create secrets files containing the Postgres user passwords.
# For normal user
touch ./secrets/postgres-pw.txt
# For read-only user
touch ./secrets/postgres-ro-pw.txt
# Of course write actual passwords to these files...
Initialize database. This will also build the initial Docker image, which might take some time.
docker compose run --rm init-db
Optional: Restore database dump.
docker compose exec -T database pg_restore -d rpki_history < rpki-history.dump
Optional (but recommended): Create an index over the prefix column to greatly decrease query time. This is not built into the init-db script, since it is faster to build the index once after all data was imported.
docker compose exec database psql -c "CREATE INDEX ON vrps USING gist (prefix inet_ops)"
Start the API server.
docker compose up -d api
To import the latest available data (uses RPKIViews by default):
docker compose run --rm update-db
For more usage options (e.g., importing a specific timestamp):
docker compose run --rm update-db --help
docker compose exec database pg_dump --data-only -Fc > rpki-history.dump
Assumes fresh install or that postgres_data
volume was deleted.
# Reinitialize database to create schema *and additional user*.
docker compose run --rm init-db
# Restore data
docker compose exec -T database pg_restore -d rpki_history < rpki-history.dump