5.9 KiB
xdb-parse
A parser to xdb files like ip2region A high-performance Rust library for parsing and querying IP database files (xdb format) like ip2region. Supports both IPv4 and IPv6 address lookup with efficient binary search algorithms.
Features
- Dual Protocol Support: Full support for both IPv4 and IPv6 address lookup
- High Performance: Optimized binary search algorithm for fast IP queries
- Memory Efficient: Load database files once and query multiple times
- Thread Safe: Designed for concurrent usage in multi-threaded environments
- Flexible Input: Accepts IP addresses in multiple formats (string, numeric)
- Zero Dependencies: Minimal external dependencies for reliability
Installation
Add this to your Cargo.toml:
[dependencies]
xdb-parse = "0.1.0"
Quick Start
Basic Usage
use xdb_parse::utils::{load_file, search_ip};
use anyhow::Result;
fn main() -> Result<()> {
// Load the IP database file
let path = "./assets/ip2region_v4.xdb";
let data = load_file(path.into())?;
// Search for an IP address
let result = search_ip("73.24.63.66", &data)?;
println!("IP location: {}", result);
Ok(())
}
IPv6 Support
use xdb_parse::utils::{load_file, search_ip};
use anyhow::Result;
fn main() -> Result<()> {
// Load IPv6 database
let path = "./assets/ip2region_v6.xdb";
let data = load_file(path.into())?;
// Search for IPv6 address
let result = search_ip("2001:0db8:85a3:0000:0000:8a2e:0370:7334", &data)?;
println!("IPv6 location: {}", result);
Ok(())
}
Examples
Example 1: Basic IP Lookup
See examples/search_ip.rs:
use std::time::Instant;
use anyhow::Result;
use xdb_parse::utils::{load_file, search_ip};
fn main() -> Result<()> {
let start = Instant::now();
let path = "./assets/ip2region_v4.xdb";
let data = load_file(path.into())?;
let ret = search_ip("73.24.63.66", &data)?;
let time = start.elapsed();
println!("Search time: {:?} - Result: {}", time, ret);
Ok(())
}
Example 2: Multi-threaded Usage
The library is designed for thread-safe concurrent usage:
use std::{sync::Arc, thread};
use xdb_parse::utils::{load_file, search_ip};
use anyhow::Result;
fn main() -> Result<()> {
let path = "./assets/ip2region_v6.xdb";
let data = Arc::new(load_file(path.into())?);
let data_clone = Arc::clone(&data);
let handle = thread::spawn(move || {
let result = search_ip("2408:8352:da10:1ad:c283:c9ff:fec6:4046", &data_clone).unwrap();
println!("Thread result: {}", result);
});
// Main thread can also query
let result = search_ip("2408:8352:da10:1ad:c283:c9ff:fec6:4046", &data)?;
println!("Main thread result: {}", result);
handle.join().unwrap();
Ok(())
}
Example 3: Performance Benchmarking
See benches/search.rs for performance testing:
use criterion::{Criterion, criterion_group, criterion_main};
use xdb_parse::utils::{load_file, search_ip};
fn search_benchmark(c: &mut Criterion) {
c.bench_function("ipv4_search", |b| {
let path = "./assets/ip2region_v4.xdb";
let data = load_file(path.into()).unwrap();
b.iter(|| {
search_ip("73.24.63.66", &data).unwrap();
})
});
}
criterion_group!(benches, search_benchmark);
criterion_main!(benches);
API Reference
Core Functions
load_file(path: PathBuf) -> Result<Vec<u8>, XdbError>
Loads an xdb database file into memory.
Parameters:
path: Path to the xdb file
Returns: Byte vector containing the database data
search_ip(ip: &str, data: &[u8]) -> Result<String, XdbError>
Searches for an IP address in the loaded database.
Parameters:
ip: IP address to search (supports multiple formats)data: Database data loaded byload_file
Returns: Location information as string
Supported IP Formats
The library accepts IP addresses in multiple formats:
// Standard IPv4 format
search_ip("192.168.1.1", &data)?;
// Standard IPv6 format
search_ip("2001:0db8:85a3::0370:7334", &data)?;
// Numeric format (IPv4)
search_ip("3232235777", &data)?; // Equivalent to 192.168.1.1
// Numeric format (IPv6)
search_ip("42540766411282592856903984951653826560", &data)?;
Database File Format
The library supports the xdb format used by ip2region:
- Header: 256 bytes containing metadata
- Vector Index: 256×256 index blocks for fast lookup
- Segment Data: IP range segments with location information
File Structure
┌─────────────────┐
│ Header │ 256 bytes
├─────────────────┤
│ Vector Index │ 256×256×8 bytes
├─────────────────┤
│ Segment Data │ Variable length
└─────────────────┘
Performance
The library uses an optimized binary search algorithm:
- IPv4 Lookup: ~5 microseconds per query
- IPv6 Lookup: ~250 microseconds per query
- Memory Usage: Database loaded once, shared across threads
Error Handling
The library uses thiserror for comprehensive error handling:
use xdb_parse::error::XdbError;
match search_ip("invalid_ip", &data) {
Ok(result) => println!("Location: {}", result),
Err(XdbError::InvalidIP(msg)) => println!("Invalid IP: {}", msg),
Err(e) => println!("Error: {}", e),
}
Running Examples
To run the provided examples:
# Run the basic search example
cargo run --example search_ip
# Run benchmarks
cargo bench
# Run tests
cargo test
License
This project is licensed under the same terms as Rust itself.
Contributing
Contributions are welcome! Please feel free to submit issues and pull requests.
Acknowledgments
- Inspired by the ip2region project
- Uses efficient binary search algorithms for fast IP lookup
- Designed for high-performance applications