use std::fs::File;
use std::io::{BufReader, Read};
use std::path::Path;
use crate::tracker::FlowEvents;
#[cfg(all(feature = "session", feature = "reassembler", feature = "extractors"))]
use crate::{DatagramParser, FlowDatagramDriver};
use crate::{FlowEvent, FlowExtractor, FlowTracker, Timestamp};
#[cfg(all(feature = "session", feature = "reassembler"))]
use crate::{FlowSessionDriver, SessionEvent, SessionParser};
use pcap_file::pcap::PcapReader;
use crate::error::{Error, Module};
pub struct PcapFlowSource<R: Read> {
reader: PcapReader<R>,
}
impl PcapFlowSource<BufReader<File>> {
pub fn open(path: impl AsRef<Path>) -> crate::Result<Self> {
let file = File::open(path).map_err(|e| Error::io(Module::Pcap, e))?;
let reader = PcapReader::new(BufReader::new(file))
.map_err(|e| Error::parse_with(Module::Pcap, "invalid pcap header", e))?;
Ok(Self { reader })
}
}
impl<R: Read> PcapFlowSource<R> {
pub fn from_reader(reader: R) -> crate::Result<Self> {
Ok(Self {
reader: PcapReader::new(reader)
.map_err(|e| Error::parse_with(Module::Pcap, "invalid pcap header", e))?,
})
}
pub fn views(self) -> ViewIter<R> {
ViewIter {
reader: self.reader,
}
}
pub fn with_extractor<E: FlowExtractor>(self, extractor: E) -> EventIter<R, E>
where
E::Key: Clone,
{
EventIter {
views: self.views(),
tracker: FlowTracker::new(extractor),
pending: std::collections::VecDeque::new(),
sweep_done: false,
}
}
#[cfg(all(feature = "session", feature = "reassembler"))]
pub fn sessions<E, P>(self, extractor: E, parser: P) -> SessionIter<R, E, P>
where
E: FlowExtractor,
E::Key: std::hash::Hash + Eq + Clone + Send + 'static,
P: SessionParser + Clone + Send + 'static,
{
SessionIter {
views: self.views(),
driver: FlowSessionDriver::new(extractor, parser),
pending: std::collections::VecDeque::new(),
finished: false,
}
}
#[cfg(all(feature = "session", feature = "reassembler", feature = "extractors"))]
pub fn datagrams<E, P>(self, extractor: E, parser: P) -> DatagramIter<R, E, P>
where
E: FlowExtractor,
E::Key: std::hash::Hash + Eq + Clone + Send + 'static,
P: DatagramParser + Clone + Send + 'static,
{
DatagramIter {
views: self.views(),
driver: FlowDatagramDriver::new(extractor, parser),
pending: std::collections::VecDeque::new(),
finished: false,
}
}
}
pub use crate::view::OwnedPacketView;
pub struct ViewIter<R: Read> {
reader: PcapReader<R>,
}
impl<R: Read> Iterator for ViewIter<R> {
type Item = crate::Result<OwnedPacketView>;
fn next(&mut self) -> Option<Self::Item> {
let pkt = self.reader.next_packet()?;
match pkt {
Ok(p) => {
let ts = Timestamp::new(p.timestamp.as_secs() as u32, p.timestamp.subsec_nanos());
Some(Ok(OwnedPacketView {
frame: p.data.into_owned(),
timestamp: ts,
}))
}
Err(e) => Some(Err(Error::parse_with(
Module::Pcap,
"malformed pcap record",
e,
))),
}
}
}
pub struct EventIter<R: Read, E: FlowExtractor>
where
E::Key: Clone,
{
views: ViewIter<R>,
tracker: FlowTracker<E, ()>,
pending: std::collections::VecDeque<FlowEvent<E::Key>>,
sweep_done: bool,
}
impl<R: Read, E: FlowExtractor> Iterator for EventIter<R, E>
where
E::Key: Clone,
{
type Item = crate::Result<FlowEvent<E::Key>>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(ev) = self.pending.pop_front() {
return Some(Ok(ev));
}
match self.views.next() {
Some(Ok(view)) => {
let evts: FlowEvents<E::Key> = self.tracker.track(&view);
for ev in evts {
self.pending.push_back(ev);
}
}
Some(Err(e)) => return Some(Err(e)),
None => {
if !self.sweep_done {
self.sweep_done = true;
for ev in self.tracker.sweep(Timestamp::MAX) {
self.pending.push_back(ev);
}
} else {
return None;
}
}
}
}
}
}
#[cfg(all(feature = "session", feature = "reassembler"))]
pub struct SessionIter<R: Read, E, P>
where
E: FlowExtractor,
E::Key: std::hash::Hash + Eq + Clone + Send + 'static,
P: SessionParser + Clone + Send + 'static,
{
views: ViewIter<R>,
driver: FlowSessionDriver<E, P>,
pending: std::collections::VecDeque<SessionEvent<E::Key, P::Message>>,
finished: bool,
}
#[cfg(all(feature = "session", feature = "reassembler"))]
impl<R: Read, E, P> Iterator for SessionIter<R, E, P>
where
E: FlowExtractor,
E::Key: std::hash::Hash + Eq + Clone + Send + 'static,
P: SessionParser + Clone + Send + 'static,
{
type Item = crate::Result<SessionEvent<E::Key, P::Message>>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(ev) = self.pending.pop_front() {
return Some(Ok(ev));
}
match self.views.next() {
Some(Ok(view)) => {
for ev in self.driver.track(&view) {
self.pending.push_back(ev);
}
}
Some(Err(e)) => return Some(Err(e)),
None => {
if self.finished {
return None;
}
self.finished = true;
for ev in self.driver.finish() {
self.pending.push_back(ev);
}
}
}
}
}
}
#[cfg(all(feature = "session", feature = "reassembler", feature = "extractors"))]
pub struct DatagramIter<R: Read, E, P>
where
E: FlowExtractor,
E::Key: std::hash::Hash + Eq + Clone + Send + 'static,
P: DatagramParser + Clone + Send + 'static,
{
views: ViewIter<R>,
driver: FlowDatagramDriver<E, P>,
pending: std::collections::VecDeque<SessionEvent<E::Key, P::Message>>,
finished: bool,
}
#[cfg(all(feature = "session", feature = "reassembler", feature = "extractors"))]
impl<R: Read, E, P> Iterator for DatagramIter<R, E, P>
where
E: FlowExtractor,
E::Key: std::hash::Hash + Eq + Clone + Send + 'static,
P: DatagramParser + Clone + Send + 'static,
{
type Item = crate::Result<SessionEvent<E::Key, P::Message>>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(ev) = self.pending.pop_front() {
return Some(Ok(ev));
}
match self.views.next() {
Some(Ok(view)) => {
for ev in self.driver.track(&view) {
self.pending.push_back(ev);
}
}
Some(Err(e)) => return Some(Err(e)),
None => {
if self.finished {
return None;
}
self.finished = true;
for ev in self.driver.finish() {
self.pending.push_back(ev);
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn owned_view_converts_to_packet_view() {
let owned = OwnedPacketView {
frame: vec![1, 2, 3, 4],
timestamp: Timestamp::new(7, 42),
};
let pv: crate::PacketView<'_> = (&owned).into();
assert_eq!(pv.frame, &[1, 2, 3, 4]);
assert_eq!(pv.timestamp, Timestamp::new(7, 42));
}
}