pcap_parser/pcapng/
capture.rs

1use crate::blocks::{PcapBlock, PcapBlockOwned};
2use crate::error::PcapError;
3use crate::pcapng::*;
4use nom::combinator::{complete, map};
5use nom::multi::many1;
6use nom::{IResult, Needed, Parser as _};
7use std::fmt;
8
9#[derive(Default)]
10pub(crate) struct CurrentSectionInfo {
11    pub(crate) big_endian: bool,
12}
13
14/// Parsing iterator over pcap-ng data (requires data to be loaded into memory)
15///
16/// ```rust
17/// use pcap_parser::*;
18/// use std::fs::File;
19/// use std::io::Read;
20///
21/// # let path = "assets/test001-le.pcapng";
22/// let mut file = File::open(path).unwrap();
23/// let mut buffer = Vec::new();
24/// file.read_to_end(&mut buffer).unwrap();
25/// let mut num_blocks = 0;
26/// let capture = PcapNGSlice::from_slice(&buffer).expect("parse file");
27/// for _block in capture {
28///     num_blocks += 1;
29/// }
30pub struct PcapNGSlice<'a> {
31    info: CurrentSectionInfo,
32    // remaining (unparsed) data
33    rem: &'a [u8],
34}
35
36impl PcapNGSlice<'_> {
37    pub fn from_slice(i: &[u8]) -> Result<PcapNGSlice<'_>, nom::Err<PcapError<&[u8]>>> {
38        // just check that first block is a valid one
39        let (_rem, _shb) = parse_sectionheaderblock(i)?;
40        let info = CurrentSectionInfo::default();
41        let rem = i;
42        Ok(PcapNGSlice { info, rem })
43    }
44}
45
46/// Iterator for PcapNGSlice. Returns a result so parsing errors are not
47/// silently ignored
48impl<'a> Iterator for PcapNGSlice<'a> {
49    type Item = Result<PcapBlockOwned<'a>, nom::Err<PcapError<&'a [u8]>>>;
50
51    fn next(&mut self) -> Option<Self::Item> {
52        if self.rem.is_empty() {
53            return None;
54        }
55        let parse = if self.info.big_endian {
56            parse_block_be
57        } else {
58            parse_block_le
59        };
60        let r = parse(self.rem).map(|(rem, b)| {
61            self.rem = rem;
62            if let Block::SectionHeader(ref shb) = b {
63                self.info.big_endian = shb.big_endian();
64            }
65            PcapBlockOwned::from(b)
66        });
67        Some(r)
68    }
69}
70
71/// Generic interface for PCAPNG file access
72pub struct PcapNGCapture<'a> {
73    pub sections: Vec<Section<'a>>,
74}
75
76impl fmt::Debug for PcapNGCapture<'_> {
77    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
78        writeln!(f, "PcapNGCapture:")
79    }
80}
81
82/// Iterator over `PcapNGCapture`
83pub struct PcapNGCaptureIterator<'a> {
84    cap: &'a PcapNGCapture<'a>,
85    idx: usize,
86}
87
88impl<'a> Iterator for PcapNGCaptureIterator<'a> {
89    type Item = PcapBlock<'a>;
90
91    fn next(&mut self) -> Option<PcapBlock<'a>> {
92        if self.cap.sections.len() != 1 {
93            // XXX only one section supported
94            unimplemented!();
95        }
96        self.cap.sections[0].blocks.get(self.idx).map(|b| {
97            self.idx += 1;
98            PcapBlock::from(b)
99        })
100    }
101}
102
103impl<'a> PcapNGCapture<'a> {
104    pub fn from_file(i: &[u8]) -> Result<PcapNGCapture<'_>, PcapError<&[u8]>> {
105        // XXX change return type to just an IResult
106        match parse_pcapng(i) {
107            Ok((_, pcap)) => Ok(pcap),
108            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e),
109            Err(nom::Err::Incomplete(Needed::Size(n))) => Err(PcapError::Incomplete(n.into())),
110            Err(nom::Err::Incomplete(Needed::Unknown)) => Err(PcapError::Incomplete(0)),
111        }
112    }
113
114    pub fn iter(&'a self) -> PcapNGCaptureIterator<'a> {
115        PcapNGCaptureIterator { cap: self, idx: 0 }
116    }
117}
118
119/// Parse the entire file
120///
121/// Note: this requires the file to be fully loaded to memory.
122pub fn parse_pcapng(i: &[u8]) -> IResult<&[u8], PcapNGCapture<'_>, PcapError<&[u8]>> {
123    map(many1(complete(parse_section)), |sections| PcapNGCapture {
124        sections,
125    })
126    .parse(i)
127}