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}