1use std::collections::HashSet;
4use std::fs;
5use std::net::IpAddr;
6use std::path::Path;
7
8use ipnetwork::IpNetwork;
9use serde::Deserialize;
10
11#[cfg(feature = "mmap")]
12pub use memmap2::Mmap;
13#[cfg(feature = "mmap")]
14use memmap2::MmapOptions;
15#[cfg(feature = "mmap")]
16use std::fs::File;
17
18use crate::decoder;
19use crate::error::MaxMindDbError;
20use crate::metadata::Metadata;
21use crate::result::{LookupResult, LookupSource, NetworkKind};
22use crate::within::{IpInt, Within, WithinNode, WithinOptions};
23
24const DATA_SECTION_SEPARATOR_SIZE: usize = 16;
26const METADATA_START_MARKER: &[u8] = b"\xab\xcd\xefMaxMind.com";
27
28pub struct Reader<S: AsRef<[u8]>> {
43 pub(crate) buf: S,
44 metadata: Metadata,
46 record_size: u16,
47 node_count: usize,
50 node_byte_size: usize,
53 pub(crate) ipv4_start: usize,
54 pub(crate) ipv4_start_bit_depth: usize,
57 pub(crate) pointer_base: usize,
58 pub(crate) data_section_len: usize,
59 pub(crate) metadata_start: usize,
60}
61
62impl<S: AsRef<[u8]>> std::fmt::Debug for Reader<S> {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 f.debug_struct("Reader")
65 .field("buf_len", &self.buf.as_ref().len())
66 .field("metadata", &self.metadata)
67 .field("ipv4_start", &self.ipv4_start)
68 .field("ipv4_start_bit_depth", &self.ipv4_start_bit_depth)
69 .field("pointer_base", &self.pointer_base)
70 .field("data_section_len", &self.data_section_len)
71 .field("metadata_start", &self.metadata_start)
72 .finish_non_exhaustive()
73 }
74}
75
76#[cfg(feature = "mmap")]
77impl Reader<Mmap> {
78 pub unsafe fn open_mmap<P: AsRef<Path>>(database: P) -> Result<Reader<Mmap>, MaxMindDbError> {
98 let file_read = File::open(database)?;
99 let mmap = MmapOptions::new()
100 .map(&file_read)
101 .map_err(MaxMindDbError::Mmap)?;
102 Reader::from_source(mmap)
103 }
104}
105
106impl Reader<Vec<u8>> {
107 pub fn open_readfile<P: AsRef<Path>>(database: P) -> Result<Reader<Vec<u8>>, MaxMindDbError> {
116 let buf: Vec<u8> = fs::read(&database)?; Reader::from_source(buf)
118 }
119}
120
121impl<'de, S: AsRef<[u8]>> Reader<S> {
122 pub fn from_source(buf: S) -> Result<Reader<S>, MaxMindDbError> {
132 let metadata_start = find_metadata_start(buf.as_ref())?;
133 let data_section_end = metadata_marker_start(metadata_start)?;
136 let mut type_decoder = decoder::Decoder::new(&buf.as_ref()[metadata_start..], 0);
137 let metadata = Metadata::deserialize(&mut type_decoder)?;
138 validate_metadata_for_reader(&metadata)?;
139
140 let search_tree_size =
141 search_tree_size_bytes(metadata.node_count as usize, metadata.record_size as usize)?;
142 let record_size = metadata.record_size;
143 let node_count = metadata.node_count as usize;
144 let node_byte_size = record_size as usize / 4;
145 let pointer_base = search_tree_size
146 .checked_add(DATA_SECTION_SEPARATOR_SIZE)
147 .ok_or_else(|| {
148 MaxMindDbError::invalid_database(
149 "the MaxMind DB file's search tree extends beyond the file",
150 )
151 })?;
152 validate_search_tree_layout(pointer_base, data_section_end)?;
153 let data_section_len = data_section_end - pointer_base;
154
155 let mut reader = Reader {
156 buf,
157 record_size,
158 node_count,
159 node_byte_size,
160 pointer_base,
161 data_section_len,
162 metadata_start,
163 metadata,
164 ipv4_start: 0,
165 ipv4_start_bit_depth: 0,
166 };
167 let (ipv4_start, ipv4_start_bit_depth) = reader.find_ipv4_start();
168 reader.ipv4_start = ipv4_start;
169 reader.ipv4_start_bit_depth = ipv4_start_bit_depth;
170
171 Ok(reader)
172 }
173
174 #[inline]
179 pub fn metadata(&self) -> &Metadata {
180 &self.metadata
181 }
182
183 pub fn lookup(&'de self, address: IpAddr) -> Result<LookupResult<'de, S>, MaxMindDbError> {
233 match address {
234 IpAddr::V4(v4) => {
235 let (pointer, prefix_len) = self.find_address_in_tree_v4(v4.into());
236
237 let prefix_len = if self.metadata.ip_version == 6 {
241 self.ipv4_start_bit_depth + prefix_len
242 } else {
243 prefix_len
244 };
245
246 self.lookup_result(pointer, prefix_len as u8, address)
247 }
248 IpAddr::V6(v6) => {
249 if self.metadata.ip_version == 4 {
250 return Err(MaxMindDbError::invalid_input(
251 "cannot look up IPv6 address in IPv4-only database",
252 ));
253 }
254
255 let (pointer, prefix_len) = self.find_address_in_tree_v6(v6.into());
256 self.lookup_result(pointer, prefix_len as u8, address)
257 }
258 }
259 }
260
261 pub fn networks(&'de self, options: WithinOptions) -> Result<Within<'de, S>, MaxMindDbError> {
288 let cidr = if self.metadata.ip_version == 6 {
289 IpNetwork::V6("::/0".parse().unwrap())
290 } else {
291 IpNetwork::V4("0.0.0.0/0".parse().unwrap())
292 };
293 self.within(cidr, options)
294 }
295
296 pub fn within(
368 &'de self,
369 cidr: IpNetwork,
370 options: WithinOptions,
371 ) -> Result<Within<'de, S>, MaxMindDbError> {
372 if self.metadata.ip_version == 4 && matches!(cidr, IpNetwork::V6(_)) {
373 return Err(MaxMindDbError::invalid_input(
374 "cannot iterate IPv6 network in IPv4-only database",
375 ));
376 }
377 let ip_address = cidr.network();
378 let prefix_len = cidr.prefix() as usize;
379 let ip_int = IpInt::new(ip_address);
380 let bit_count = ip_int.bit_count();
381
382 let mut node = self.start_node(bit_count);
383 let node_count = self.node_count;
384 let has_ipv4_subtree = self.has_ipv4_subtree();
385
386 let mut stack: Vec<WithinNode> = Vec::with_capacity(bit_count - prefix_len);
387
388 if bit_count == 32
394 && self.metadata.ip_version == 6
395 && !has_ipv4_subtree
396 && node >= node_count
397 {
398 stack.push(WithinNode {
399 node,
400 ip_int: IpInt::V6(0),
401 prefix_len: self.ipv4_start_bit_depth,
402 });
403
404 return Ok(Within {
405 reader: self,
406 node_count,
407 has_ipv4_subtree,
408 stack,
409 options,
410 });
411 }
412
413 let mut depth = 0_usize;
415 for i in 0..prefix_len {
416 if node >= node_count {
418 break;
421 }
422
423 let bit = ip_int.get_bit(i);
424 node = self.read_node(node, bit as usize);
425 depth = i + 1; if node >= node_count {
428 break;
431 }
432 }
433
434 stack.push(WithinNode {
439 node,
440 ip_int,
441 prefix_len: depth,
442 });
443
444 let within = Within {
445 reader: self,
446 node_count,
447 has_ipv4_subtree,
448 stack,
449 options,
450 };
451
452 Ok(within)
453 }
454
455 #[inline(always)]
461 fn lookup_result(
462 &'de self,
463 pointer: usize,
464 prefix_len: u8,
465 address: IpAddr,
466 ) -> Result<LookupResult<'de, S>, MaxMindDbError> {
467 let network_kind = match address {
468 IpAddr::V4(_) if self.metadata.ip_version == 6 && self.has_ipv4_subtree() => {
469 NetworkKind::V4InV6Subtree
470 }
471 IpAddr::V4(_) if self.metadata.ip_version == 6 => NetworkKind::V6,
472 IpAddr::V4(_) => NetworkKind::V4,
473 IpAddr::V6(_) => NetworkKind::V6,
474 };
475 if pointer == 0 {
476 Ok(LookupResult::new_not_found(
477 self,
478 prefix_len,
479 address,
480 LookupSource::Lookup,
481 network_kind,
482 ))
483 } else {
484 let data_offset = self.resolve_data_pointer(pointer)?;
485 Ok(LookupResult::new_found(
486 self,
487 data_offset,
488 prefix_len,
489 address,
490 LookupSource::Lookup,
491 network_kind,
492 ))
493 }
494 }
495
496 #[inline(always)]
497 fn find_address_in_tree_v4(&self, ip: u32) -> (usize, usize) {
498 let buf = self.buf.as_ref();
499 let node_count = self.node_count;
500
501 match self.record_size {
502 24 => find_address_in_tree_v4::<RecordSize24>(buf, self.ipv4_start, node_count, ip),
503 28 => find_address_in_tree_v4::<RecordSize28>(buf, self.ipv4_start, node_count, ip),
504 32 => find_address_in_tree_v4::<RecordSize32>(buf, self.ipv4_start, node_count, ip),
505 _ => unreachable!("record_size is validated in Reader::from_source"),
506 }
507 }
508
509 #[inline(always)]
510 fn find_address_in_tree_v6(&self, ip: u128) -> (usize, usize) {
511 let buf = self.buf.as_ref();
512 let node_count = self.node_count;
513
514 match self.record_size {
515 24 => find_address_in_tree_v6::<RecordSize24>(buf, node_count, ip),
516 28 => find_address_in_tree_v6::<RecordSize28>(buf, node_count, ip),
517 32 => find_address_in_tree_v6::<RecordSize32>(buf, node_count, ip),
518 _ => unreachable!("record_size is validated in Reader::from_source"),
519 }
520 }
521
522 #[inline]
523 fn start_node(&self, length: usize) -> usize {
524 if length == 128 {
525 0
526 } else {
527 self.ipv4_start
528 }
529 }
530
531 #[inline]
532 pub(crate) fn has_ipv4_subtree(&self) -> bool {
533 self.metadata.ip_version == 6 && self.ipv4_start < self.node_count
534 }
535
536 fn find_ipv4_start(&self) -> (usize, usize) {
539 if self.metadata.ip_version != 6 {
540 return (0, 0);
541 }
542
543 let mut node: usize = 0;
546 for i in 0_u8..96 {
547 if node >= self.node_count {
548 return (node, i as usize);
549 }
550 node = self.read_node(node, 0);
551 }
552 (node, 96)
553 }
554
555 #[inline(always)]
556 pub(crate) fn read_node(&self, node_number: usize, index: usize) -> usize {
557 let buf = self.buf.as_ref();
558
559 match self.record_size {
560 24 => RecordSize24::read_node(buf, node_number, index),
561 28 => RecordSize28::read_node(buf, node_number, index),
562 32 => RecordSize32::read_node(buf, node_number, index),
563 _ => unreachable!("record_size is validated in Reader::from_source"),
564 }
565 }
566
567 #[inline]
569 pub(crate) fn resolve_data_pointer(&self, pointer: usize) -> Result<usize, MaxMindDbError> {
570 let resolved = pointer
571 .checked_sub(self.node_count)
572 .and_then(|p| p.checked_sub(DATA_SECTION_SEPARATOR_SIZE))
573 .ok_or_else(|| {
574 MaxMindDbError::invalid_database(
575 "the MaxMind DB file's data pointer resolves to an invalid location",
576 )
577 })?;
578 if resolved >= self.data_section_len {
580 return Err(MaxMindDbError::invalid_database(
581 "the MaxMind DB file's data pointer resolves to an invalid location",
582 ));
583 }
584
585 Ok(resolved)
586 }
587
588 pub fn verify(&self) -> Result<(), MaxMindDbError> {
617 let metadata_start = find_metadata_start(self.buf.as_ref())?;
618 let data_section_end = metadata_marker_start(metadata_start)?;
619 self.verify_metadata(data_section_end)?;
620 self.verify_database(data_section_end)
621 }
622
623 fn verify_metadata(&self, data_section_end: usize) -> Result<(), MaxMindDbError> {
624 let m = &self.metadata;
625
626 validate_metadata_for_reader(m)?;
627 if m.database_type.is_empty() {
628 return Err(MaxMindDbError::invalid_database(
629 "database_type - Expected: non-empty string Actual: \"\"",
630 ));
631 }
632 if m.description.is_empty() {
633 return Err(MaxMindDbError::invalid_database(
634 "description - Expected: non-empty map Actual: {}",
635 ));
636 }
637 validate_search_tree_layout(self.pointer_base, data_section_end)?;
638 Ok(())
639 }
640
641 fn verify_database(&self, data_section_end: usize) -> Result<(), MaxMindDbError> {
642 let offsets = self.verify_search_tree()?;
643 self.verify_data_section_separator()?;
644 self.verify_data_section(offsets, data_section_end)
645 }
646
647 fn verify_search_tree(&self) -> Result<HashSet<usize>, MaxMindDbError> {
648 let mut offsets = HashSet::new();
649 let opts = WithinOptions::default().include_networks_without_data();
650
651 let max_iterations = self.node_count.saturating_mul(3);
655 let mut iteration_count = 0usize;
656
657 for result in self.networks(opts)? {
658 let lookup = result?;
659 if let Some(offset) = lookup.offset() {
660 offsets.insert(offset);
661 }
662
663 iteration_count += 1;
664 if iteration_count > max_iterations {
665 return Err(MaxMindDbError::invalid_database(format!(
666 "search tree appears to have a cycle or invalid structure (exceeded {max_iterations} iterations)"
667 )));
668 }
669 }
670 Ok(offsets)
671 }
672
673 fn verify_data_section_separator(&self) -> Result<(), MaxMindDbError> {
674 let separator_start = self.node_count * self.node_byte_size;
675 let separator_end = separator_start + DATA_SECTION_SEPARATOR_SIZE;
676
677 if separator_end > self.buf.as_ref().len() {
678 return Err(MaxMindDbError::invalid_database_at(
679 "data section separator extends past end of file",
680 separator_start,
681 ));
682 }
683
684 let separator = &self.buf.as_ref()[separator_start..separator_end];
685
686 for &b in separator {
687 if b != 0 {
688 return Err(MaxMindDbError::invalid_database_at(
689 format!("unexpected byte in data separator: {separator:?}"),
690 separator_start,
691 ));
692 }
693 }
694 Ok(())
695 }
696
697 fn verify_data_section(
698 &self,
699 offsets: HashSet<usize>,
700 data_section_end: usize,
701 ) -> Result<(), MaxMindDbError> {
702 let data_section = &self.buf.as_ref()[self.pointer_base..data_section_end];
703 let mut verification_state = decoder::VerificationState::default();
704
705 for &offset in &offsets {
707 if offset >= data_section.len() {
708 return Err(MaxMindDbError::invalid_database_at(
709 format!(
710 "search tree pointer is beyond data section (len: {})",
711 data_section.len()
712 ),
713 offset,
714 ));
715 }
716
717 let mut dec = decoder::Decoder::new(data_section, offset);
718
719 if let Err(e) = dec.skip_value_for_verification(&mut verification_state) {
721 return Err(MaxMindDbError::invalid_database_at(
722 format!("decoding error: {e}"),
723 offset,
724 ));
725 }
726 }
727
728 Ok(())
729 }
730}
731
732fn validate_record_size(record_size: u16) -> Result<(), MaxMindDbError> {
733 if matches!(record_size, 24 | 28 | 32) {
734 Ok(())
735 } else {
736 Err(MaxMindDbError::invalid_database(format!(
737 "record_size - Expected: 24, 28, or 32 Actual: {}",
738 record_size
739 )))
740 }
741}
742
743pub(crate) fn validate_metadata_for_reader(metadata: &Metadata) -> Result<(), MaxMindDbError> {
744 if metadata.binary_format_major_version != 2 {
745 return Err(MaxMindDbError::invalid_database(format!(
746 "binary_format_major_version - Expected: 2 Actual: {}",
747 metadata.binary_format_major_version
748 )));
749 }
750 if metadata.ip_version != 4 && metadata.ip_version != 6 {
752 return Err(MaxMindDbError::invalid_database(format!(
753 "ip_version - Expected: 4 or 6 Actual: {}",
754 metadata.ip_version
755 )));
756 }
757 if metadata.node_count == 0 {
758 return Err(MaxMindDbError::invalid_database(
759 "node_count - Expected: positive integer Actual: 0",
760 ));
761 }
762 metadata.build_time()?;
763 validate_record_size(metadata.record_size)
764}
765
766fn search_tree_size_bytes(node_count: usize, record_size: usize) -> Result<usize, MaxMindDbError> {
767 node_count
768 .checked_mul(record_size)
769 .map(|size| size / 4)
770 .ok_or_else(|| {
771 MaxMindDbError::invalid_database(
772 "search tree size calculation overflowed or is impossibly large",
773 )
774 })
775}
776
777fn validate_search_tree_layout(
778 pointer_base: usize,
779 data_section_end: usize,
780) -> Result<(), MaxMindDbError> {
781 if pointer_base > data_section_end {
782 return Err(MaxMindDbError::invalid_database(
783 "the MaxMind DB file's search tree extends beyond the metadata section",
784 ));
785 }
786 Ok(())
787}
788
789trait SearchTreeRecord {
790 fn read_node(buf: &[u8], node_number: usize, index: usize) -> usize;
791}
792
793struct RecordSize24;
794
795impl SearchTreeRecord for RecordSize24 {
796 #[inline(always)]
797 fn read_node(buf: &[u8], node_number: usize, index: usize) -> usize {
798 let offset = node_number * 6 + index * 3;
799 (buf[offset] as usize) << 16 | (buf[offset + 1] as usize) << 8 | buf[offset + 2] as usize
800 }
801}
802
803struct RecordSize28;
804
805impl SearchTreeRecord for RecordSize28 {
806 #[inline(always)]
807 fn read_node(buf: &[u8], node_number: usize, index: usize) -> usize {
808 let base_offset = node_number * 7;
809 let middle = if index == 0 {
810 (buf[base_offset + 3] & 0xF0) >> 4
811 } else {
812 buf[base_offset + 3] & 0x0F
813 };
814 let offset = base_offset + index * 4;
815 (middle as usize) << 24
816 | (buf[offset] as usize) << 16
817 | (buf[offset + 1] as usize) << 8
818 | buf[offset + 2] as usize
819 }
820}
821
822struct RecordSize32;
823
824impl SearchTreeRecord for RecordSize32 {
825 #[inline(always)]
826 fn read_node(buf: &[u8], node_number: usize, index: usize) -> usize {
827 let offset = node_number * 8 + index * 4;
828 (buf[offset] as usize) << 24
829 | (buf[offset + 1] as usize) << 16
830 | (buf[offset + 2] as usize) << 8
831 | buf[offset + 3] as usize
832 }
833}
834
835#[inline(always)]
836fn find_address_in_tree_v4<R: SearchTreeRecord>(
837 buf: &[u8],
838 start_node: usize,
839 node_count: usize,
840 ip: u32,
841) -> (usize, usize) {
842 let mut node = start_node;
843 let mut prefix_len = 32;
844
845 for i in 0..32 {
846 if node >= node_count {
847 prefix_len = i;
848 break;
849 }
850 let bit = ((ip >> (31 - i)) & 1) as usize;
851 node = R::read_node(buf, node, bit);
852 }
853
854 normalize_lookup_result(node, node_count, prefix_len)
855}
856
857#[inline(always)]
858fn find_address_in_tree_v6<R: SearchTreeRecord>(
859 buf: &[u8],
860 node_count: usize,
861 ip: u128,
862) -> (usize, usize) {
863 let mut node = 0;
864 let mut prefix_len = 128;
865
866 for i in 0..128 {
867 if node >= node_count {
868 prefix_len = i;
869 break;
870 }
871 let bit = ((ip >> (127 - i)) & 1) as usize;
872 node = R::read_node(buf, node, bit);
873 }
874
875 normalize_lookup_result(node, node_count, prefix_len)
876}
877
878#[inline(always)]
885fn normalize_lookup_result(node: usize, node_count: usize, prefix_len: usize) -> (usize, usize) {
886 if node <= node_count {
887 (0, prefix_len)
888 } else {
889 (node, prefix_len)
890 }
891}
892
893fn find_metadata_start(buf: &[u8]) -> Result<usize, MaxMindDbError> {
894 memchr::memmem::rfind(buf, METADATA_START_MARKER)
895 .map(|x| x + METADATA_START_MARKER.len())
896 .ok_or_else(|| {
897 MaxMindDbError::invalid_database("could not find MaxMind DB metadata in file")
898 })
899}
900
901fn metadata_marker_start(metadata_start: usize) -> Result<usize, MaxMindDbError> {
902 metadata_start
903 .checked_sub(METADATA_START_MARKER.len())
904 .ok_or_else(|| MaxMindDbError::invalid_database("invalid metadata marker location"))
905}