pcap_file/pcapng/
parser.rs

1use byteorder_slice::{BigEndian, ByteOrder, LittleEndian};
2
3use super::blocks::block_common::{Block, RawBlock};
4use super::blocks::enhanced_packet::EnhancedPacketBlock;
5use super::blocks::interface_description::InterfaceDescriptionBlock;
6use super::blocks::section_header::SectionHeaderBlock;
7use super::blocks::{INTERFACE_DESCRIPTION_BLOCK, SECTION_HEADER_BLOCK};
8use crate::errors::PcapError;
9use crate::Endianness;
10
11
12/// Parses a PcapNg from a slice of bytes.
13///
14/// You can match on [`PcapError::IncompleteBuffer`] to know if the parser need more data.
15///
16/// # Example
17/// ```rust,no_run
18/// use std::fs::File;
19///
20/// use pcap_file::pcapng::PcapNgParser;
21/// use pcap_file::PcapError;
22///
23/// let pcap = std::fs::read("test.pcapng").expect("Error reading file");
24/// let mut src = &pcap[..];
25///
26/// let (rem, mut pcapng_parser) = PcapNgParser::new(src).unwrap();
27/// src = rem;
28///
29/// loop {
30///     match pcapng_parser.next_block(src) {
31///         Ok((rem, block)) => {
32///             // Do something
33///
34///             // Don't forget to update src
35///             src = rem;
36///         },
37///         Err(PcapError::IncompleteBuffer) => {
38///             // Load more data into src
39///         },
40///         Err(_) => {
41///             // Handle parsing error
42///         },
43///     }
44/// }
45/// ```
46pub struct PcapNgParser {
47    section: SectionHeaderBlock<'static>,
48    interfaces: Vec<InterfaceDescriptionBlock<'static>>,
49}
50
51impl PcapNgParser {
52    /// Creates a new [`PcapNgParser`].
53    ///
54    /// Parses the first block which must be a valid SectionHeaderBlock.
55    pub fn new(src: &[u8]) -> Result<(&[u8], Self), PcapError> {
56        // Always use BigEndian here because we can't know the SectionHeaderBlock endianness
57        let (rem, section) = Block::from_slice::<BigEndian>(src)?;
58        let section = match section {
59            Block::SectionHeader(section) => section.into_owned(),
60            _ => return Err(PcapError::InvalidField("PcapNg: SectionHeader invalid or missing")),
61        };
62
63        let parser = PcapNgParser { section, interfaces: vec![] };
64
65        Ok((rem, parser))
66    }
67
68    /// Returns the remainder and the next [`Block`].
69    pub fn next_block<'a>(&mut self, src: &'a [u8]) -> Result<(&'a [u8], Block<'a>), PcapError> {
70        // Read next Block
71        match self.section.endianness {
72            Endianness::Big => {
73                let (rem, raw_block) = self.next_raw_block_inner::<BigEndian>(src)?;
74                let block = raw_block.try_into_block::<BigEndian>()?;
75                Ok((rem, block))
76            },
77            Endianness::Little => {
78                let (rem, raw_block) = self.next_raw_block_inner::<LittleEndian>(src)?;
79                let block = raw_block.try_into_block::<LittleEndian>()?;
80                Ok((rem, block))
81            },
82        }
83    }
84
85    /// Returns the remainder and the next [`RawBlock`].
86    pub fn next_raw_block<'a>(&mut self, src: &'a [u8]) -> Result<(&'a [u8], RawBlock<'a>), PcapError> {
87        // Read next Block
88        match self.section.endianness {
89            Endianness::Big => self.next_raw_block_inner::<BigEndian>(src),
90            Endianness::Little => self.next_raw_block_inner::<LittleEndian>(src),
91        }
92    }
93
94    /// Inner function to parse the next raw block.
95    fn next_raw_block_inner<'a, B: ByteOrder>(&mut self, src: &'a [u8]) -> Result<(&'a [u8], RawBlock<'a>), PcapError> {
96        let (rem, raw_block) = RawBlock::from_slice::<B>(src)?;
97
98        match raw_block.type_ {
99            SECTION_HEADER_BLOCK => {
100                self.section = raw_block.clone().try_into_block::<B>()?.into_owned().into_section_header().unwrap();
101                self.interfaces.clear();
102            },
103            INTERFACE_DESCRIPTION_BLOCK => {
104                let interface = raw_block.clone().try_into_block::<B>()?.into_owned().into_interface_description().unwrap();
105                self.interfaces.push(interface);
106            },
107            _ => {},
108        }
109
110        Ok((rem, raw_block))
111    }
112
113    /// Returns the current [`SectionHeaderBlock`].
114    pub fn section(&self) -> &SectionHeaderBlock<'static> {
115        &self.section
116    }
117
118    /// Returns all the current [`InterfaceDescriptionBlock`].
119    pub fn interfaces(&self) -> &[InterfaceDescriptionBlock<'static>] {
120        &self.interfaces[..]
121    }
122
123    /// Returns the [`InterfaceDescriptionBlock`] corresponding to the given packet.
124    pub fn packet_interface(&self, packet: &EnhancedPacketBlock) -> Option<&InterfaceDescriptionBlock> {
125        self.interfaces.get(packet.interface_id as usize)
126    }
127}