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    header_sent: bool,
76    reader_exhausted: bool,
77    parse: LegacyParseFn,
78}
79
80type LegacyParseFn = fn(&[u8]) -> IResult<&[u8], LegacyPcapBlock, PcapError<&[u8]>>;
81
82impl<R> LegacyPcapReader<R>
83where
84    R: Read,
85{
86    /// Creates a new `LegacyPcapReader<R>` with the provided buffer capacity.
87    pub fn new(
88        capacity: usize,
89        reader: R,
90    ) -> Result<LegacyPcapReader<R>, PcapError<&'static [u8]>> {
91        let buffer = Buffer::with_capacity(capacity);
92        Self::from_buffer(buffer, reader)
93    }
94    /// Creates a new `LegacyPcapReader<R>` using the provided `Buffer`.
95    pub fn from_buffer(
96        mut buffer: Buffer,
97        mut reader: R,
98    ) -> Result<LegacyPcapReader<R>, PcapError<&'static [u8]>> {
99        let sz = reader.read(buffer.space()).or(Err(PcapError::ReadError))?;
100        buffer.fill(sz);
101        let (_rem, header) = match parse_pcap_header(buffer.data()) {
102            Ok((r, h)) => Ok((r, h)),
103            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e.to_owned_vec()),
104            Err(nom::Err::Incomplete(Needed::Size(n))) => Err(PcapError::Incomplete(n.into())),
105            Err(nom::Err::Incomplete(Needed::Unknown)) => Err(PcapError::Incomplete(0)),
106        }?;
107        let parse = if !header.is_modified_format() {
108            if header.is_bigendian() {
109                parse_pcap_frame_be
110            } else {
111                parse_pcap_frame
112            }
113        } else {
114            parse_pcap_frame_modified
115        };
116        // do not consume
117        Ok(LegacyPcapReader {
118            header,
119            reader,
120            buffer,
121            consumed: 0,
122            header_sent: false,
123            reader_exhausted: false,
124            parse,
125        })
126    }
127}
128
129impl<R> PcapReaderIterator for LegacyPcapReader<R>
130where
131    R: Read,
132{
133    fn next(&mut self) -> Result<(usize, PcapBlockOwned), PcapError<&'_ [u8]>> {
134        if !self.header_sent {
135            self.header_sent = true;
136            return Ok((
137                self.header.size(),
138                PcapBlockOwned::from(self.header.clone()),
139            ));
140        }
141        // Return EOF if
142        // 1) all bytes have been read
143        // 2) no more data is available
144        if self.buffer.available_data() == 0
145            && (self.buffer.position() == 0 && self.reader_exhausted)
146        {
147            return Err(PcapError::Eof);
148        }
149        let data = self.buffer.data();
150        match (self.parse)(data) {
151            Ok((rem, b)) => {
152                let offset = data.offset(rem);
153                Ok((offset, PcapBlockOwned::from(b)))
154            }
155            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e),
156            Err(nom::Err::Incomplete(n)) => {
157                if self.reader_exhausted {
158                    // expected more bytes but reader is EOF, truncated pcap?
159                    Err(PcapError::UnexpectedEof)
160                } else {
161                    match n {
162                        Needed::Size(n) => {
163                            if self.buffer.available_data() + usize::from(n)
164                                >= self.buffer.capacity()
165                            {
166                                Err(PcapError::BufferTooSmall)
167                            } else {
168                                Err(PcapError::Incomplete(n.into()))
169                            }
170                        }
171                        Needed::Unknown => Err(PcapError::Incomplete(0)),
172                    }
173                }
174            }
175        }
176    }
177    fn consume(&mut self, offset: usize) {
178        self.consumed += offset;
179        self.buffer.consume(offset);
180    }
181    fn consume_noshift(&mut self, offset: usize) {
182        self.consumed += offset;
183        self.buffer.consume_noshift(offset);
184    }
185    fn consumed(&self) -> usize {
186        self.consumed
187    }
188    fn refill(&mut self) -> Result<(), PcapError<&[u8]>> {
189        self.buffer.shift();
190        let space = self.buffer.space();
191        // check if available space is empty, so we can distinguish
192        // a read() returning 0 because of EOF or because we requested 0
193        if space.is_empty() {
194            return Ok(());
195        }
196        let sz = self.reader.read(space).or(Err(PcapError::ReadError))?;
197        self.reader_exhausted = sz == 0;
198        self.buffer.fill(sz);
199        Ok(())
200    }
201    fn position(&self) -> usize {
202        self.buffer.position()
203    }
204    fn grow(&mut self, new_size: usize) -> bool {
205        self.buffer.grow(new_size)
206    }
207    fn data(&self) -> &[u8] {
208        self.buffer.data()
209    }
210    fn reader_exhausted(&self) -> bool {
211        self.reader_exhausted
212    }
213}