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