1use std::io::{BufReader, Read};
24
25use bytes::Bytes;
26use pcap_parser::traits::PcapReaderIterator;
27use pcap_parser::{LegacyPcapReader, PcapBlockOwned, PcapNGReader};
28
29use crate::error::{Error, PcapError};
30use crate::io::{PacketRef, RawPacket};
31
32const BUFFER_SIZE: usize = 262144;
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub enum PcapFormat {
38 LegacyLeMicro,
40 LegacyBeMicro,
42 LegacyLeNano,
44 LegacyBeNano,
46 PcapNg,
48}
49
50impl PcapFormat {
51 pub fn detect(data: &[u8]) -> Result<Self, Error> {
53 if data.len() < 4 {
54 return Err(Error::Pcap(PcapError::InvalidFormat {
55 reason: "Data too small for PCAP magic".into(),
56 }));
57 }
58
59 let magic = u32::from_ne_bytes([data[0], data[1], data[2], data[3]]);
60
61 match magic {
62 0xa1b2c3d4 => Ok(PcapFormat::LegacyLeMicro),
63 0xd4c3b2a1 => Ok(PcapFormat::LegacyBeMicro),
64 0xa1b23c4d => Ok(PcapFormat::LegacyLeNano),
65 0x4d3cb2a1 => Ok(PcapFormat::LegacyBeNano),
66 0x0a0d0d0a => Ok(PcapFormat::PcapNg),
67 _ => Err(Error::Pcap(PcapError::InvalidFormat {
68 reason: format!("Unknown PCAP magic: 0x{magic:08x}"),
69 })),
70 }
71 }
72
73 pub fn is_pcapng(&self) -> bool {
75 matches!(self, PcapFormat::PcapNg)
76 }
77
78 pub fn is_legacy(&self) -> bool {
80 !self.is_pcapng()
81 }
82
83 pub fn is_little_endian(&self) -> bool {
89 match self {
90 PcapFormat::LegacyLeMicro | PcapFormat::LegacyLeNano => true,
91 PcapFormat::LegacyBeMicro | PcapFormat::LegacyBeNano => false,
92 PcapFormat::PcapNg => true, }
94 }
95}
96
97pub struct GenericPcapReader<R: Read> {
102 inner: ReaderInner<R>,
103 frame_number: u64,
104 link_type: u32,
105}
106
107enum ReaderInner<R: Read> {
109 Legacy(LegacyPcapReader<BufReader<R>>),
110 Ng(PcapNGReader<BufReader<R>>),
111}
112
113impl<R: Read> GenericPcapReader<R> {
114 pub fn with_format(source: R, format: PcapFormat) -> Result<Self, Error> {
123 let buf_reader = BufReader::with_capacity(BUFFER_SIZE, source);
124
125 let (inner, link_type) = if format.is_pcapng() {
126 let reader = PcapNGReader::new(BUFFER_SIZE, buf_reader).map_err(|e| {
127 Error::Pcap(PcapError::InvalidFormat {
128 reason: format!("Failed to parse PCAPNG: {e}"),
129 })
130 })?;
131 (ReaderInner::Ng(reader), 1u32)
133 } else {
134 let mut reader = LegacyPcapReader::new(BUFFER_SIZE, buf_reader).map_err(|e| {
135 Error::Pcap(PcapError::InvalidFormat {
136 reason: format!("Failed to parse legacy PCAP: {e}"),
137 })
138 })?;
139 let link_type = Self::read_legacy_header_link_type(&mut reader)?;
141 (ReaderInner::Legacy(reader), link_type)
142 };
143
144 Ok(GenericPcapReader {
145 inner,
146 frame_number: 0,
147 link_type,
148 })
149 }
150
151 fn read_legacy_header_link_type<S: Read>(
156 reader: &mut LegacyPcapReader<S>,
157 ) -> Result<u32, Error> {
158 use pcap_parser::PcapError as PcapParserError;
159
160 loop {
161 match reader.next() {
162 Ok((offset, block)) => match block {
163 PcapBlockOwned::LegacyHeader(header) => {
164 let link_type = header.network.0 as u32;
165 reader.consume(offset);
166 return Ok(link_type);
167 }
168 PcapBlockOwned::Legacy(_) => {
169 return Ok(1); }
173 _ => {
174 reader.consume(offset);
175 continue;
176 }
177 },
178 Err(PcapParserError::Eof) => {
179 return Ok(1); }
181 Err(PcapParserError::Incomplete(_)) => {
182 reader.refill().map_err(|e| {
183 Error::Pcap(PcapError::InvalidFormat {
184 reason: format!("Failed to read PCAP header: {e}"),
185 })
186 })?;
187 continue;
188 }
189 Err(e) => {
190 return Err(Error::Pcap(PcapError::InvalidFormat {
191 reason: format!("Failed to parse PCAP header: {e}"),
192 }));
193 }
194 }
195 }
196 }
197
198 pub fn next_packet(&mut self) -> Result<Option<RawPacket>, Error> {
202 match &mut self.inner {
203 ReaderInner::Legacy(reader) => {
204 read_legacy_packet(reader, &mut self.frame_number, &mut self.link_type)
205 }
206 ReaderInner::Ng(reader) => {
207 read_pcapng_packet(reader, &mut self.frame_number, &mut self.link_type)
208 }
209 }
210 }
211
212 pub fn link_type(&self) -> u32 {
214 self.link_type
215 }
216
217 pub fn frame_count(&self) -> u64 {
219 self.frame_number
220 }
221
222 #[inline]
230 pub fn process_packets<F>(&mut self, max: usize, f: F) -> Result<usize, Error>
231 where
232 F: FnMut(PacketRef<'_>) -> Result<(), Error>,
233 {
234 match &mut self.inner {
235 ReaderInner::Legacy(reader) => {
236 process_legacy_packets(reader, max, &mut self.frame_number, &mut self.link_type, f)
237 }
238 ReaderInner::Ng(reader) => {
239 process_pcapng_packets(reader, max, &mut self.frame_number, &mut self.link_type, f)
240 }
241 }
242 }
243}
244
245fn read_legacy_packet<S: Read>(
247 reader: &mut LegacyPcapReader<S>,
248 frame_number: &mut u64,
249 link_type: &mut u32,
250) -> Result<Option<RawPacket>, Error> {
251 use pcap_parser::PcapError as PcapParserError;
252
253 loop {
254 match reader.next() {
255 Ok((offset, block)) => match block {
256 PcapBlockOwned::Legacy(packet) => {
257 *frame_number += 1;
258
259 let timestamp_us = (packet.ts_sec as i64) * 1_000_000 + (packet.ts_usec as i64);
260
261 let raw = RawPacket {
262 frame_number: *frame_number,
263 timestamp_us,
264 captured_length: packet.caplen,
265 original_length: packet.origlen,
266 link_type: *link_type as u16,
267 data: Bytes::copy_from_slice(packet.data),
268 };
269
270 reader.consume(offset);
271 return Ok(Some(raw));
272 }
273 PcapBlockOwned::LegacyHeader(header) => {
274 *link_type = header.network.0 as u32;
275 reader.consume(offset);
276 continue;
277 }
278 _ => {
279 reader.consume(offset);
280 continue;
281 }
282 },
283 Err(PcapParserError::Eof) => return Ok(None),
284 Err(PcapParserError::Incomplete(_)) => {
285 reader.refill().map_err(|e| {
286 Error::Pcap(PcapError::InvalidFormat {
287 reason: format!("Legacy PCAP refill error: {e}"),
288 })
289 })?;
290 continue;
291 }
292 Err(e) => {
293 return Err(Error::Pcap(PcapError::InvalidFormat {
294 reason: format!("Legacy PCAP parse error: {e}"),
295 }));
296 }
297 }
298 }
299}
300
301fn read_pcapng_packet<S: Read>(
303 reader: &mut PcapNGReader<S>,
304 frame_number: &mut u64,
305 link_type: &mut u32,
306) -> Result<Option<RawPacket>, Error> {
307 use pcap_parser::PcapError as PcapParserError;
308
309 loop {
310 match reader.next() {
311 Ok((offset, block)) => match block {
312 PcapBlockOwned::NG(ng_block) => {
313 use pcap_parser::pcapng::*;
314
315 match ng_block {
316 Block::InterfaceDescription(idb) => {
317 *link_type = idb.linktype.0 as u32;
318 reader.consume(offset);
319 continue;
320 }
321 Block::EnhancedPacket(epb) => {
322 *frame_number += 1;
323
324 let timestamp_us = ((epb.ts_high as i64) << 32) | (epb.ts_low as i64);
325
326 let packet = RawPacket {
327 frame_number: *frame_number,
328 timestamp_us,
329 captured_length: epb.caplen,
330 original_length: epb.origlen,
331 link_type: *link_type as u16,
332 data: Bytes::copy_from_slice(epb.data),
333 };
334
335 reader.consume(offset);
336 return Ok(Some(packet));
337 }
338 Block::SimplePacket(spb) => {
339 *frame_number += 1;
340
341 let packet = RawPacket {
342 frame_number: *frame_number,
343 timestamp_us: 0,
344 captured_length: spb.data.len() as u32,
345 original_length: spb.origlen,
346 link_type: *link_type as u16,
347 data: Bytes::copy_from_slice(spb.data),
348 };
349
350 reader.consume(offset);
351 return Ok(Some(packet));
352 }
353 _ => {
354 reader.consume(offset);
355 continue;
356 }
357 }
358 }
359 _ => {
360 reader.consume(offset);
361 continue;
362 }
363 },
364 Err(PcapParserError::Eof) => return Ok(None),
365 Err(PcapParserError::Incomplete(_)) => {
366 reader.refill().map_err(|e| {
367 Error::Pcap(PcapError::InvalidFormat {
368 reason: format!("PCAPNG refill error: {e}"),
369 })
370 })?;
371 continue;
372 }
373 Err(e) => {
374 return Err(Error::Pcap(PcapError::InvalidFormat {
375 reason: format!("PCAPNG parse error: {e}"),
376 }));
377 }
378 }
379 }
380}
381
382fn process_legacy_packets<S: Read, F>(
387 reader: &mut LegacyPcapReader<S>,
388 max: usize,
389 frame_number: &mut u64,
390 link_type: &mut u32,
391 mut f: F,
392) -> Result<usize, Error>
393where
394 F: FnMut(PacketRef<'_>) -> Result<(), Error>,
395{
396 use pcap_parser::PcapError as PcapParserError;
397
398 let mut count = 0;
399 while count < max {
400 match reader.next() {
401 Ok((offset, block)) => {
402 match block {
403 PcapBlockOwned::Legacy(packet) => {
404 *frame_number += 1;
405
406 let timestamp_us =
407 (packet.ts_sec as i64) * 1_000_000 + (packet.ts_usec as i64);
408
409 let packet_ref = PacketRef {
411 frame_number: *frame_number,
412 timestamp_us,
413 captured_len: packet.caplen,
414 original_len: packet.origlen,
415 link_type: *link_type as u16,
416 data: packet.data, };
418
419 f(packet_ref)?;
421
422 reader.consume(offset);
424 count += 1;
425 }
426 PcapBlockOwned::LegacyHeader(header) => {
427 *link_type = header.network.0 as u32;
428 reader.consume(offset);
429 continue;
430 }
431 _ => {
432 reader.consume(offset);
433 continue;
434 }
435 }
436 }
437 Err(PcapParserError::Eof) => break,
438 Err(PcapParserError::Incomplete(_)) => {
439 reader.refill().map_err(|e| {
440 Error::Pcap(PcapError::InvalidFormat {
441 reason: format!("Legacy PCAP refill error: {e}"),
442 })
443 })?;
444 continue;
445 }
446 Err(e) => {
447 return Err(Error::Pcap(PcapError::InvalidFormat {
448 reason: format!("Legacy PCAP parse error: {e}"),
449 }));
450 }
451 }
452 }
453 Ok(count)
454}
455
456fn process_pcapng_packets<S: Read, F>(
461 reader: &mut PcapNGReader<S>,
462 max: usize,
463 frame_number: &mut u64,
464 link_type: &mut u32,
465 mut f: F,
466) -> Result<usize, Error>
467where
468 F: FnMut(PacketRef<'_>) -> Result<(), Error>,
469{
470 use pcap_parser::PcapError as PcapParserError;
471
472 let mut count = 0;
473 while count < max {
474 match reader.next() {
475 Ok((offset, block)) => {
476 match block {
477 PcapBlockOwned::NG(ng_block) => {
478 use pcap_parser::pcapng::*;
479
480 match ng_block {
481 Block::InterfaceDescription(idb) => {
482 *link_type = idb.linktype.0 as u32;
483 reader.consume(offset);
484 continue;
485 }
486 Block::EnhancedPacket(epb) => {
487 *frame_number += 1;
488
489 let timestamp_us =
490 ((epb.ts_high as i64) << 32) | (epb.ts_low as i64);
491
492 let packet_ref = PacketRef {
494 frame_number: *frame_number,
495 timestamp_us,
496 captured_len: epb.caplen,
497 original_len: epb.origlen,
498 link_type: *link_type as u16,
499 data: epb.data, };
501
502 f(packet_ref)?;
504
505 reader.consume(offset);
507 count += 1;
508 }
509 Block::SimplePacket(spb) => {
510 *frame_number += 1;
511
512 let packet_ref = PacketRef {
514 frame_number: *frame_number,
515 timestamp_us: 0,
516 captured_len: spb.data.len() as u32,
517 original_len: spb.origlen,
518 link_type: *link_type as u16,
519 data: spb.data, };
521
522 f(packet_ref)?;
524
525 reader.consume(offset);
527 count += 1;
528 }
529 _ => {
530 reader.consume(offset);
531 continue;
532 }
533 }
534 }
535 _ => {
536 reader.consume(offset);
537 continue;
538 }
539 }
540 }
541 Err(PcapParserError::Eof) => break,
542 Err(PcapParserError::Incomplete(_)) => {
543 reader.refill().map_err(|e| {
544 Error::Pcap(PcapError::InvalidFormat {
545 reason: format!("PCAPNG refill error: {e}"),
546 })
547 })?;
548 continue;
549 }
550 Err(e) => {
551 return Err(Error::Pcap(PcapError::InvalidFormat {
552 reason: format!("PCAPNG parse error: {e}"),
553 }));
554 }
555 }
556 }
557 Ok(count)
558}
559
560unsafe impl<R: Read + Send> Send for GenericPcapReader<R> {}
562
563impl<R: Read> Unpin for GenericPcapReader<R> {}
565
566#[cfg(test)]
567mod tests {
568 use super::*;
569 use std::io::Cursor;
570
571 #[test]
572 fn test_pcap_format_detect() {
573 let le_micro = [0xd4, 0xc3, 0xb2, 0xa1];
579 assert_eq!(
580 PcapFormat::detect(&le_micro).unwrap(),
581 PcapFormat::LegacyLeMicro
582 );
583
584 let be_micro = [0xa1, 0xb2, 0xc3, 0xd4];
586 assert_eq!(
587 PcapFormat::detect(&be_micro).unwrap(),
588 PcapFormat::LegacyBeMicro
589 );
590
591 let pcapng = [0x0a, 0x0d, 0x0d, 0x0a];
593 assert_eq!(PcapFormat::detect(&pcapng).unwrap(), PcapFormat::PcapNg);
594
595 let unknown = [0xDE, 0xAD, 0xBE, 0xEF];
597 assert!(PcapFormat::detect(&unknown).is_err());
598 }
599
600 #[test]
601 fn test_pcap_format_properties() {
602 assert!(PcapFormat::LegacyLeMicro.is_legacy());
603 assert!(!PcapFormat::LegacyLeMicro.is_pcapng());
604
605 assert!(PcapFormat::PcapNg.is_pcapng());
606 assert!(!PcapFormat::PcapNg.is_legacy());
607 }
608
609 #[test]
610 fn test_pcap_format_endianness() {
611 assert!(PcapFormat::LegacyLeMicro.is_little_endian());
613 assert!(PcapFormat::LegacyLeNano.is_little_endian());
614 assert!(PcapFormat::PcapNg.is_little_endian()); assert!(!PcapFormat::LegacyBeMicro.is_little_endian());
618 assert!(!PcapFormat::LegacyBeNano.is_little_endian());
619 }
620
621 fn create_minimal_pcap() -> Vec<u8> {
623 let mut data = Vec::new();
624
625 data.extend_from_slice(&[0xd4, 0xc3, 0xb2, 0xa1]); data.extend_from_slice(&[0x02, 0x00]); data.extend_from_slice(&[0x04, 0x00]); data.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); data.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); data.extend_from_slice(&[0xff, 0xff, 0x00, 0x00]); data.extend_from_slice(&[0x01, 0x00, 0x00, 0x00]); let packet_data = [
636 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, ];
640
641 let ts_sec: u32 = 1000000000;
642 let ts_usec: u32 = 500000;
643 let caplen: u32 = packet_data.len() as u32;
644 let origlen: u32 = packet_data.len() as u32;
645
646 data.extend_from_slice(&ts_sec.to_le_bytes());
647 data.extend_from_slice(&ts_usec.to_le_bytes());
648 data.extend_from_slice(&caplen.to_le_bytes());
649 data.extend_from_slice(&origlen.to_le_bytes());
650 data.extend_from_slice(&packet_data);
651
652 data
653 }
654
655 #[test]
656 fn test_generic_reader_from_memory() {
657 let pcap_data = create_minimal_pcap();
658
659 let format = PcapFormat::detect(&pcap_data).expect("Failed to detect format");
661
662 let cursor = Cursor::new(pcap_data);
663 let mut reader =
664 GenericPcapReader::with_format(cursor, format).expect("Failed to create reader");
665
666 let packet = reader.next_packet().expect("Read error");
668 assert!(packet.is_some());
669
670 let pkt = packet.unwrap();
671 assert_eq!(pkt.frame_number, 1);
672 assert_eq!(pkt.captured_length, 14);
673 assert_eq!(pkt.original_length, 14);
674 assert_eq!(pkt.link_type, 1); assert_eq!(pkt.timestamp_us, 1000000000_500000i64);
676 assert_eq!(pkt.data.len(), 14);
677
678 let packet2 = reader.next_packet().expect("Read error");
680 assert!(packet2.is_none());
681 }
682
683 #[test]
684 fn test_generic_reader_link_type() {
685 let pcap_data = create_minimal_pcap();
686 let format = PcapFormat::detect(&pcap_data).expect("Failed to detect format");
687 let cursor = Cursor::new(pcap_data);
688
689 let mut reader =
690 GenericPcapReader::with_format(cursor, format).expect("Failed to create reader");
691
692 reader.next_packet().ok();
694 assert_eq!(reader.link_type(), 1); }
696
697 #[test]
698 fn test_generic_reader_frame_count() {
699 let pcap_data = create_minimal_pcap();
700 let format = PcapFormat::detect(&pcap_data).expect("Failed to detect format");
701 let cursor = Cursor::new(pcap_data);
702
703 let mut reader =
704 GenericPcapReader::with_format(cursor, format).expect("Failed to create reader");
705 assert_eq!(reader.frame_count(), 0);
706
707 reader.next_packet().ok();
708 assert_eq!(reader.frame_count(), 1);
709 }
710}