1use std::cmp::Ordering;
4use std::net::{IpAddr, Ipv6Addr};
5
6use crate::decoder;
7use crate::error::MaxMindDbError;
8use crate::reader::Reader;
9use crate::result::{LookupResult, LookupSource, NetworkKind};
10
11#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
33pub struct WithinOptions {
34 include_aliased_networks: bool,
36 include_networks_without_data: bool,
38 skip_empty_values: bool,
40}
41
42impl WithinOptions {
43 #[must_use]
52 pub fn include_aliased_networks(mut self) -> Self {
53 self.include_aliased_networks = true;
54 self
55 }
56
57 #[must_use]
63 pub fn include_networks_without_data(mut self) -> Self {
64 self.include_networks_without_data = true;
65 self
66 }
67
68 #[must_use]
73 pub fn skip_empty_values(mut self) -> Self {
74 self.skip_empty_values = true;
75 self
76 }
77}
78
79#[derive(Debug)]
80pub(crate) struct WithinNode {
81 pub(crate) node: usize,
82 pub(crate) ip_int: IpInt,
83 pub(crate) prefix_len: usize,
84}
85
86#[derive(Debug)]
114pub struct Within<'de, S: AsRef<[u8]>> {
115 pub(crate) reader: &'de Reader<S>,
116 pub(crate) node_count: usize,
117 pub(crate) has_ipv4_subtree: bool,
118 pub(crate) stack: Vec<WithinNode>,
119 pub(crate) options: WithinOptions,
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub(crate) enum IpInt {
124 V4(u32),
125 V6(u128),
126}
127
128impl IpInt {
129 pub(crate) fn new(ip_addr: IpAddr) -> Self {
130 match ip_addr {
131 IpAddr::V4(v4) => IpInt::V4(v4.into()),
132 IpAddr::V6(v6) => IpInt::V6(v6.into()),
133 }
134 }
135
136 #[inline(always)]
137 pub(crate) fn get_bit(&self, index: usize) -> bool {
138 match self {
139 IpInt::V4(ip) => (ip >> (31 - index)) & 1 == 1,
140 IpInt::V6(ip) => (ip >> (127 - index)) & 1 == 1,
141 }
142 }
143
144 #[inline(always)]
145 pub(crate) fn set_bit(&mut self, index: usize) {
146 match self {
147 IpInt::V4(ip) => *ip |= 1 << (31 - index),
148 IpInt::V6(ip) => *ip |= 1 << (127 - index),
149 }
150 }
151
152 pub(crate) fn bit_count(&self) -> usize {
153 match self {
154 IpInt::V4(_) => 32,
155 IpInt::V6(_) => 128,
156 }
157 }
158
159 pub(crate) fn is_ipv4_in_ipv6(&self) -> bool {
160 match self {
161 IpInt::V4(_) => false,
162 IpInt::V6(ip) => *ip <= 0xFFFFFFFF,
163 }
164 }
165}
166
167impl<'de, S: AsRef<[u8]>> Iterator for Within<'de, S> {
168 type Item = Result<LookupResult<'de, S>, MaxMindDbError>;
169
170 fn next(&mut self) -> Option<Self::Item> {
171 while let Some(current) = self.stack.pop() {
172 let bit_count = current.ip_int.bit_count();
173
174 if !self.options.include_aliased_networks
176 && self.has_ipv4_subtree
177 && self.reader.ipv4_start != 0
178 && current.node == self.reader.ipv4_start
179 && bit_count == 128
180 && !current.ip_int.is_ipv4_in_ipv6()
181 {
182 continue;
183 }
184
185 match current.node.cmp(&self.node_count) {
186 Ordering::Greater => {
187 let data_offset = match self.reader.resolve_data_pointer(current.node) {
190 Ok(offset) => offset,
191 Err(e) => return Some(Err(e)),
192 };
193
194 if self.options.skip_empty_values {
196 match self.is_empty_value_at(data_offset) {
197 Ok(true) => continue, Ok(false) => {} Err(e) => return Some(Err(e)),
200 }
201 }
202
203 let network_kind = self.network_kind(¤t);
204 let ip_addr = network_ip_addr(network_kind, current.ip_int);
205
206 return Some(Ok(LookupResult::new_found(
207 self.reader,
208 data_offset,
209 current.prefix_len as u8,
210 ip_addr,
211 LookupSource::Iter,
212 network_kind,
213 )));
214 }
215 Ordering::Equal => {
216 if self.options.include_networks_without_data {
218 let network_kind = self.network_kind(¤t);
219 let ip_addr = network_ip_addr(network_kind, current.ip_int);
220 return Some(Ok(LookupResult::new_not_found(
221 self.reader,
222 current.prefix_len as u8,
223 ip_addr,
224 LookupSource::Iter,
225 network_kind,
226 )));
227 }
228 }
230 Ordering::Less => {
231 if current.prefix_len >= bit_count {
232 return Some(Err(MaxMindDbError::invalid_database(
233 "search tree appears to have a cycle or invalid structure (traversal exceeded the address bit length)",
234 )));
235 }
236 let mut right_ip_int = current.ip_int;
239
240 if current.prefix_len < bit_count {
241 right_ip_int.set_bit(current.prefix_len);
242 }
243
244 self.push_child(current.node, 1, right_ip_int, current.prefix_len + 1);
245 self.push_child(current.node, 0, current.ip_int, current.prefix_len + 1);
247 }
248 }
249 }
250 None
251 }
252}
253
254impl<'de, S: AsRef<[u8]>> Within<'de, S> {
255 #[inline(always)]
256 fn network_kind(&self, node: &WithinNode) -> NetworkKind {
257 match node.ip_int {
258 IpInt::V4(_) if self.reader.metadata().ip_version == 6 && !self.has_ipv4_subtree => {
259 NetworkKind::V6
260 }
261 IpInt::V4(_) => NetworkKind::V4,
262 IpInt::V6(_)
263 if node.ip_int.is_ipv4_in_ipv6()
264 && self.has_ipv4_subtree
265 && node.prefix_len >= self.reader.ipv4_start_bit_depth =>
266 {
267 NetworkKind::V4InV6Subtree
268 }
269 IpInt::V6(_) => NetworkKind::V6,
270 }
271 }
272
273 fn push_child(
274 &mut self,
275 parent_node: usize,
276 direction: usize,
277 ip_int: IpInt,
278 prefix_len: usize,
279 ) {
280 let node = self.reader.read_node(parent_node, direction);
281 self.stack.push(WithinNode {
282 node,
283 ip_int,
284 prefix_len,
285 });
286 }
287
288 fn is_empty_value_at(&self, data_offset: usize) -> Result<bool, MaxMindDbError> {
290 let buf = &self.reader.buf.as_ref()[self.reader.pointer_base..];
291 let mut dec =
292 decoder::Decoder::new_with_limit(buf, data_offset, self.reader.data_section_len);
293 let (size, type_num) = dec
294 .peek_type()
295 .map_err(|error| error.with_invalid_database_offset_base(self.reader.pointer_base))?;
296 match type_num {
297 decoder::TYPE_MAP | decoder::TYPE_ARRAY => Ok(size == 0),
298 _ => Ok(false), }
300 }
301}
302
303#[inline(always)]
304fn network_ip_addr(network_kind: NetworkKind, ip_int: IpInt) -> IpAddr {
305 let ip_addr = ip_int_to_addr(&ip_int);
306 match (network_kind, ip_int, ip_addr) {
307 (NetworkKind::V6, IpInt::V6(ip), IpAddr::V4(_)) => IpAddr::V6(ip.into()),
311 (NetworkKind::V6, IpInt::V4(_), IpAddr::V4(_)) => IpAddr::V6(Ipv6Addr::UNSPECIFIED),
314 (_, _, ip_addr) => ip_addr,
315 }
316}
317
318#[inline(always)]
320pub(crate) fn ip_int_to_addr(ip_int: &IpInt) -> IpAddr {
321 match ip_int {
322 IpInt::V4(ip) => IpAddr::V4((*ip).into()),
323 IpInt::V6(ip) => {
324 if *ip <= 0xFFFFFFFF {
326 IpAddr::V4((*ip as u32).into())
327 } else {
328 IpAddr::V6((*ip).into())
329 }
330 }
331 }
332}
333
334#[cfg(test)]
335mod tests {
336 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
337
338 use crate::result::NetworkKind;
339
340 use super::{network_ip_addr, IpInt};
341
342 #[test]
343 fn network_ip_addr_preserves_low_ipv6_bits() {
344 assert_eq!(
345 network_ip_addr(NetworkKind::V6, IpInt::V6(1)),
346 IpAddr::V6(Ipv6Addr::from(1_u128))
347 );
348 }
349
350 #[test]
351 fn network_ip_addr_formats_ipv4_subtree_records_as_ipv4() {
352 assert_eq!(
353 network_ip_addr(NetworkKind::V4InV6Subtree, IpInt::V6(1)),
354 IpAddr::V4(Ipv4Addr::from(1_u32))
355 );
356 }
357}