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}