This library reads the MaxMind DB format, including the GeoIP2 and GeoLite2 databases.
To build everything:
cargo build
This crate manages its test data within a git submodule. To run the tests, you will first need to run the following command.
git submodule update --init
Add this to your Cargo.toml:
[dependencies]
maxminddb = "0.32"
use maxminddb::{geoip2, path, Reader};
use std::net::IpAddr;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let reader = Reader::open_readfile("/path/to/GeoLite2-City.mmdb")?;
let ip: IpAddr = "89.160.20.128".parse()?;
let result = reader.lookup(ip)?;
println!("Network: {}", result.network()?);
if let Some(city) = result.decode::<geoip2::City>()? {
println!("Country: {}", city.country.iso_code.unwrap_or("N/A"));
println!("City: {}", city.city.names.english.unwrap_or("N/A"));
}
let iso_code: Option<&str> = result.decode_path(&path!["country", "iso_code"])?;
println!("Country code via decode_path: {}", iso_code.unwrap_or("N/A"));
Ok(())
}
lookup() returns a lightweight LookupResult handle. You can:
has_data()network()decode()decode_path()offset() as a cache key when many IPs share the same recordUse within() to iterate over the networks contained in a CIDR range, or
networks() to iterate over the whole database. The example below uses the
ipnetwork crate, which is not
re-exported by maxminddb; add it to your own Cargo.toml to run this code.
use ipnetwork::IpNetwork;
use maxminddb::{Reader, WithinOptions};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let reader = Reader::open_readfile("/path/to/GeoLite2-City.mmdb")?;
let cidr: IpNetwork = "89.160.20.0/24".parse()?;
let opts = WithinOptions::default().skip_empty_values();
for result in reader.within(cidr, opts)? {
let lookup = result?;
println!("{}", lookup.network()?);
}
Ok(())
}
See the examples directory for runnable programs, including:
cargo run --example lookup -- <database.mmdb> <ip>cargo run --example within -- <database.mmdb> <cidr>Optional features:
mmap: Memory-mapped file access for long-running applicationsunsafe-str-decode: Skip UTF-8 validation when deserializing trusted
database strings into Rust str or String values. Cross-runtime format
adapters should prefer deserialize_any_with_raw_strings() and validate
while constructing the target runtime's string type.Enable in Cargo.toml:
[dependencies]
maxminddb = { version = "0.32", features = ["mmap"] }
The project includes benchmarks using Criterion.rs.
First you need to have a working copy of the GeoIP City database. You can fetch it from here.
Place it in the root folder as GeoLite2-City.mmdb.
Once this is done, run
cargo bench
Two focused benchmarks are especially useful while iterating on changes:
cargo bench --bench lookup
cargo bench --bench serde_usage
The serde_usage suite covers typed records, ignored fields, generic JSON
values, raw-string adapters, and selective paths. The decode_raw_strings
case walks every record using borrowed identifier bytes and
deserialize_any_with_raw_strings, as language bindings do, without adding
another runtime's allocation costs. It detects decoder overhead that typed
record benchmarks can miss.
Criterion.rs generates an HTML report at target/criterion/report/index.html.
It uses gnuplot when available and the bundled Plotters backend otherwise.
Contributions welcome! Please fork the repository and open a pull request with your changes.
This is free software, licensed under the ISC license.
1,024 followers · starred Feb 2023
46 followers · starred Jul 2016
15 followers · starred Sep 2023
This library reads the MaxMind DB format, including the GeoIP2 and GeoLite2 databases.
To build everything:
cargo build
This crate manages its test data within a git submodule. To run the tests, you will first need to run the following command.
git submodule update --init
Add this to your Cargo.toml:
[dependencies]
maxminddb = "0.32"
use maxminddb::{geoip2, path, Reader};
use std::net::IpAddr;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let reader = Reader::open_readfile("/path/to/GeoLite2-City.mmdb")?;
let ip: IpAddr = "89.160.20.128".parse()?;
let result = reader.lookup(ip)?;
println!("Network: {}", result.network()?);
if let Some(city) = result.decode::<geoip2::City>()? {
println!("Country: {}", city.country.iso_code.unwrap_or("N/A"));
println!("City: {}", city.city.names.english.unwrap_or("N/A"));
}
let iso_code: Option<&str> = result.decode_path(&path!["country", "iso_code"])?;
println!("Country code via decode_path: {}", iso_code.unwrap_or("N/A"));
Ok(())
}
lookup() returns a lightweight LookupResult handle. You can:
has_data()network()decode()decode_path()offset() as a cache key when many IPs share the same recordUse within() to iterate over the networks contained in a CIDR range, or
networks() to iterate over the whole database. The example below uses the
ipnetwork crate, which is not
re-exported by maxminddb; add it to your own Cargo.toml to run this code.
use ipnetwork::IpNetwork;
use maxminddb::{Reader, WithinOptions};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let reader = Reader::open_readfile("/path/to/GeoLite2-City.mmdb")?;
let cidr: IpNetwork = "89.160.20.0/24".parse()?;
let opts = WithinOptions::default().skip_empty_values();
for result in reader.within(cidr, opts)? {
let lookup = result?;
println!("{}", lookup.network()?);
}
Ok(())
}
See the examples directory for runnable programs, including:
cargo run --example lookup -- <database.mmdb> <ip>cargo run --example within -- <database.mmdb> <cidr>Optional features:
mmap: Memory-mapped file access for long-running applicationsunsafe-str-decode: Skip UTF-8 validation when deserializing trusted
database strings into Rust str or String values. Cross-runtime format
adapters should prefer deserialize_any_with_raw_strings() and validate
while constructing the target runtime's string type.Enable in Cargo.toml:
[dependencies]
maxminddb = { version = "0.32", features = ["mmap"] }
The project includes benchmarks using Criterion.rs.
First you need to have a working copy of the GeoIP City database. You can fetch it from here.
Place it in the root folder as GeoLite2-City.mmdb.
Once this is done, run
cargo bench
Two focused benchmarks are especially useful while iterating on changes:
cargo bench --bench lookup
cargo bench --bench serde_usage
The serde_usage suite covers typed records, ignored fields, generic JSON
values, raw-string adapters, and selective paths. The decode_raw_strings
case walks every record using borrowed identifier bytes and
deserialize_any_with_raw_strings, as language bindings do, without adding
another runtime's allocation costs. It detects decoder overhead that typed
record benchmarks can miss.
Criterion.rs generates an HTML report at target/criterion/report/index.html.
It uses gnuplot when available and the bundled Plotters backend otherwise.
Contributions welcome! Please fork the repository and open a pull request with your changes.
This is free software, licensed under the ISC license.
1,024 followers · starred Feb 2023
46 followers · starred Jul 2016
15 followers · starred Sep 2023