use pcap::{Active, Capture, Device};
use crate::capture::frame::Frame;
use crate::capture::PacketSource;
use crate::error::{Error, Result};
pub struct LivePcapSource {
handle: Capture<Active>,
}
impl LivePcapSource {
pub fn open(interface: &str, bpf: &str) -> Result<Self> {
let device = Device::from(interface);
let mut handle = Capture::from_device(device)
.map_err(|e| Error::Capture(e.to_string()))?
.promisc(false)
.snaplen(65535)
.timeout(100)
.immediate_mode(true)
.open()
.map_err(|e| Error::Capture(e.to_string()))?;
handle
.filter(bpf, true)
.map_err(|e| Error::Capture(format!("BPF `{bpf}`: {e}")))?;
Ok(Self { handle })
}
pub fn open_default(bpf: &str) -> Result<Self> {
let device = Device::lookup()
.map_err(|e| Error::Capture(e.to_string()))?
.ok_or_else(|| Error::Capture("no default network device found".into()))?;
Self::open(&device.name, bpf)
}
}
impl PacketSource for LivePcapSource {
fn next_frame(&mut self) -> Result<Option<Frame>> {
match self.handle.next_packet() {
Ok(pkt) => {
let ts = pkt.header.ts;
Ok(Some(Frame {
timestamp_secs: u64::try_from(ts.tv_sec).unwrap_or(0),
timestamp_usecs: u32::try_from(ts.tv_usec).unwrap_or(0),
bytes: pkt.data.to_vec(),
}))
}
Err(pcap::Error::TimeoutExpired | pcap::Error::NoMorePackets) => Ok(None),
Err(e) => Err(Error::Capture(e.to_string())),
}
}
}