1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! # Custom Database Builder Example for libmaxminddb-rs
//!
//! This example shows how to build and configure a custom MMDB file from scratch:
//! - Configuring database metadata (record size, IP version, multi-language descriptions).
//! - Inserting both IPv4 and IPv6 networks into the same database.
//! - Writing the database directly to a disk file.
//! - Opening the resulting file with memory mapping (`open_mmap`).
//!
//! Run this example with:
//! ```bash
//! cargo run --example custom_database
//! ```
use std::error::Error;
use std::net::IpAddr;
use std::path::Path;
use libmaxminddb_rs::{MetadataBuilder, MmdbDecode, MmdbEncode, Reader, Writer};
#[derive(Debug, PartialEq, MmdbEncode, MmdbDecode)]
struct NetworkPolicy<'a> {
zone: &'a str,
rate_limit_rps: u32,
allowed_protocols: Vec<&'a str>,
}
fn main() -> Result<(), Box<dyn Error>> {
println!("=== libmaxminddb-rs Custom Database Builder Example ===\n");
let db_path = Path::new("target/custom_policy.mmdb");
// -----------------------------------------------------------------------
// 1. Build metadata with custom specifications
// -----------------------------------------------------------------------
println!("1. Configuring database metadata...");
let metadata = MetadataBuilder::new()
.database_type("Network-Policy-DB")
// An IPv6 database can store both IPv4 (mapped) and IPv6 subnets:
.ip_version(6)
.build_epoch(1700000000)
.language("en")
.language("fr")
.description("en", "Custom network policy routing database")
.description("fr", "Base de données de politiques réseau")
.build()?;
let mut writer = Writer::with_metadata(metadata);
// -----------------------------------------------------------------------
// 2. Insert IPv4 and IPv6 network policies
// -----------------------------------------------------------------------
println!("2. Inserting network policy rules...");
// IPv4 internal zone
writer.insert_encoded(
"10.0.0.0/8".parse()?,
&NetworkPolicy {
zone: "internal_trusted",
rate_limit_rps: 50_000,
allowed_protocols: vec!["https", "ssh", "grpc"],
},
)?;
// IPv4 external DMZ zone
writer.insert_encoded(
"198.51.100.0/24".parse()?,
&NetworkPolicy {
zone: "dmz_public",
rate_limit_rps: 1_000,
allowed_protocols: vec!["https"],
},
)?;
// IPv6 internal management zone
writer.insert_encoded(
"2001:db8:acad::/48".parse()?,
&NetworkPolicy {
zone: "ipv6_management",
rate_limit_rps: 10_000,
allowed_protocols: vec!["https", "ssh"],
},
)?;
// -----------------------------------------------------------------------
// 3. Write database to disk
// -----------------------------------------------------------------------
println!("3. Writing database to: {}", db_path.display());
std::fs::create_dir_all(db_path.parent().unwrap())?;
writer.write_to_file(db_path)?;
let file_size = std::fs::metadata(db_path)?.len();
println!(
" File successfully created (size: {} bytes).\n",
file_size
);
// -----------------------------------------------------------------------
// 4. Open via memory mapping (open_mmap)
// -----------------------------------------------------------------------
println!("4. Re-opening with zero-copy memory mapping (`open_mmap`)...");
// SAFETY: The file is not modified while open.
let reader = unsafe { Reader::open_mmap(db_path)? };
// Inspect metadata
let meta = reader.metadata();
println!(" ↳ Database Type : {}", meta.database_type);
println!(" ↳ IP Version : IPv{}", meta.ip_version);
println!(" ↳ Record Size : {} bits", meta.record_size);
println!(" ↳ Node Count : {}", meta.node_count);
// -----------------------------------------------------------------------
// 5. Query IPv4 and IPv6 addresses
// -----------------------------------------------------------------------
println!("\n5. Querying policies across address families:");
let queries: &[(&str, &str)] = &[
("10.50.1.20", "IPv4 internal address"),
("198.51.100.5", "IPv4 DMZ address"),
("2001:db8:acad::1", "IPv6 management address"),
];
for &(ip_str, desc) in queries {
let ip: IpAddr = ip_str.parse()?;
let policy: NetworkPolicy<'_> = reader.lookup_borrowed(ip)?;
println!(" IP: {} ({})", ip, desc);
println!(" ↳ Zone : {}", policy.zone);
println!(" ↳ Rate Limit : {} rps", policy.rate_limit_rps);
println!(" ↳ Protocols : {:?}\n", policy.allowed_protocols);
}
// Clean up temporary file
let _ = std::fs::remove_file(db_path);
println!("Custom database builder example completed successfully!");
Ok(())
}