stackforge_core/pcap/
reader.rs1use std::fs::File;
4use std::io::{BufReader, Read};
5use std::path::Path;
6
7use bytes::Bytes;
8use pcap_file::pcap::PcapReader as PcapFileReader;
9
10use crate::error::{PacketError, Result};
11use crate::packet::Packet;
12
13use super::{CapturedPacket, LinkType, PcapMetadata};
14
15pub fn rdpcap(path: impl AsRef<Path>) -> Result<Vec<CapturedPacket>> {
19 let iter = PcapIterator::open(path)?;
20 iter.collect()
21}
22
23pub struct PcapIterator<R: Read> {
28 inner: PcapFileReader<R>,
29 link_type: LinkType,
30}
31
32impl PcapIterator<BufReader<File>> {
33 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
35 let file = File::open(path.as_ref()).map_err(|e| {
36 PacketError::Io(format!("failed to open {}: {}", path.as_ref().display(), e))
37 })?;
38 let reader = BufReader::new(file);
39 Self::from_reader(reader)
40 }
41}
42
43impl<R: Read> PcapIterator<R> {
44 pub fn from_reader(reader: R) -> Result<Self> {
46 let pcap_reader = PcapFileReader::new(reader)
47 .map_err(|e| PacketError::Io(format!("invalid PCAP: {}", e)))?;
48 let link_type = LinkType(u32::from(pcap_reader.header().datalink));
49 Ok(Self {
50 inner: pcap_reader,
51 link_type,
52 })
53 }
54
55 pub fn link_type(&self) -> LinkType {
57 self.link_type
58 }
59}
60
61impl<R: Read> Iterator for PcapIterator<R> {
62 type Item = Result<CapturedPacket>;
63
64 fn next(&mut self) -> Option<Self::Item> {
65 match self.inner.next_packet() {
66 Some(Ok(pcap_pkt)) => {
67 let ts = pcap_pkt.timestamp;
68 let data = Bytes::copy_from_slice(&pcap_pkt.data);
69 let mut pkt = Packet::from_bytes(data);
70 let _ = pkt.parse();
72 Some(Ok(CapturedPacket {
73 packet: pkt,
74 metadata: PcapMetadata {
75 timestamp: ts,
76 orig_len: pcap_pkt.orig_len,
77 },
78 }))
79 }
80 Some(Err(e)) => Some(Err(PacketError::Io(format!("PCAP read error: {}", e)))),
81 None => None,
82 }
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use std::io::Cursor;
90 use std::time::Duration;
91
92 use pcap_file::pcap::{PcapHeader, PcapPacket, PcapWriter as PcapFileWriter};
93
94 fn sample_ethernet_packet() -> Vec<u8> {
95 vec![
97 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ]
102 }
103
104 fn create_test_pcap(packets: &[(Duration, &[u8])]) -> Vec<u8> {
105 let mut buf = Vec::new();
106 let header = PcapHeader::default();
107 let mut writer = PcapFileWriter::with_header(Cursor::new(&mut buf), header).unwrap();
108 for (ts, data) in packets {
109 let pkt = PcapPacket::new(*ts, data.len() as u32, data);
110 writer.write_packet(&pkt).unwrap();
111 }
112 drop(writer);
113 buf
114 }
115
116 #[test]
117 fn test_pcap_iterator_from_reader() {
118 let eth = sample_ethernet_packet();
119 let pcap_data = create_test_pcap(&[
120 (Duration::from_secs(1), ð),
121 (Duration::from_secs(2), ð),
122 ]);
123 let iter = PcapIterator::from_reader(Cursor::new(pcap_data)).unwrap();
124 let packets: Vec<_> = iter.collect::<std::result::Result<Vec<_>, _>>().unwrap();
125 assert_eq!(packets.len(), 2);
126 assert_eq!(packets[0].metadata.timestamp, Duration::from_secs(1));
127 assert_eq!(packets[1].metadata.timestamp, Duration::from_secs(2));
128 }
129
130 #[test]
131 fn test_pcap_iterator_link_type() {
132 let pcap_data = create_test_pcap(&[]);
133 let iter = PcapIterator::from_reader(Cursor::new(pcap_data)).unwrap();
134 assert_eq!(iter.link_type(), LinkType::ETHERNET);
135 }
136
137 #[test]
138 fn test_pcap_iterator_empty() {
139 let pcap_data = create_test_pcap(&[]);
140 let iter = PcapIterator::from_reader(Cursor::new(pcap_data)).unwrap();
141 let packets: Vec<_> = iter.collect::<std::result::Result<Vec<_>, _>>().unwrap();
142 assert!(packets.is_empty());
143 }
144
145 #[test]
146 fn test_pcap_iterator_metadata() {
147 let eth = sample_ethernet_packet();
148 let pcap_data = create_test_pcap(&[(Duration::from_millis(1500), ð)]);
149 let iter = PcapIterator::from_reader(Cursor::new(pcap_data)).unwrap();
150 let packets: Vec<_> = iter.collect::<std::result::Result<Vec<_>, _>>().unwrap();
151 assert_eq!(packets.len(), 1);
152 assert_eq!(packets[0].metadata.orig_len, eth.len() as u32);
153 assert_eq!(packets[0].packet.len(), eth.len());
154 }
155
156 #[test]
157 fn test_pcap_iterator_is_lazy() {
158 let eth = sample_ethernet_packet();
159 let pcap_data = create_test_pcap(&[
160 (Duration::from_secs(1), ð),
161 (Duration::from_secs(2), ð),
162 (Duration::from_secs(3), ð),
163 ]);
164 let mut iter = PcapIterator::from_reader(Cursor::new(pcap_data)).unwrap();
165 let first = iter.next().unwrap().unwrap();
167 assert_eq!(first.metadata.timestamp, Duration::from_secs(1));
168 let second = iter.next().unwrap().unwrap();
170 assert_eq!(second.metadata.timestamp, Duration::from_secs(2));
171 }
172}