stackforge_core/sniffer/
capture.rs1use bytes::Bytes;
2use pcap::{Capture, Device};
3
4use super::config::SnifferConfig;
5use super::error::SnifferError;
6
7#[derive(Debug, Clone)]
9pub struct InterfaceInfo {
10 pub name: String,
11 pub description: Option<String>,
12 pub addresses: Vec<String>,
13 pub is_loopback: bool,
14 pub is_up: bool,
15}
16
17#[derive(Debug, Clone)]
19pub struct RawPacket {
20 pub data: Bytes,
22 pub timestamp_us: i64,
24}
25
26pub(crate) fn open_capture(config: &SnifferConfig) -> Result<Capture<pcap::Active>, SnifferError> {
28 let device = Device::list()
30 .map_err(SnifferError::Pcap)?
31 .into_iter()
32 .find(|d| d.name == config.iface)
33 .ok_or_else(|| SnifferError::InterfaceNotFound(config.iface.clone()))?;
34
35 let mut cap = Capture::from_device(device)
37 .map_err(SnifferError::Pcap)?
38 .snaplen(config.snaplen)
39 .promisc(config.promisc)
40 .timeout(100)
42 .open()
43 .map_err(|e| {
44 let msg = e.to_string();
45 if msg.contains("ermission") || msg.contains("Operation not permitted") {
46 SnifferError::PermissionDenied(msg)
47 } else {
48 SnifferError::Pcap(e)
49 }
50 })?;
51
52 if let Some(ref filter) = config.filter {
54 cap.filter(filter, true)
55 .map_err(|e| SnifferError::InvalidFilter(format!("{filter}: {e}")))?;
56 }
57
58 Ok(cap)
59}
60
61pub fn list_interfaces() -> Result<Vec<InterfaceInfo>, SnifferError> {
63 let devices = Device::list().map_err(SnifferError::Pcap)?;
64 Ok(devices
65 .into_iter()
66 .map(|d| {
67 let addresses: Vec<String> = d.addresses.iter().map(|a| a.addr.to_string()).collect();
68
69 InterfaceInfo {
70 name: d.name,
71 description: d.desc,
72 addresses,
73 is_loopback: false, is_up: true,
75 }
76 })
77 .collect())
78}
79
80pub fn validate_filter(filter: &str) -> Result<(), SnifferError> {
82 let cap = Capture::dead(pcap::Linktype::ETHERNET).map_err(SnifferError::Pcap)?;
84 cap.compile(filter, true)
85 .map_err(|e| SnifferError::InvalidFilter(format!("{filter}: {e}")))?;
86 Ok(())
87}