use crate::{DataLink, DataLinkAddress, DataLinkError};
use std::io::{self, Write};
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::sync::Mutex;
const PCAP_LINK_TYPE_USER0: u32 = 147;
const PCAP_MAGIC: u32 = 0xa1b2c3d4;
const PCAP_VERSION_MAJOR: u16 = 2;
const PCAP_VERSION_MINOR: u16 = 4;
const PCAP_MAX_SNAPLEN: u32 = 65535;
#[derive(Debug, Clone, Copy)]
pub enum Direction {
In,
Out,
}
struct PcapWriter<W: Write + Send> {
inner: W,
}
impl<W: Write + Send> PcapWriter<W> {
fn new(mut writer: W) -> io::Result<Self> {
writer.write_all(&PCAP_MAGIC.to_le_bytes())?;
writer.write_all(&PCAP_VERSION_MAJOR.to_le_bytes())?;
writer.write_all(&PCAP_VERSION_MINOR.to_le_bytes())?;
writer.write_all(&0i32.to_le_bytes())?; writer.write_all(&0u32.to_le_bytes())?; writer.write_all(&PCAP_MAX_SNAPLEN.to_le_bytes())?;
writer.write_all(&PCAP_LINK_TYPE_USER0.to_le_bytes())?;
writer.flush()?;
Ok(Self { inner: writer })
}
fn write_packet(&mut self, data: &[u8]) -> io::Result<()> {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default();
let ts_sec = now.as_secs() as u32;
let ts_usec = now.subsec_micros();
let len = data.len() as u32;
self.inner.write_all(&ts_sec.to_le_bytes())?;
self.inner.write_all(&ts_usec.to_le_bytes())?;
self.inner.write_all(&len.to_le_bytes())?; self.inner.write_all(&len.to_le_bytes())?; self.inner.write_all(data)?;
self.inner.flush()
}
}
pub struct CapturingDataLink<D: DataLink> {
inner: D,
writer: Arc<Mutex<PcapWriter<std::io::BufWriter<std::fs::File>>>>,
}
impl<D: DataLink> CapturingDataLink<D> {
pub fn to_file(inner: D, path: impl AsRef<std::path::Path>) -> io::Result<Self> {
let file = std::fs::File::create(path)?;
let buf_writer = std::io::BufWriter::new(file);
let pcap = PcapWriter::new(buf_writer)?;
Ok(Self {
inner,
writer: Arc::new(Mutex::new(pcap)),
})
}
}
impl<D: DataLink> DataLink for CapturingDataLink<D> {
async fn send(&self, address: DataLinkAddress, payload: &[u8]) -> Result<(), DataLinkError> {
{
let mut w = self.writer.lock().await;
let _ = w.write_packet(payload);
}
self.inner.send(address, payload).await
}
async fn recv(&self, buf: &mut [u8]) -> Result<(usize, DataLinkAddress), DataLinkError> {
let result = self.inner.recv(buf).await?;
{
let mut w = self.writer.lock().await;
let _ = w.write_packet(&buf[..result.0]);
}
Ok(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pcap_global_header_format() {
let mut buf = Vec::new();
let _writer = PcapWriter::new(&mut buf).unwrap();
assert_eq!(buf.len(), 24); assert_eq!(
u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]),
PCAP_MAGIC
);
}
#[test]
fn pcap_write_packet() {
let mut buf = Vec::new();
let mut writer = PcapWriter::new(&mut buf).unwrap();
writer.write_packet(&[0x01, 0x02, 0x03]).unwrap();
assert_eq!(buf.len(), 43);
}
}