wireforge_app/pcap/
ng_reader.rs1use std::io::Read;
4use std::time::Duration;
5
6use super::types::{Endianness, LinkType, PcapNgBlock};
7use super::PacketCaptureReader;
8
9pub struct PcapNgReader<R: Read> {
10 reader: R,
11 link_type: Option<LinkType>,
12 byte_order: Endianness,
13}
14
15impl<R: Read> PcapNgReader<R> {
16 pub fn new(mut reader: R) -> Result<Self, std::io::Error> {
17 let mut hdr = [0u8; 8];
19 reader.read_exact(&mut hdr)?;
20 let block_type = u32::from_be_bytes([hdr[0], hdr[1], hdr[2], hdr[3]]);
21 let _block_len = u32::from_be_bytes([hdr[4], hdr[5], hdr[6], hdr[7]]);
22 let byte_order = if block_type == 0x0A0D0D0A { Endianness::Big } else { Endianness::Little };
24 Ok(Self { reader, link_type: None, byte_order })
25 }
26
27 pub fn link_type(&self) -> Option<LinkType> { self.link_type }
28}
29
30impl<R: Read> PacketCaptureReader for PcapNgReader<R> {
31 type Error = std::io::Error;
32
33 fn link_type(&self) -> Option<LinkType> { self.link_type }
34
35 fn next_packet(&mut self) -> Option<Result<(std::time::Duration, Vec<u8>), Self::Error>> {
36 loop {
37 match self.next()? {
38 Ok(PcapNgBlock::EnhancedPacket { timestamp, data }) => {
39 return Some(Ok((timestamp, data)));
40 }
41 Ok(_) => continue, Err(e) => return Some(Err(e)),
43 }
44 }
45 }
46}
47
48impl<R: Read> Iterator for PcapNgReader<R> {
49 type Item = Result<PcapNgBlock, std::io::Error>;
50
51 fn next(&mut self) -> Option<Self::Item> {
52 let mut hdr = [0u8; 8];
53 match self.reader.read_exact(&mut hdr) {
54 Ok(_) => {},
55 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return None,
56 Err(e) => return Some(Err(e)),
57 }
58 let block_type = read_u32(&hdr[0..4], self.byte_order);
59 let block_len = read_u32(&hdr[4..8], self.byte_order) as usize;
60 if block_len < 12 { return Some(Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "block too short"))); }
61 let body_len = block_len - 12;
62 let mut body = vec![0u8; body_len];
63 if let Err(e) = self.reader.read_exact(&mut body) { return Some(Err(e)); }
64 let mut tail = [0u8; 4];
66 let _ = self.reader.read_exact(&mut tail);
67
68 let block = match block_type {
69 0x0A0D0D0A => PcapNgBlock::SectionHeader {
70 byte_order: self.byte_order,
71 version: read_u16(&body, self.byte_order),
72 },
73 0x00000001 => {
74 let lt = read_u16(&body[8..10], self.byte_order) as u32;
75 self.link_type = Some(LinkType::from(lt));
76 PcapNgBlock::InterfaceDescription {
77 link_type: LinkType::from(lt),
78 snap_len: read_u32(&body[12..16], self.byte_order),
79 }
80 }
81 0x00000006 => {
82 let _if_id = read_u32(&body[0..4], self.byte_order);
83 let ts_hi = read_u32(&body[4..8], self.byte_order) as u64;
84 let ts_lo = read_u32(&body[8..12], self.byte_order) as u64;
85 let cap_len = read_u32(&body[12..16], self.byte_order) as usize;
86 let ts = Duration::new(ts_hi, (ts_lo / 1000) as u32);
87 let data = body[20..20 + cap_len].to_vec();
88 PcapNgBlock::EnhancedPacket { timestamp: ts, data }
89 }
90 _ => PcapNgBlock::Unknown { block_type, data: body },
91 };
92 Some(Ok(block))
93 }
94}
95
96#[inline]
97fn read_u16(buf: &[u8], endian: Endianness) -> u16 {
98 match endian { Endianness::Big => u16::from_be_bytes([buf[0], buf[1]]), Endianness::Little => u16::from_le_bytes([buf[0], buf[1]]) }
99}
100#[inline]
101fn read_u32(buf: &[u8], endian: Endianness) -> u32 {
102 match endian { Endianness::Big => u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]), Endianness::Little => u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]) }
103}