wireforge_app/pcap/
reader.rs1use std::io::Read;
4use std::time::Duration;
5
6use super::types::{Endianness, LinkType, PcapHeader};
7use super::PacketCaptureReader;
8
9#[inline]
10fn read_u32(buf: &[u8], endian: Endianness) -> u32 {
11 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]]) }
12}
13
14pub struct PcapReader<R: Read> {
15 reader: R,
16 header: PcapHeader,
17 endian: Endianness,
18}
19
20impl<R: Read> PcapReader<R> {
21 pub fn new(mut reader: R) -> Result<Self, std::io::Error> {
22 let mut hdr_buf = [0u8; 24];
23 reader.read_exact(&mut hdr_buf)?;
24 let magic = u32::from_be_bytes([hdr_buf[0], hdr_buf[1], hdr_buf[2], hdr_buf[3]]);
25 let endian = match magic {
26 0xa1b2c3d4 => Endianness::Big,
27 0xd4c3b2a1 => Endianness::Little,
28 _ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, format!("invalid magic: 0x{magic:08X}"))),
29 };
30 let read_u32 = |off: usize| -> u32 {
32 let b = &hdr_buf[off..off+4];
33 match endian { Endianness::Big => u32::from_be_bytes([b[0],b[1],b[2],b[3]]), Endianness::Little => u32::from_le_bytes([b[0],b[1],b[2],b[3]]) }
34 };
35 let read_u16 = |off: usize| -> u16 {
36 let b = &hdr_buf[off..off+2];
37 match endian { Endianness::Big => u16::from_be_bytes([b[0],b[1]]), Endianness::Little => u16::from_le_bytes([b[0],b[1]]) }
38 };
39 Ok(Self {
40 reader,
41 endian,
42 header: PcapHeader {
43 magic_number: magic,
44 version_major: read_u16(4),
45 version_minor: read_u16(6),
46 thiszone: read_u32(8) as i32,
47 sigfigs: read_u32(12),
48 snaplen: read_u32(16),
49 network: read_u32(20),
50 },
51 })
52 }
53
54 pub fn header(&self) -> &PcapHeader { &self.header }
55 pub fn link_type(&self) -> LinkType { LinkType::from(self.header.network) }
56}
57
58impl<R: Read> Iterator for PcapReader<R> {
59 type Item = Result<(Duration, Vec<u8>), std::io::Error>;
60
61 fn next(&mut self) -> Option<Self::Item> {
62 let mut rec_hdr = [0u8; 16];
63 match self.reader.read_exact(&mut rec_hdr) {
64 Ok(_) => {},
65 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return None,
66 Err(e) => return Some(Err(e)),
67 }
68 let ts_sec = read_u32(&rec_hdr[0..4], self.endian);
69 let ts_usec = read_u32(&rec_hdr[4..8], self.endian);
70 let incl_len = read_u32(&rec_hdr[8..12], self.endian) as usize;
71
72 let mut data = vec![0u8; incl_len];
73 if let Err(e) = self.reader.read_exact(&mut data) {
74 return Some(Err(e));
75 }
76 Some(Ok((Duration::new(ts_sec as u64, ts_usec * 1000), data)))
77 }
78}
79
80impl<R: Read> PacketCaptureReader for PcapReader<R> {
81 type Error = std::io::Error;
82
83 fn link_type(&self) -> Option<LinkType> { Some(self.link_type()) }
84
85 fn next_packet(&mut self) -> Option<Result<(std::time::Duration, Vec<u8>), Self::Error>> {
86 self.next()
87 }
88}
89
90impl PcapReader<std::io::Cursor<Vec<u8>>> {
92 pub fn from_bytes(data: Vec<u8>) -> Result<Self, std::io::Error> {
93 Self::new(std::io::Cursor::new(data))
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 fn make_pcap_file(packets: &[&[u8]]) -> Vec<u8> {
102 let mut data = Vec::new();
103 data.extend_from_slice(&0xa1b2c3d4u32.to_be_bytes());
105 data.extend_from_slice(&2u16.to_be_bytes());
106 data.extend_from_slice(&4u16.to_be_bytes());
107 data.extend_from_slice(&[0u8; 8]); data.extend_from_slice(&65535u32.to_be_bytes()); data.extend_from_slice(&1u32.to_be_bytes()); for pkt in packets {
111 data.extend_from_slice(&0u32.to_be_bytes()); data.extend_from_slice(&0u32.to_be_bytes()); data.extend_from_slice(&(pkt.len() as u32).to_be_bytes()); data.extend_from_slice(&(pkt.len() as u32).to_be_bytes()); data.extend_from_slice(pkt);
116 }
117 data
118 }
119
120 #[test]
121 fn read_pcap_empty() {
122 let data = make_pcap_file(&[]);
123 let reader = PcapReader::from_bytes(data).unwrap();
124 assert_eq!(reader.link_type(), LinkType::Ethernet);
125 assert_eq!(reader.header().version_major, 2);
126 }
127
128 #[test]
129 fn read_pcap_with_packets() {
130 let packets: Vec<&[u8]> = vec![&[0xAA, 0xBB], &[0xCC, 0xDD, 0xEE]];
131 let data = make_pcap_file(&packets);
132 let reader = PcapReader::from_bytes(data).unwrap();
133 let results: Vec<_> = reader.collect();
134 assert_eq!(results.len(), 2);
135 assert_eq!(results[0].as_ref().unwrap().1, &[0xAA, 0xBB]);
136 assert_eq!(results[1].as_ref().unwrap().1, &[0xCC, 0xDD, 0xEE]);
137 }
138
139 #[test]
140 fn read_pcap_bad_magic() {
141 let mut data = vec![0u8; 24];
142 data[0..4].copy_from_slice(&0xDEADBEEFu32.to_be_bytes());
143 assert!(PcapReader::from_bytes(data).is_err());
144 }
145}