If you want to use our IPinfo MMDB database in a Rust environment, here are some high-level notes for you:
- You need to use the Rust MMDB reader library.
- The Rust MMDB reader crate does not support IPinfo MMDB IP databases out of the box. It is just an MMDB reader library. You have to deserialize/serialize the response from the library.
- You have to declare a
struct
based on the IPinfo IP database schema. You can find the database schema in our documentation. - The IPinfo Rust Official Library only supports the IPinfo API and does not work with the MMDB database.
Okay, now that we have the fundamentals covered, let’s go through a basic tutorial. You will need Rust, Cargo and all that stuff. For the IPinfo IP database, we will use the IPinfo free IP database, the IP to Country ASN database.
Initializing the Rust project
Initialize the Rust project with the following command with package name being ipinfo_mmdb
:
cargo new ipinfo_mmdb
cd ipinfo_mmdb
In your Cargo.toml
file, bring in the required crates:
[dependencies]
maxminddb = "0.24.0"
serde = "1.0.197"
Your crate versions can be different. Check out the latest version from their crates.io pages:
After that, you are ready to write some basic code.
Downloading the IPinfo MMDB database
You can use whatever IPinfo IP database you have access to; just make sure you download the MMDB database. We are going to use the IPinfo IP to Country ASN database.
Run the following code from your terminal to download the IP to Country ASN database:
curl -L https://ipinfo.io/data/free/country_asn.mmdb?token=$TOKEN -o country_asn.mmdb
Make sure to replace the $token
placeholder with your IPinfo access token. The above command will download the IPinfo IP to Country ASN MMDB database in your directory with the filename country_asn.mmdb
IP Query code in Rust
The [main.rs](http://main.rs)
code
use maxminddb::MaxMindDBError;
use std::net::IpAddr;
use serde::{Deserialize, Serialize};
// Declare the struct based on the IPinfo IP database schema
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct IpinfoCountryASN<'a> {
pub country: Option<&'a str>,
pub country_name: Option<&'a str>,
pub continent: Option<&'a str>,
pub continent_name: Option<&'a str>,
pub asn: Option<&'a str>,
pub as_name: Option<&'a str>,
pub as_domain: Option<&'a str>,
}
fn main() -> Result<(), MaxMindDBError> {
// Replace with the actual path to your IPinfo IP database MMDB path
let mmdb_path = "./country_asn.mmdb";
// Open the MMDB IP database
let reader = maxminddb::Reader::open_readfile(&mmdb_path)?;
// Replace with the IP address you want to look up
let ip_address: IpAddr = "78.35.248.93".parse().expect("Failed to parse IP");
// Perform the IP address lookup
let record: IpinfoCountryASN = reader.lookup(ip_address).unwrap();
// Return IP query response
println!("Country: {}", record.country.unwrap());
println!("Country Name: {}", record.country_name.unwrap());
println!("Continent: {}", record.continent.unwrap());
println!("Continent Name: {}", record.continent_name.unwrap());
println!("ASN: {}", record.asn.unwrap());
println!("AS Organization Name: {}", record.as_name.unwrap());
println!("AS Domain/Website: {}", record.as_domain.unwrap());
println!("Payload: {:?}", record);
Ok(())
}
Let’s go through the code block by block.
use
statements
use maxminddb::MaxMindDBError;
use std::net::IpAddr;
use serde::{Deserialize, Serialize};
maxminddb
is the MMDB reader crate. We will also use theMaxMindDBError
function to handle IP addresses that are not present in the MMDB database.std::net::IpAddr
is from the standard library. We will use it to parse IP addresses from string format toIpAddr
format.serde
will be used to deserialize and serialize the response from the MMDB IP query response.
Declaring the struct
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct IpinfoCountryASN<'a> {
pub country: Option<&'a str>,
pub country_name: Option<&'a str>,
pub continent: Option<&'a str>,
pub continent_name: Option<&'a str>,
pub asn: Option<&'a str>,
pub as_name: Option<&'a str>,
pub as_domain: Option<&'a str>,
}
We will declare a struct
using serde
. This is based on the IPinfo IP to Country ASN database schema. In the struct declaration, we will include all the IP metadata columns, which do not contain an IP address, as the MMDB reader only returns the IP metadata as a response.
We are using Option<&'a str>
for declaring the values for optional string references. Usually, for all our database values, we return a string, except for our privacy detection database, where we return ""
(empty string) or true
for privacy detection flags (VPN, hosting, proxy, tor, and relay).
Main function
fn main() -> Result<(), MaxMindDBError>
Our main function runs the core lookup logic with errors being caught by MaxMindDBError
error type. If the IP address does not exist in the MMDB database or is a bogon IP address, you will see the following error:
thread 'main' panicked at src/main.rs:29:62:
called `Result::unwrap()` on an `Err` value: AddressNotFoundError("Address not found in database")
let mmdb_path = "./country_asn.mmdb";
let reader = maxminddb::Reader::open_readfile(&mmdb_path)?;
Provide the path to the mmdb
IP database. Ensure you have the IP database name and path correct, or you will get an IoError
. Using the provided path, the MMDB reader crate will convert the MMDB database and create the reader
object that will be used to query IP addresses from the MMDB IP database.
let reader = maxminddb::Reader::open_readfile(&mmdb_path)?;
let ip_address: IpAddr = "78.35.248.93".parse().expect("Failed to parse IP address");
This section accepts the input IP address as a string and converts it to the IpAddr
data type using the std::net
standard library. In this example, we are using the random IP address 78.35.248.93
Then, using the reader
object, we look up the input IP address from the MMDB database and store the MMDB response IP metadata in the record variable, which is the type IpinfoCountryASN
println!("Country: {}", record.country.unwrap());
println!("Country Name: {}", record.country_name.unwrap());
println!("Continent: {}", record.continent.unwrap());
println!("Continent Name: {}", record.continent_name.unwrap());
println!("ASN: {}", record.asn.unwrap());
println!("AS Organization Name: {}", record.as_name.unwrap());
println!("AS Domain/Website: {}", record.as_domain.unwrap());
println!("Payload: {:?}", record);
Then, we print out the individual values from the record
response and the entire payload.
Country: DE
Country Name: Germany
Continent: EU
Continent Name: Europe
ASN: AS8422
AS Organization Name: NetCologne Gesellschaft fur Telekommunikation mbH
AS Domain/Website: netcologne.de
Payload: IpinfoCountryASN { country: Some("DE"), country_name: Some("Germany"), continent: Some("EU"), continent_name: Some("Europe"), asn: Some("AS8422"), as_name: Some("NetCologne Gesellschaft fur Telekommunikation mbH"), as_domain: Some("netcologne.de") }
That is the gist of using our MMDB dataset in Rust.