DEV Community

Cover image for Verifying an IPv4 Block Before You Lease It: RDAP, BGP, and RPKI in Practice
Artem Kohanevich
Artem Kohanevich

Posted on

Verifying an IPv4 Block Before You Lease It: RDAP, BGP, and RPKI in Practice

Most "who owns this IP" tooling answers one question and presents it as the whole answer. For incident response that's usually fine. For a lease you're about to route production traffic through, it isn't.

There are five separate questions, and they resolve against five different data sources:

Question Source What the answer actually means
Who is registered for the block? RDAP / RIR WHOIS Registered holder of the containing object
Who is originating it now? BGP (RIPEstat, RouteViews) Origin ASN as seen by route collectors
Is that origin authorized? RPKI, secondarily IRR Whether origin+prefix match a covering ROA
Where is it used? Geolocation providers An estimate. Not authoritative for anything
What's its abuse history? Reputation services, plural Provider-specific, time-sensitive signals

A holder/origin mismatch is not evidence of fraud - leasing, transit, BYOIP, and parent/subsidiary structures all produce one routinely. What matters is whether the mismatch is accounted for.

RDAP over WHOIS, and why

RDAP is standardized where WHOIS isn't:

  • RFC 9082 - query format
  • RFC 9083 - JSON response structure
  • RFC 9224 - bootstrap (IANA registry → correct RIR endpoint)

WHOIS returns registry-specific plain text. ARIN uses NetRange / OrgName; RIPE and APNIC use RPSL-style inetnum / descr. If you're parsing, you write a parser per registry. RDAP gives you consistent field names across all five RIRs.

Two things RDAP does not give you:

  1. Accuracy. Both services read from the same registry data maintained by resource holders. A stale org name is stale in both.
  2. A different answer than WHOIS. They're views over the same records, not independent sources. Cross-checking one against the other proves nothing.

One correction that comes up a lot: the January 2025 WHOIS sunset applied to gTLD registration data. RDAP became definitive for domain names on 28 January 2025, 374 gTLDs had disabled WHOIS by that September, and RDAP query volume overtook WHOIS in June 2025. RIR WHOIS for IP and ASN resources was unaffected and is still running in 2026.

The first pass

#!/usr/bin/env bash
# Minimum viable due diligence on an offered prefix.
PREFIX="198.51.100.0/24"
IP="198.51.100.10"

# 1. Registry record, via RDAP bootstrap.
curl -s "https://rdap.org/ip/${IP}" | jq '{
  name, handle, type, country,
  cidr: .cidr0_cidrs,
  parent: .parentHandle,
  roles: [.entities[]? | {handle, roles}],
  events: [.events[]? | {action: .eventAction, date: .eventDate}]
}'

# 2. Current origin + history.
curl -s "https://stat.ripe.net/data/routing-status/data.json?resource=${PREFIX}" \
  | jq '.data | {visibility, first_seen, last_seen, announced_space}'

curl -s "https://stat.ripe.net/data/routing-history/data.json?resource=${PREFIX}" \
  | jq '.data.by_origin[] | {origin, timelines}'

# 3. ROA state.
curl -s "https://stat.ripe.net/data/rpki-validation/data.json?resource=AS64500&prefix=${PREFIX}" \
  | jq '.data | {status, validating_roas}'
Enter fullscreen mode Exit fullscreen mode

198.51.100.0/24 is TEST-NET-2 (RFC 5737). Substitute the real prefix; don't route the example.

Notes on the output:

  • type distinguishes ALLOCATION, ASSIGNMENT, LEGACY, and registry-specific values. Terminology differs per RIR - don't map ARIN semantics onto a RIPE object.
  • parentHandle matters when the offered range sits under a larger allocation. RDAP returns the most specific object; the commercial relationship may live one level up.
  • events gives you registration and last changed. A recent last changed means something was touched, not that every field was reverified.
  • cidr0_cidrs - confirm the returned object actually contains your full offered prefix. Querying one IP and assuming the /24 inherits its status is the single most common mistake here.

Persist the raw JSON with a timestamp. Registry and routing state both drift; a saved response is evidence, a screenshot isn't.

Origin history is the interesting part

Current origin tells you today. History tells you what you're inheriting.

What to pull out of routing-history:

  • Every origin ASN observed, with first/last seen
  • Gaps in announcement - dormant space is a hijack target
  • More-specifics announced from unrelated ASNs
  • Churn without explanation

Any of these is a question for the provider, not a disqualification. But "we don't know" is itself an answer.

ROA state, and what it's worth

Three outcomes:

