pub mod ethernet_frame;
pub use ethernet_frame::*;
pub mod ipv4_packet;
pub use ipv4_packet::*;
pub mod tcp_packet;
pub use tcp_packet::*;
pub use pnet::packet::Packet;
use pnet::datalink::Channel::Ethernet;
use pnet::datalink::{self, NetworkInterface};
use pnet::packet::ethernet::EthernetPacket as pnet_EthernetPacket;
use pnet::packet::ipv4::Ipv4Packet as pnet_Ipv4Packet;
use pnet::packet::tcp::TcpPacket as pnet_TcpPacket;
use std::error::Error;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
#[derive(Debug)]
pub struct Uninitialized;
#[derive(Debug)]
pub struct Initialized;
#[derive(Debug)]
pub struct Started;
#[derive(Debug)]
pub struct Completed;
#[derive(Debug)]
pub struct PacketCapture<State> {
interface: NetworkInterface,
packets: Arc<Mutex<Vec<Vec<u8>>>>,
results: Arc<[Vec<u8>]>,
state: PhantomData<State>,
stop_signal: Arc<AtomicBool>,
}
impl PacketCapture<Uninitialized> {
pub fn new_from_interface(
interface_name: &str,
) -> Result<PacketCapture<Initialized>, Box<dyn Error>> {
let interface = datalink::interfaces()
.into_iter()
.find(|iface| iface.name == interface_name)
.ok_or(format!("Could not find interface '{interface_name}'"))?;
Ok(PacketCapture {
interface,
packets: Arc::new(Mutex::new(vec![])),
results: Arc::new([]),
state: PhantomData,
stop_signal: Arc::new(AtomicBool::new(false)),
})
}
pub fn new_with_default() -> Result<PacketCapture<Initialized>, Box<dyn Error>> {
let interface = datalink::interfaces()
.into_iter()
.find(|iface| iface.is_up() && !iface.is_loopback() && !iface.ips.is_empty())
.ok_or("Could not determine default interface")?;
Ok(PacketCapture {
interface,
packets: Arc::new(Mutex::new(vec![])),
results: Arc::new([]),
state: PhantomData,
stop_signal: Arc::new(AtomicBool::new(false)),
})
}
}
impl PacketCapture<Initialized> {
pub fn start_capture(&self) -> PacketCapture<Started> {
let stop_signal = Arc::clone(&self.stop_signal);
let interface = self.interface.clone();
let mut rx = match datalink::channel(&interface, Default::default()) {
Ok(Ethernet(_, rx)) => rx,
Ok(_) => panic!("Non-ethernet channel created"),
Err(e) => panic!("Could not create channel using interface: {e}"),
};
let packets = Arc::clone(&self.packets);
rayon::spawn(move || {
while !stop_signal.load(Ordering::Relaxed) {
match rx.next() {
Ok(packet) => {
packets.lock().unwrap().push(packet.to_owned());
}
Err(e) => panic!("Could not read packet: {e}"),
}
}
});
PacketCapture {
interface: self.interface.clone(),
packets: self.packets.clone(),
results: self.results.clone(),
state: PhantomData,
stop_signal: self.stop_signal.clone(),
}
}
pub fn start_live_process(
&self,
mut callback: impl FnMut(Vec<u8>) + std::marker::Send + 'static,
) -> PacketCapture<Started> {
let stop_signal = Arc::clone(&self.stop_signal);
let interface = self.interface.clone();
let mut rx = match datalink::channel(&interface, Default::default()) {
Ok(Ethernet(_, rx)) => rx,
Ok(_) => panic!("Non-ethernet channel created"),
Err(e) => panic!("Could not create channel: {e}"),
};
rayon::spawn(move || {
while !stop_signal.load(Ordering::Relaxed) {
match rx.next() {
Ok(packet) => {
callback(packet.to_vec());
}
Err(e) => panic!("Could not read packet: {e}"),
}
}
});
PacketCapture {
interface: self.interface.clone(),
packets: self.packets.clone(),
results: self.results.clone(),
state: PhantomData,
stop_signal: self.stop_signal.clone(),
}
}
}
impl PacketCapture<Started> {
pub fn stop_capture(&self) -> PacketCapture<Completed> {
self.stop_signal.store(true, Ordering::Relaxed);
PacketCapture {
interface: self.interface.clone(),
packets: self.packets.clone(),
results: Arc::from(
self.packets
.lock()
.unwrap()
.clone()
.into_iter()
.collect::<Vec<_>>(),
),
state: PhantomData,
stop_signal: self.stop_signal.clone(),
}
}
}
impl PacketCapture<Completed> {
pub fn results_raw(&self) -> Arc<[Vec<u8>]> {
self.results.clone()
}
pub fn results_as_ethernet(&self) -> EthernetFrameCollection<'_> {
self.results_raw()
.iter()
.filter(|buf| pnet_EthernetPacket::new(buf).is_some())
.map(|buf| EthernetFrame::from(pnet_EthernetPacket::owned(buf.to_vec()).unwrap()))
.collect::<EthernetFrameCollection>()
}
pub fn results_as_ipv4(&self) -> Ipv4PacketCollection<'_> {
self.results_as_ethernet()
.iter()
.filter(|ethernet_frame| pnet_Ipv4Packet::new(ethernet_frame.payload()).is_some())
.map(|ethernet_frame| {
Ipv4Packet::from(pnet_Ipv4Packet::owned(ethernet_frame.payload().to_vec()).unwrap())
})
.collect::<Ipv4PacketCollection>()
}
pub fn results_as_tcp(&self) -> TcpSegmentCollection<'_> {
self.results_as_ipv4()
.iter()
.filter(|ipv4_packet| pnet_TcpPacket::new(ipv4_packet.payload()).is_some())
.map(|ipv4_packet| {
TcpSegment::from(pnet_TcpPacket::owned(ipv4_packet.payload().to_vec()).unwrap())
})
.collect::<TcpSegmentCollection>()
}
}