pcap_parser/pcap/
capture.rs

1use crate::blocks::{PcapBlock, PcapBlockOwned};
2use crate::capture::Capture;
3use crate::error::PcapError;
4use crate::linktype::Linktype;
5use crate::pcap::{parse_pcap_frame, parse_pcap_header, LegacyPcapBlock, PcapHeader};
6use nom::combinator::complete;
7use nom::multi::many0;
8use nom::{IResult, Needed, Parser as _};
9use std::fmt;
10
11/// Parsing iterator over legacy pcap data (requires data to be loaded into memory)
12///
13/// ```rust
14/// use pcap_parser::*;
15/// use std::fs::File;
16/// use std::io::Read;
17///
18/// # let path = "assets/ntp.pcap";
19/// let mut file = File::open(path).unwrap();
20/// let mut buffer = Vec::new();
21/// file.read_to_end(&mut buffer).unwrap();
22/// let mut num_blocks = 0;
23/// match LegacyPcapSlice::from_slice(&buffer) {
24///     Ok(iter) => {
25///         println!("Format: PCAP");
26///         for _block in iter {
27///             num_blocks += 1;
28///         }
29///         return;
30///     },
31///     _ => ()
32/// }
33/// ```
34pub struct LegacyPcapSlice<'a> {
35    pub header: PcapHeader,
36    // remaining (unparsed) data
37    rem: &'a [u8],
38}
39
40impl LegacyPcapSlice<'_> {
41    pub fn from_slice(i: &[u8]) -> Result<LegacyPcapSlice<'_>, nom::Err<PcapError<&[u8]>>> {
42        let (rem, header) = parse_pcap_header(i)?;
43        Ok(LegacyPcapSlice { header, rem })
44    }
45}
46
47/// Iterator for LegacyPcapSlice. Returns a result so parsing errors are not
48/// silently ignored
49impl<'a> Iterator for LegacyPcapSlice<'a> {
50    type Item = Result<PcapBlockOwned<'a>, nom::Err<PcapError<&'a [u8]>>>;
51
52    fn next(&mut self) -> Option<Self::Item> {
53        if self.rem.is_empty() {
54            return None;
55        }
56        let r = parse_pcap_frame(self.rem).map(|(rem, b)| {
57            self.rem = rem;
58            PcapBlockOwned::from(b)
59        });
60        Some(r)
61    }
62}
63
64/// Generic interface for PCAP file access
65pub struct PcapCapture<'a> {
66    pub header: PcapHeader,
67
68    pub blocks: Vec<LegacyPcapBlock<'a>>,
69}
70
71impl PcapCapture<'_> {
72    pub fn from_file(i: &[u8]) -> Result<PcapCapture<'_>, PcapError<&[u8]>> {
73        match parse_pcap(i) {
74            Ok((_, pcap)) => Ok(pcap),
75            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e),
76            Err(nom::Err::Incomplete(Needed::Size(n))) => Err(PcapError::Incomplete(n.into())),
77            Err(nom::Err::Incomplete(Needed::Unknown)) => Err(PcapError::Incomplete(0)),
78        }
79    }
80}
81
82impl fmt::Debug for PcapCapture<'_> {
83    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
84        writeln!(f, "PcapCapture:")
85    }
86}
87
88/// Iterator over `PcapCapture`
89pub struct LegacyPcapIterator<'a> {
90    cap: &'a PcapCapture<'a>,
91    idx: usize,
92}
93
94impl<'a> Iterator for LegacyPcapIterator<'a> {
95    type Item = PcapBlock<'a>;
96
97    fn next(&mut self) -> Option<PcapBlock<'a>> {
98        self.cap.blocks.get(self.idx).map(|b| {
99            self.idx += 1;
100            PcapBlock::from(b)
101        })
102    }
103}
104
105impl Capture for PcapCapture<'_> {
106    fn get_datalink(&self) -> Linktype {
107        self.header.network
108    }
109
110    fn get_snaplen(&self) -> u32 {
111        self.header.snaplen
112    }
113
114    fn iter<'b>(&'b self) -> Box<dyn Iterator<Item = PcapBlock<'b>> + 'b> {
115        Box::new(LegacyPcapIterator { 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_pcap(i: &[u8]) -> IResult<&[u8], PcapCapture<'_>, PcapError<&[u8]>> {
123    let (i, header) = parse_pcap_header(i)?;
124    let (i, blocks) = many0(complete(parse_pcap_frame)).parse(i)?;
125    Ok((i, PcapCapture { header, blocks }))
126}