Valid    → prefix + origin ASN covered by a matching ROA,
           announcement no more specific than maxLength
Invalid  → covering ROA exists, ASN or prefix length doesn't match
NotFound → no covering ROA
Enter fullscreen mode Exit fullscreen mode

Worth calibrating expectations here. RPKI coverage hit a record 67.43% of announced prefixes in June 2026 - roughly 1.07M of 1.58M routes carrying a signed ROA. Enforcement is the lagging half: measurement work cited by RIPE Labs puts full route origin validation at around 12% of ASes, with roughly 36% not validating at all.

So Valid means the origin is authorized and networks that validate will accept it. It does not mean the announcement is safe from hijack, that the AS path is sound, or that the entity emailing you is the holder. ROV checks the rightmost AS in the path. An attacker who wants a protected prefix doesn't fight the ROA - they announce the victim's prefix with the victim's ASN at origin and prepend their own.

Also worth checking maxLength in the ROA. Over-permissive maxLength (RFC 9319 covers this) leaves room for more-specific announcements that still validate. If the lessor is creating a fresh ROA for your ASN, specify it exactly rather than accepting a default.

Reputation: scan the range, not a sample

Registry and routing checks say nothing about deliverability or platform acceptance. Separate step, separate tooling.

# Spamhaus ZEN, reversed-octet DNSBL query.
# Use your own resolver - public mirrors refuse queries from large resolvers,
# and a sequential /24 scan will hit rate limits.
check_zen() {
  local ip=$1
  local rev
  rev=$(echo "$ip" | awk -F. '{print $4"."$3"."$2"."$1}')
  local result
  result=$(dig +short "${rev}.zen.spamhaus.org" A)
  [[ -n "$result" ]] && echo "$ip -> $result"
}

# Whole /24, not a sample.
for i in $(seq 0 255); do check_zen "198.51.100.$i"; done
Enter fullscreen mode Exit fullscreen mode

Return codes map to distinct lists, and they mean different things:

Code List What it means
127.0.0.2 SBL Manually researched spam source
127.0.0.3 CSS Auto-detected low-reputation sender
127.0.0.4 XBL Compromised/exploited host
127.0.0.9 SBL DROP Hijacked or wholly malicious allocation
127.0.0.10/11 PBL Policy range, shouldn't send direct-to-MX

A PBL listing is a policy statement about the range, not an abuse finding. Treating it as equivalent to SBL will make you walk away from perfectly usable space. 127.0.0.9 is the one that should stop a deal.

One number that justifies the whole exercise: a study of RIR transfer reports from 2009 to 2019 found nearly 40% of routed transferred prefixes carried at least one blacklist report, against about 6% of routed prefixes that had never been transferred. Traded space isn't inherently bad. It's a different prior.

The check nobody automates

Everything above queries what the registry says. None of it tells you whether the registry can act.

That matters when a lease depends on a record change - a ROA creation, a route object update, an entity change - happening inside the lease term.

AFRINIC is the working example. Board dissolved, registry under receivership from 2022-2023, address requests stalled for months with no functioning governance. A board was seated after the 2025 elections and the receiver applied to terminate receivership in October 2025, but litigation begun before and after those elections is still open, the June 2025 election was annulled and re-run, and the incoming CEO doesn't take office until January 2027.

There's no API for "can this registry process my request this quarter." Ask the provider, name the RIR, get it in writing.

Checklist

[ ] Full CIDR, RIR, proposed origin ASN, lease term, activation date
[ ] RDAP object contains the entire offered prefix (not just a sample IP)
[ ] Registered holder identified; counterparty's relationship documented
[ ] Signer authority verified via a channel the counterparty didn't supply
[ ] Current + historical BGP origins reviewed; anomalies explained
[ ] ROA plan matches agreed prefix and origin ASN, maxLength specified
[ ] IRR route object plan confirmed
[ ] Full range scanned across multiple reputation sources
[ ] Registry turnaround time for record changes confirmed in writing
[ ] Acceptance criteria + remediation deadlines in the contract
[ ] Withdrawal sequence defined for end of lease
[ ] Raw JSON responses archived with timestamps
Enter fullscreen mode Exit fullscreen mode

Activation ordering matters too: old announcement withdrawn → ROA and IRR updated → new announcement started → propagation monitored. Overlapping announcements during a handover produce exactly the ambiguity you spent all this effort eliminating.


Longer writeup with the field-by-field registry reading guide, the RDAP-vs-WHOIS comparison, and a green/yellow/red decision table for lease evaluation: Who Owns an IP Address? How to Check with WHOIS and RDAP

Top comments (0)