| Crates.io | ip-alloc-lookup |
| lib.rs | ip-alloc-lookup |
| version | 0.1.3 |
| created_at | 2025-12-31 14:15:40.255093+00 |
| updated_at | 2025-12-31 14:44:50.352809+00 |
| description | Fast, offline IPv4/IPv6 IP allocation lookup (country + EU flag) using RIPE NCC delegated data |
| homepage | |
| repository | https://github.com/markobekko/ip-alloc-lookup |
| max_upload_size | |
| id | 2014803 |
| size | 18,028,793 |
A fast, offline IPv4 and IPv6 lookup library based on RIPE NCC delegated allocation data. The crate maps IP addresses to ISO-3166 country codes and includes a built-in European Union (EU) membership classification.
This is an allocation-based lookup, not a geolocation service.
The data used by this library comes from RIPE NCC delegated statistics. Each IP range is associated with:
The EU flag reflects political membership, derived from the country code. It does not indicate where traffic is physically routed or processed.
[dependencies]
ip-alloc-lookup = "0.1.3"
use std::net::Ipv4Addr;
use ip_alloc_lookup::GeoIpDb;
let db = GeoIpDb::new();
let ip = Ipv4Addr::new(8, 8, 8, 8);
if let Some(info) = db.lookup_v4(ip) {
println!("Country: {}", info.country_code_str());
println!("EU member: {}", info.is_eu);
}
use std::net::Ipv6Addr;
use ip_alloc_lookup::GeoIpDb;
let db = GeoIpDb::new();
let ip = "2001:4860:4860::8888".parse::<Ipv6Addr>().unwrap();
if let Some(info) = db.lookup_v6(ip) {
println!("Country: {}", info.country_code_str());
println!("EU member: {}", info.is_eu);
}
use std::net::IpAddr;
use ip_alloc_lookup::GeoIpDb;
let db = GeoIpDb::new();
let ip: IpAddr = "2a01:4f8::1".parse().unwrap();
if let Some(info) = db.lookup(ip) {
println!("Country: {}", info.country_code_str());
println!("EU member: {}", info.is_eu);
}
By default, the crate ships with embedded, pre-generated RIPE data. This guarantees deterministic behavior and zero network usage at runtime.
If you enable the optional download feature, the crate can:
[dependencies]
ip-alloc-lookup = { version = "0.1", features = ["download"] }
#[cfg(feature = "download")]
use std::net::IpAddr;
#[cfg(feature = "download")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let cache_path = "cache/ripe-data.txt";
// 1) Update cache from the official RIPE delegated URL
let bytes = ip_alloc_lookup::GeoIpDb::update_cache(cache_path)?;
println!("Downloaded {bytes} bytes into {cache_path}");
// 2) Load database from cached file (not embedded data)
let db = ip_alloc_lookup::GeoIpDb::from_ripe_delegated_file(cache_path)?;
// 3) Perform a lookup
let ip: IpAddr = "88.198.0.1".parse()?; // commonly DE (Hetzner)
if let Some(info) = db.lookup(ip) {
println!(
"{ip} -> country={}, is_eu={}",
info.country_code_str(),
info.is_eu
);
} else {
println!("{ip} not found");
}
Ok(())
}
#[cfg(not(feature = "download"))]
fn main() {
eprintln!("This demo requires the `download` feature.");
eprintln!("Run: cargo run --features download");
}
Once loaded, all lookups are offline and have the same performance characteristics as the embedded database.
EU membership is determined by a built-in list of ISO-3166 country codes corresponding to current EU member states.
This classification is:
It reflects political membership, not physical location or legal compliance.
Lookups are implemented using binary search over sorted IP ranges and are designed for hot paths.
Typical performance on modern x86_64 systems:
The database is immutable after construction and safe to share across threads.
All measurements were taken on a modern x86_64 system in release mode. Results are representative and may vary depending on hardware, OS, and CPU frequency scaling.
| Benchmark | Description | Median Result |
|---|---|---|
database_creation |
Build lookup tables | ~3.2 ms |
single_lookup_ipv4 (EU) |
Single IPv4 lookup (EU IP) | ~20 ns |
single_lookup_ipv4 (Non-EU) |
Single IPv4 lookup (Non-EU IP) | ~20–21 ns |
single_lookup_ipv6 (EU) |
Single IPv6 lookup (EU IP) | ~18–19 ns |
single_lookup_ipv6 (Non-EU) |
Single IPv6 lookup (Non-EU IP) | ~19–100 ns* |
unified_lookup IPv4 (EU) |
Unified IpAddr lookup |
~150–165 ns |
unified_lookup IPv4 (Non-EU) |
Unified IpAddr lookup |
~20–21 ns |
unified_lookup IPv6 (EU) |
Unified IpAddr lookup |
~19–20 ns |
unified_lookup IPv6 (Non-EU) |
Unified IpAddr lookup |
~20 ns |
is_eu_check IPv4 |
EU membership check (IPv4) | ~28–60 ns |
is_eu_check IPv6 |
EU membership check (IPv6) | ~20–21 ns |
batch_lookups_ipv4 (100) |
100 IPv4 lookups | ~2.6 µs (~38 Melem/s) |
batch_lookups_ipv4 (1,000) |
1,000 IPv4 lookups | ~28.5 µs (~35 Melem/s) |
batch_lookups_ipv4 (10,000) |
10,000 IPv4 lookups | ~287 µs (~35 Melem/s) |
batch_lookups_ipv6 (100) |
100 IPv6 lookups | ~2.0 µs (~50 Melem/s) |
batch_lookups_ipv6 (1,000) |
1,000 IPv6 lookups | ~20.5 µs (~49 Melem/s) |
batch_lookups_ipv6 (10,000) |
10,000 IPv6 lookups | ~211 µs (~47 Melem/s) |
worst_case_ipv4 |
Worst-case IPv4 lookup | ~127 µs |
worst_case_ipv6 |
Worst-case IPv6 lookup | ~110 µs |
* IPv6 lookup latency depends on range density and position wit
The repository includes a comprehensive Criterion benchmark suite.
To run benchmarks locally:
cargo bench
Benchmarks cover:
IpAddr lookupsResults show consistent nanosecond-scale performance for single lookups and throughput in the tens of millions of lookups per second for batch processing on commodity hardware.
✔ You need fast, deterministic IP classification
✔ You run in offline or restricted environments
✔ You care about allocation metadata, not precise geolocation
✘ You need real-time physical location
✘ You need routing-aware or anycast-aware answers
✘ You need guaranteed legal or regulatory compliance
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you shall be dual licensed as above, without any additional terms or conditions.