The structural flaw in registration-based IP geolocation
For the first twenty years of the commercial internet, IP geolocation databases relied on a straightforward assumption: the country listed on an IP block's Regional Internet Registry (RIR) allocation record was the country where packets addressed to that block actually terminated. When ARIN allocated a /16 to a corporation headquartered in Wilmington, Delaware, legacy geolocation providers mapped all 65,536 addresses in that block to the United States.
In modern network engineering, legal registration geography and physical router topology diverge on millions of prefixes every single day. The exhaustion of the free IPv4 pools across all five RIRs (ARIN, RIPE NCC, APNIC, LACNIC, and AFRINIC) created a liquid global secondary market for IPv4 address space. Organizations routinely lease /22 and /24 blocks across continents without transferring the underlying RIR org record, announce those prefixes out of foreign Internet Exchange Points (IXPs), or re-home subnets across cloud availability zones in minutes using automated BGP orchestration.
If your application relies on a single country_code field derived purely from WHOIS, RDAP, or unverified self-published geofeeds, you are systematically misrouting edge traffic, miscalculating regional VAT or tax rules, and triggering false-positive compliance blocks.
This engineering deep dive examines the three root causes of registration-versus-physical divergence, explains how the ipscope compiler separates legal jurisdiction from physical router topology using speed-of-light latency triangulation, and provides concrete implementation patterns for routing, fraud scoring, and regulatory compliance.
Three ways legal registration diverges from physical routing
1. Cross-border IPv4 leasing and Letter of Authorization (LOA) announcements
Since IPv4 runout, brokers and IP leasing platforms have enabled cloud providers, content delivery networks, and regional ISPs to lease address blocks on short-term contracts. Under standard routing practice, the original registrant (the lessor) retains administrative ownership of the inetnum or NetRange record in ARIN or APNIC, and issues a cryptographic ROA (Route Origin Authorization) via RPKI alongside a Letter of Authorization permitting the lessee's Autonomous System Number (ASN) to announce the /24 over BGP.
Consider what happens when a bare-metal hosting provider in Frankfurt (DE) leases 198.51.100.0/24 from a legacy US telecom holder:
- The ARIN RDAP
NetRangerecord still lists the registrant's corporate address in Virginia (US). - Legacy geolocation vendors that refresh primarily from RIR WHOIS dumps continue to report
country_code: "US". - In reality, every BGP update for
198.51.100.0/24originates from an ASN peering at DE-CIX Frankfurt, and physical fiber latency from Frankfurt probes is under1.4 ms.
2. Multinational backbone sub-allocations without discrete inetnum objects
Global cloud providers, hyperscalers, and Tier-1 transit carriers register massive /12 or /14 IPv4 blocks and /29 or /32 IPv6 blocks under a single holding entity, typically in Seattle, Dublin, or Singapore. Internally, their traffic engineering controllers slice those parent blocks into thousands of /24 IPv4 and /48 IPv6 prefixes deployed across 35+ countries.
Many operators do not create separate RIR sub-allocation objects for every /24 they move between Tokyo, Mumbai, and Sydney. Even when an operator publishes an RFC 8805 geofeed CSV, internal capacity migrations frequently happen days or weeks before the public CSV file is updated. During that window, registration-driven databases report the holding company's headquarters country rather than the active data center region.
3. Stale or unverified RFC 8805 geofeeds and geofeed spoofing
RFC 8805 (A Format for Self-Published IP Geolocation Feeds) was designed so network operators could publish a CSV mapping their CIDR blocks to ISO-3166 country and subdivision codes. While RFC 8805 solved the problem of slow WHOIS updates for honest operators, it introduced two new failure modes:
- Operational drift: A network engineering team re-announces a
/24from Amsterdam to London during a peering migration and forgets to commit the updated row to their staticgeofeed.csvrepository. - Intentional geo-arbitrage: Commercial proxy networks and grey-market VPN providers intentionally publish RFC 8805 rows claiming that cheap datacenter subnets hosted in Frankfurt or Bucharest are located in high-value residential metros like New York, London, or Zurich in order to bypass streaming media geo-fences and ad-verification filters.
Why collapsing geography into a single country field breaks production systems
When an IP intelligence provider collapses legal registration and physical location into a single country_code column, every downstream team in your organization is forced into a compromise:
| Engineering Team | What They Actually Need | What Goes Wrong with a Single Collapsed Field |
|---|---|---|
| Edge Routing & CDN | Physical router location (physical_country_code) | Traffic from a Frankfurt server using a US-registered /24 gets routed across the Atlantic to a US East PoP, adding 85 ms of unnecessary RTT. |
| Sanctions & Export Control | Both legal registrant and physical termination (declared_country_code + physical_country_code) | Checking only physical routing misses an IP block legally owned by a sanctioned corporate entity; checking only registration blocks legitimate European infrastructure leasing legacy US space. |
| Media Licensing & DRM | Physical termination + virtual location flag (physical_country_code + is_virtual_location) | Proxy exits spoofing RFC 8805 geofeeds bypass regional licensing checks unless physical RTT triangulation overrides the self-declared CSV. |
| Payments & Tax (VAT / GST) | Explicit reconciliation against billing country | Checkout flows reject valid transactions when a multinational corporate VPN egresses in one country using an IP block registered to its parent company in another. |
How ipscope separates declared and physical geography
Rather than hiding the disagreement between administrative records and active network topology inside a black-box heuristic, ipscope exposes three explicit country fields plus a boolean virtual-location indicator inside the geo block on every REST API response, MMDB record, and Parquet row:
{
"ip": "198.51.100.7",
"ip_version": 4,
"matched_network": "198.51.100.0/24",
"geo": {
"country_code": "DE",
"declared_country_code": "US",
"physical_country_code": "DE",
"is_virtual_location": true,
"location_type": "virtual",
"confidence": 0.96,
"subdivision": "Hesse",
"city": "Frankfurt am Main",
"latitude": 50.1109,
"longitude": 8.6821,
"accuracy_radius_km": 10,
"timezone": "Europe/Berlin"
},
"network": {
"cidr": "198.51.100.0/24",
"asn": 24940,
"organization": "Hetzner Online GmbH",
"rir": "ARIN"
}
}Field definitions and compiler semantics
| Field | Data Type | Compiler Source of Truth | Operational Meaning |
|---|---|---|---|
declared_country_code | string (ISO-3166-1 alpha-2) | RIR RDAP/WHOIS allocation records (inetnum, inet6num, NetRange) and RPKI-authenticated RFC 8805 geofeeds | The legal or administrative jurisdiction where the IP block is registered or formally declared by its holder. |
physical_country_code | string (ISO-3166-1 alpha-2) | Multi-vantage active RTT triangulation, BGP next-hop IXP locality, and rDNS router interface telemetry | The country where packets addressed to this prefix physically terminate on hardware. |
country_code | string (ISO-3166-1 alpha-2) | Resolved effective country (physical_country_code when physical confidence exceeds threshold) | Primary country code for localization, default currency, and UI rendering. |
is_virtual_location | boolean | true whenever declared_country_code !== physical_country_code | Indicates that the subnet is leased cross-border, announced remotely via BGP, or has a declared geofeed that conflicts with physical router physics. |
location_type | string ("physical", "virtual", "anycast") | Topology classifier | Distinguishes standard single-homed physical subnets from cross-border virtualized announcements and global BGP anycast prefixes. |
How our compiler resolves physical location using speed-of-light physics
Network operators can put whatever text they want into a WHOIS remark or an RFC 8805 CSV file, but they cannot violate the speed of light in optical fiber.
In single-mode silica optical fiber, light propagates at approximately 200,000 km/s (roughly two-thirds the speed of light in a vacuum due to a refractive index of n ≈ 1.468). Because an ICMP Echo, TCP SYN/ACK, or UDP probe must travel from the measurement vantage point to the target IP and back, the theoretical minimum round-trip propagation delay in straight-line fiber is 1 millisecond per 100 kilometers of geographic distance. Once you account for non-linear fiber conduit routing, DWDM optical repeaters, and MPLS/BGP switching serialization, real-world terrestrial internet paths achieve roughly 65 to 85 kilometers of geographic radius per millisecond of minimum RTT.
Stage 1: BGP table ingestion and RIR bailiwick extraction
Every compilation cycle starts by ingesting full BGP routing tables (RIB dumps and real-time UPDATE streams) from route collectors peering at major IXPs worldwide, alongside daily RDAP and WHOIS snapshots from ARIN, RIPE NCC, APNIC, LACNIC, and AFRINIC.
For every routed IPv4 /24 and IPv6 /48, the compiler extracts:
- The originating ASN and its upstream transit or IXP peering adjacency graph.
- The administrative registrant country from the most specific RIR allocation object.
- Any RFC 8805
#geofeedURL attached to the allocation object via RFC 9092 remarks, validated against RPKI Route Origin Authorizations (ROAs).
Stage 2: Reverse DNS (rDNS) router interface parsing
Before firing active latency probes, the compiler evaluates PTR records on gateway and router interfaces within the prefix and along the penultimate traceroute hops. Carrier backbone engineers name core and edge router interfaces using standardized IATA airport codes, UN/LOCODE city identifiers, and CLLI codes (for example, ae4-200.cr1-fra1.ip4.gtt.net or et-0-0-2.br02.ams01.example.net).
While rDNS on a leaf host can be set to anything by a customer, rDNS on the upstream provider's penultimate MPLS/BGP hop is controlled by the transit carrier. When multiple upstream peers converge on fra (Frankfurt) or ams (Amsterdam), the compiler records a strong topological prior for that metro area.
Stage 3: Multi-vantage minimum-RTT trilateration
Whenever a prefix is newly announced, shifts its upstream BGP path, claims a new RFC 8805 city, or exhibits a disagreement between its RIR registration country and its upstream peering graph, our distributed measurement fleet executes lightweight TCP/ICMP minimum-RTT probes from vantage points across North America, Europe, Asia-Pacific, Latin America, and Africa.
We always take the minimum observed RTT (min_rtt) across multiple samples rather than the mean or median. Queuing delay on a congested router interface can inflate a single packet's RTT upward, but queuing delay can never make a packet arrive faster than the speed of light in fiber.
Consider our earlier example (198.51.100.0/24), where ARIN WHOIS and a stale geofeed claim the subnet is in Ashburn, Virginia (US):
| Measurement Vantage Point | Claimed Distance to Ashburn, VA | Measured min_rtt | Maximum Physical Radius (~80 km/ms) | Physically Compatible with Ashburn (US)? |
|---|---|---|---|---|
Ashburn, US (iad-01) | 12 km | 84.2 ms | 6,736 km | Suspiciously high for local metro |
Newark, US (ewr-01) | 380 km | 81.6 ms | 6,528 km | Suspiciously high |
Amsterdam, NL (ams-01) | 6,170 km | 6.4 ms | 512 km | Impossible (6,170 km > 512 km) |
Frankfurt, DE (fra-01) | 6,530 km | 1.3 ms | 104 km | Impossible (6,530 km > 104 km) |
Zurich, CH (zrh-01) | 6,640 km | 5.8 ms | 464 km | Impossible (6,640 km > 464 km) |
A 1.3 ms round-trip time from our Frankfurt vantage point proves with physical certainty that the target host lies within roughly 100 km of Frankfurt am Main. It is physically impossible for a packet to leave Frankfurt, cross the Atlantic Ocean to Virginia, and return in 1.3 ms (which would require travelling at over 10,000 times the speed of light in fiber).
When the trilateration solver sees this intersection of circles (1.3 ms from Frankfurt, 5.8 ms from Zurich, 6.4 ms from Amsterdam), it deterministically assigns:
declared_country_code: "US"(preserving the ARIN administrative record for legal audit trails)physical_country_code: "DE"(reflecting the verified physical termination in Frankfurt)country_code: "DE"is_virtual_location: truelocation_type: "virtual"
How BGP Anycast prefixes are handled (location_type: "anycast")
A critical edge case in physical RTT triangulation is BGP Anycast. Content delivery networks, authoritative DNS providers, and DDoS scrubbing networks announce the exact same /24 IPv4 or /48 IPv6 prefix simultaneously from 50 to 300+ global Points of Presence.
When our measurement fleet probes an anycast prefix, the Frankfurt probe gets a 1.1 ms reply (from the local Frankfurt anycast node), the Ashburn probe gets a 0.9 ms reply (from the local Ashburn node), and the Tokyo probe gets a 1.4 ms reply (from the local Tokyo node). If a naive trilateration solver tried to intersect three 100 km circles centered in Frankfurt, Ashburn, and Tokyo, the intersection would be empty!
Our compiler detects anycast topology automatically when three or more geographically disjoint continents simultaneously observe sub-10 ms minimum RTTs to the same /24 or /48 prefix. When that condition holds, the compiler sets location_type: "anycast" and anchors the administrative metadata to the operator's primary registration while flagging that the prefix terminates at the nearest local PoP.
Production implementation patterns
Pattern 1: Dual-jurisdiction sanctions and export compliance in Python
If you operate a fintech, crypto exchange, or SaaS platform subject to OFAC, EU, or UK export controls, checking a single country code leaves a dangerous blind spot. A sanctioned corporate entity can lease infrastructure in a non-sanctioned country, or a non-sanctioned entity can route traffic into a restricted territory.
By inspecting both declared_country_code and physical_country_code, your compliance middleware catches both vectors cleanly:
import asyncio
import os
from typing import TypedDict
from ipscope import AsyncIpScopeClient
RESTRICTED_JURISDICTIONS = {"CU", "IR", "KP", "SY"}
class ComplianceDecision(TypedDict):
allowed: bool
reason: str
declared_country: str
physical_country: str
is_virtual: bool
async def evaluate_jurisdiction_policy(client_ip: str) -> ComplianceDecision:
async with AsyncIpScopeClient(api_key=os.environ["IPSCOPE_KEY"]) as client:
res = await client.lookup_ip(client_ip)
geo = res["geo"]
declared = geo["declared_country_code"]
physical = geo["physical_country_code"]
is_virtual = bool(geo["is_virtual_location"])
if physical in RESTRICTED_JURISDICTIONS:
return {
"allowed": False,
"reason": f"blocked_physical_termination:{physical}",
"declared_country": declared,
"physical_country": physical,
"is_virtual": is_virtual,
}
if declared in RESTRICTED_JURISDICTIONS:
return {
"allowed": False,
"reason": f"blocked_registered_allocation:{declared}",
"declared_country": declared,
"physical_country": physical,
"is_virtual": is_virtual,
}
return {
"allowed": True,
"reason": "compliant_jurisdiction",
"declared_country": declared,
"physical_country": physical,
"is_virtual": is_virtual,
}
if __name__ == "__main__":
decision = asyncio.run(evaluate_jurisdiction_policy("198.51.100.7"))
print(decision)Pattern 2: Eliminating false checkout declines on cross-border cloud and corporate subnets
In e-commerce payment risk engines, a classic rule compares the customer's credit card billing country against the IP address country. When a multinational company routes employee laptop traffic through a regional cloud firewall whose IP block was leased from another RIR region, legacy databases report a country mismatch and trigger a false decline.
With ipscope, your risk engine can check whether the customer's billing country matches either the physical_country_code or, for verified business networks (connection.is_business), the declared_country_code, while stepping up authentication only when security.is_vpn or security.is_proxy is active:
import { IpScopeClient } from '@ipscope/sdk-node';
const client = new IpScopeClient({ apiKey: process.env.IPSCOPE_KEY });
export async function verifyBillingCountryMatch(
clientIp: string,
billingCountryIso2: string,
): Promise<{ status: 'match' | 'virtual_match' | 'mismatch'; details: string }> {
const res = await client.lookupIp(clientIp);
const { geo, connection, security } = res;
if (geo.physical_country_code === billingCountryIso2) {
return {
status: 'match',
details: `Physical termination matches billing country (${billingCountryIso2})`,
};
}
if (
geo.is_virtual_location &&
geo.declared_country_code === billingCountryIso2 &&
connection?.is_business &&
!security.is_vpn &&
!security.is_proxy
) {
return {
status: 'virtual_match',
details: `Enterprise virtual subnet registered to ${geo.declared_country_code}, routed via ${geo.physical_country_code}`,
};
}
return {
status: 'mismatch',
details: `Billing=${billingCountryIso2}, Physical=${geo.physical_country_code}, Declared=${geo.declared_country_code}`,
};
}Frequently asked questions (FAQ)
Which country field should I use for general website localization and CDN routing?
Use geo.country_code (or geo.physical_country_code). In standard unicast prefixes, geo.country_code resolves to the verified physical country where the user or server actually connects to the internet, ensuring low-latency PoP selection and accurate local language/currency defaults.
Why does my IP show declared_country_code: "US" and physical_country_code: "NL"?
This means the IPv4 or IPv6 block is administratively registered in ARIN to a US legal entity (or declares US in its registration metadata), but the prefix is actively announced over BGP and physically terminated on routers located in the Netherlands (NL), as confirmed by sub-5 ms speed-of-light latency measurements from Dutch and German vantage points.
Are declared_country_code, physical_country_code, and is_virtual_location included in downloadable .mmdb and .parquet files?
Yes. Every ipscope database SKU that includes the geo_country family (IPScope-Country, IPScope-Privacy, and IPScope-Complete) embeds country_code, declared_country_code, physical_country_code, is_virtual_location, location_type, and confidence directly inside the .mmdb binary tree, .parquet columns, and .csv.gz exports.