pcap_parser/pcap/
reader.rs

1use crate::blocks::PcapBlockOwned;
2use crate::error::PcapError;
3use crate::pcap::{
4    parse_pcap_frame, parse_pcap_frame_be, parse_pcap_frame_modified, parse_pcap_header,
5    LegacyPcapBlock, PcapHeader,
6};
7use crate::traits::PcapReaderIterator;
8use circular::Buffer;
9use nom::{IResult, Needed, Offset};
10use std::io::Read;
11
12/// Parsing iterator over legacy pcap data (streaming version)
13///
14/// ## Pcap Reader
15///
16/// This reader is a streaming parser based on a circular buffer, which means memory
17/// usage is constant, and that it can be used to parse huge files or infinite streams.
18/// It creates an abstraction over any input providing the `Read` trait, and takes care
19/// of managing the circular buffer to provide an iterator-like interface.
20///
21/// The first call to `next` will return the file header. Some information of this header must
22/// be stored (for ex. the data link type) to be able to parse following block contents.
23/// Following calls to `next` will always return legacy data blocks.
24///
25/// The size of the circular buffer has to be big enough for at least one complete block. Using a
26/// larger value (at least 65k) is advised to avoid frequent reads and buffer shifts.
27///
28/// **There are precautions to take when reading multiple blocks before consuming data. See
29/// [`PcapReaderIterator`] for details.**
30///
31/// ## Example
32///
33/// ```rust
34/// use pcap_parser::*;
35/// use pcap_parser::traits::PcapReaderIterator;
36/// use std::fs::File;
37///
38/// # let path = "assets/ntp.pcap";
39/// let file = File::open(path).unwrap();
40/// let mut num_blocks = 0;
41/// let mut reader = LegacyPcapReader::new(65536, file).expect("LegacyPcapReader");
42/// loop {
43///     match reader.next() {
44///         Ok((offset, block)) => {
45///             println!("got new block");
46///             num_blocks += 1;
47///             match block {
48///                 PcapBlockOwned::LegacyHeader(_hdr) => {
49///                     // save hdr.network (linktype)
50///                 },
51///                 PcapBlockOwned::Legacy(_b) => {
52///                     // use linktype to parse b.data()
53///                 },
54///                 PcapBlockOwned::NG(_) => unreachable!(),
55///             }
56///             reader.consume(offset);
57///         },
58///         Err(PcapError::Eof) => break,
59///         Err(PcapError::Incomplete(_)) => {
60///             reader.refill().unwrap();
61///         },
62///         Err(e) => panic!("error while reading: {:?}", e),
63///     }
64/// }
65/// println!("num_blocks: {}", num_blocks);
66/// ```
67pub struct LegacyPcapReader<R>
68where
69    R: Read,
70{
71    header: PcapHeader,
72    reader: R,
73    buffer: Buffer,
74    consumed: usize,
75    reader_exhausted: bool,
76    parse: LegacyParseFn,
77}
78
79type LegacyParseFn = fn(&[u8]) -> IResult<&[u8], LegacyPcapBlock, PcapError<&[u8]>>;
80
81impl<R> LegacyPcapReader<R>
82where
83    R: Read,
84{
85    /// Creates a new `LegacyPcapReader<R>` with the provided buffer capacity.
86    pub fn new(
87        capacity: usize,
88        reader: R,
89    ) -> Result<LegacyPcapReader<R>, PcapError<&'static [u8]>> {
90        let buffer = Buffer::with_capacity(capacity);
91        Self::from_buffer(buffer, reader)
92    }
93    /// Creates a new `LegacyPcapReader<R>` using the provided `Buffer`.
94    pub fn from_buffer(
95        mut buffer: Buffer,
96        mut reader: R,
97    ) -> Result<LegacyPcapReader<R>, PcapError<&'static [u8]>> {
98        let sz = reader.read(buffer.space()).or(Err(PcapError::ReadError))?;
99        buffer.fill(sz);
100        let (_rem, header) = match parse_pcap_header(buffer.data()) {
101            Ok((r, h)) => Ok((r, h)),
102            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e.to_owned_vec()),
103            Err(nom::Err::Incomplete(Needed::Size(n))) => Err(PcapError::Incomplete(n.into())),
104            Err(nom::Err::Incomplete(Needed::Unknown)) => Err(PcapError::Incomplete(0)),
105        }?;
106        let parse = if !header.is_modified_format() {
107            if header.is_bigendian() {
108                parse_pcap_frame_be
109            } else {
110                parse_pcap_frame
111            }
112        } else {
113            parse_pcap_frame_modified
114        };
115        // do not consume
116        Ok(LegacyPcapReader {
117            header,
118            reader,
119            buffer,
120            consumed: 0,
121            reader_exhausted: false,
122            parse,
123        })
124    }
125}
126
127impl<R> PcapReaderIterator for LegacyPcapReader<R>
128where
129    R: Read,
130{
131    fn next(&mut self) -> Result<(usize, PcapBlockOwned<'_>), PcapError<&'_ [u8]>> {
132        if self.consumed == 0 {
133            return Ok((
134                self.header.size(),
135                PcapBlockOwned::from(self.header.clone()),
136            ));
137        }
138        // Return EOF if
139        // 1) all bytes have been read
140        // 2) no more data is available
141        if self.buffer.available_data() == 0
142            && (self.buffer.position() == 0 && self.reader_exhausted)
143        {
144            return Err(PcapError::Eof);
145        }
146        let data = self.buffer.data();
147        match (self.parse)(data) {
148            Ok((rem, b)) => {
149                let offset = data.offset(rem);
150                Ok((offset, PcapBlockOwned::from(b)))
151            }
152            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e),
153            Err(nom::Err::Incomplete(n)) => {
154                if self.reader_exhausted {
155                    // expected more bytes but reader is EOF, truncated pcap?
156                    Err(PcapError::UnexpectedEof)
157                } else {
158                    match n {
159                        Needed::Size(n) => {
160                            if self.buffer.available_data() + usize::from(n)
161                                >= self.buffer.capacity()
162                            {
163                                Err(PcapError::BufferTooSmall)
164                            } else {
165                                Err(PcapError::Incomplete(n.into()))
166                            }
167                        }
168                        Needed::Unknown => Err(PcapError::Incomplete(0)),
169                    }
170                }
171            }
172        }
173    }
174    fn consume(&mut self, offset: usize) {
175        self.consumed += offset;
176        self.buffer.consume(offset);
177    }
178    fn consume_noshift(&mut self, offset: usize) {
179        self.consumed += offset;
180        self.buffer.consume_noshift(offset);
181    }
182    fn consumed(&self) -> usize {
183        self.consumed
184    }
185    fn refill(&mut self) -> Result<(), PcapError<&[u8]>> {
186        self.buffer.shift();
187        let space = self.buffer.space();
188        // check if available space is empty, so we can distinguish
189        // a read() returning 0 because of EOF or because we requested 0
190        if space.is_empty() {
191            return Ok(());
192        }
193        let sz = self.reader.read(space).or(Err(PcapError::ReadError))?;
194        self.reader_exhausted = sz == 0;
195        self.buffer.fill(sz);
196        Ok(())
197    }
198    fn position(&self) -> usize {
199        self.buffer.position()
200    }
201    fn grow(&mut self, new_size: usize) -> bool {
202        self.buffer.grow(new_size)
203    }
204    fn data(&self) -> &[u8] {
205        self.buffer.data()
206    }
207    fn reader_exhausted(&self) -> bool {
208        self.reader_exhausted
209    }
210}