rustbac_datalink/
capture.rs1use crate::{DataLink, DataLinkAddress, DataLinkError};
7use std::io::{self, Write};
8use std::sync::Arc;
9use std::time::{SystemTime, UNIX_EPOCH};
10use tokio::sync::Mutex;
11
12const PCAP_LINK_TYPE_USER0: u32 = 147;
17const PCAP_MAGIC: u32 = 0xa1b2c3d4;
18const PCAP_VERSION_MAJOR: u16 = 2;
19const PCAP_VERSION_MINOR: u16 = 4;
20const PCAP_MAX_SNAPLEN: u32 = 65535;
21
22#[derive(Debug, Clone, Copy)]
24pub enum Direction {
25 In,
26 Out,
27}
28
29struct PcapWriter<W: Write + Send> {
31 inner: W,
32}
33
34impl<W: Write + Send> PcapWriter<W> {
35 fn new(mut writer: W) -> io::Result<Self> {
36 writer.write_all(&PCAP_MAGIC.to_le_bytes())?;
38 writer.write_all(&PCAP_VERSION_MAJOR.to_le_bytes())?;
39 writer.write_all(&PCAP_VERSION_MINOR.to_le_bytes())?;
40 writer.write_all(&0i32.to_le_bytes())?; writer.write_all(&0u32.to_le_bytes())?; writer.write_all(&PCAP_MAX_SNAPLEN.to_le_bytes())?;
43 writer.write_all(&PCAP_LINK_TYPE_USER0.to_le_bytes())?;
44 writer.flush()?;
45 Ok(Self { inner: writer })
46 }
47
48 fn write_packet(&mut self, data: &[u8]) -> io::Result<()> {
49 let now = SystemTime::now()
50 .duration_since(UNIX_EPOCH)
51 .unwrap_or_default();
52 let ts_sec = now.as_secs() as u32;
53 let ts_usec = now.subsec_micros();
54 let len = data.len() as u32;
55
56 self.inner.write_all(&ts_sec.to_le_bytes())?;
57 self.inner.write_all(&ts_usec.to_le_bytes())?;
58 self.inner.write_all(&len.to_le_bytes())?; self.inner.write_all(&len.to_le_bytes())?; self.inner.write_all(data)?;
61 self.inner.flush()
62 }
63}
64
65pub struct CapturingDataLink<D: DataLink> {
78 inner: D,
79 writer: Arc<Mutex<PcapWriter<std::io::BufWriter<std::fs::File>>>>,
80}
81
82impl<D: DataLink> CapturingDataLink<D> {
83 pub fn to_file(inner: D, path: impl AsRef<std::path::Path>) -> io::Result<Self> {
85 let file = std::fs::File::create(path)?;
86 let buf_writer = std::io::BufWriter::new(file);
87 let pcap = PcapWriter::new(buf_writer)?;
88 Ok(Self {
89 inner,
90 writer: Arc::new(Mutex::new(pcap)),
91 })
92 }
93}
94
95impl<D: DataLink> DataLink for CapturingDataLink<D> {
96 async fn send(&self, address: DataLinkAddress, payload: &[u8]) -> Result<(), DataLinkError> {
97 {
98 let mut w = self.writer.lock().await;
99 let _ = w.write_packet(payload);
100 }
101 self.inner.send(address, payload).await
102 }
103
104 async fn recv(&self, buf: &mut [u8]) -> Result<(usize, DataLinkAddress), DataLinkError> {
105 let result = self.inner.recv(buf).await?;
106 {
107 let mut w = self.writer.lock().await;
108 let _ = w.write_packet(&buf[..result.0]);
109 }
110 Ok(result)
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn pcap_global_header_format() {
120 let mut buf = Vec::new();
121 let _writer = PcapWriter::new(&mut buf).unwrap();
122 assert_eq!(buf.len(), 24); assert_eq!(
124 u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]),
125 PCAP_MAGIC
126 );
127 }
128
129 #[test]
130 fn pcap_write_packet() {
131 let mut buf = Vec::new();
132 let mut writer = PcapWriter::new(&mut buf).unwrap();
133 writer.write_packet(&[0x01, 0x02, 0x03]).unwrap();
134 assert_eq!(buf.len(), 43);
136 }
137}