use std::hash::Hash;
use std::time::Duration;
use crate::Timestamp;
use crate::event::{AnomalyKind, EndReason, FlowEvent, FlowSide, FlowStats};
use crate::extractor::{FlowExtractor, L4Proto, Orientation, TcpInfo};
use crate::flow_driver::FlowDriver;
use crate::parser_kind::ParserKind;
use crate::reassembler::StreamChunks;
use crate::segment_reassembler::SegmentBufferReassemblerFactory;
use crate::session::core::{Ctx, DatagramCore, Emit, Output, Ports, Selector, SessionCore, Stream};
use crate::session::engine::{Dispatch, Engine};
use crate::session::{
DatagramParser, DatagramParserFactory, SessionEvent, SessionParser, SessionParserFactory,
};
use crate::tracker::{FlowTracker, FlowTrackerConfig};
use crate::view::PacketView;
impl<K: Clone, M: std::fmt::Debug> Output<K, M> for Vec<SessionEvent<K, M>> {
fn message(
&mut self,
key: &K,
side: FlowSide,
orientation: Orientation,
message: M,
ts: Timestamp,
parser_kind: ParserKind,
) {
crate::obs::trace_session_message(side, &message);
self.push(SessionEvent::Application {
key: key.clone(),
side,
orientation,
message,
ts,
parser_kind,
});
}
fn parser_closed(
&mut self,
key: &K,
parser_kind: ParserKind,
reason: EndReason,
detail: Option<String>,
ts: Timestamp,
at_flow_end: bool,
) {
if !at_flow_end {
self.push(SessionEvent::ParserClosed {
key: key.clone(),
parser_kind,
reason,
detail,
ts,
});
}
}
fn parser_side_stopped(
&mut self,
key: &K,
parser_kind: ParserKind,
side: FlowSide,
reason: EndReason,
detail: Option<String>,
ts: Timestamp,
) {
self.push(SessionEvent::ParserSideStopped {
key: key.clone(),
parser_kind,
side,
reason,
detail,
ts,
});
}
fn anomaly(&mut self, key: &K, kind: AnomalyKind, ts: Timestamp) {
self.push(SessionEvent::FlowAnomaly {
key: key.clone(),
kind,
ts,
});
}
}
fn lifecycle<K, M>(ev: FlowEvent<K>, out: &mut Vec<SessionEvent<K, M>>) {
out.extend(SessionEvent::from_flow_event(ev));
}
impl<K, F> Dispatch<K> for SessionCore<K, F>
where
K: Hash + Eq + Clone,
F: SessionParserFactory<K>,
{
type Out = Vec<SessionEvent<K, <F::Parser as SessionParser>::Message>>;
fn needs_ports(&self) -> bool {
self.selector().needs_ports()
}
fn wants_stream(&self, ports: Ports) -> bool {
self.wants(ports)
}
fn wants_datagram(&self, _ports: Ports, _l4: Option<crate::L4Proto>) -> bool {
false
}
fn on_stream(
&mut self,
cx: &Ctx<'_, K>,
ports: Ports,
chunks: &Stream<'_>,
out: &mut Self::Out,
) {
SessionCore::on_stream(self, cx, ports, chunks, out);
}
fn streams_done(&self, key: &K, ports: Ports) -> [bool; 2] {
SessionCore::streams_done(self, key, ports)
}
fn on_datagram(
&mut self,
_cx: &Ctx<'_, K>,
_ports: Ports,
_payload: &[u8],
_out: &mut Self::Out,
) {
}
fn on_flow_end(
&mut self,
key: &K,
reason: EndReason,
stats: &FlowStats,
finals: [&StreamChunks; 2],
ports: Ports,
emit: Emit,
out: &mut Self::Out,
) {
SessionCore::on_flow_end(self, key, reason, stats, finals, ports, emit, out);
}
fn on_tick(
&mut self,
now: Timestamp,
stamp: Timestamp,
orientation_of: &dyn Fn(&K) -> Orientation,
emit: Emit,
out: &mut Self::Out,
) {
SessionCore::on_tick(self, now, stamp, orientation_of, emit, out);
}
fn retain(&mut self, alive: &dyn Fn(&K) -> bool) {
SessionCore::retain(self, alive);
}
fn lifecycle(&mut self, ev: FlowEvent<K>, _tcp: Option<TcpInfo>, out: &mut Self::Out) {
lifecycle(ev, out);
}
}
impl<K, F> Dispatch<K> for DatagramCore<K, F>
where
K: Hash + Eq + Clone,
F: DatagramParserFactory<K>,
{
type Out = Vec<SessionEvent<K, <F::Parser as DatagramParser>::Message>>;
fn needs_ports(&self) -> bool {
self.selector().needs_ports()
}
fn wants_stream(&self, _ports: Ports) -> bool {
false
}
fn wants_datagram(&self, ports: Ports, l4: Option<crate::L4Proto>) -> bool {
self.wants(ports, l4)
}
fn on_stream(
&mut self,
_cx: &Ctx<'_, K>,
_ports: Ports,
_chunks: &Stream<'_>,
_out: &mut Self::Out,
) {
}
fn streams_done(&self, _key: &K, _ports: Ports) -> [bool; 2] {
[true, true]
}
fn on_datagram(&mut self, cx: &Ctx<'_, K>, ports: Ports, payload: &[u8], out: &mut Self::Out) {
DatagramCore::on_datagram(self, cx, ports, payload, out);
}
fn on_flow_end(
&mut self,
key: &K,
reason: EndReason,
stats: &FlowStats,
_finals: [&StreamChunks; 2],
_ports: Ports,
emit: Emit,
out: &mut Self::Out,
) {
DatagramCore::on_flow_end(self, key, reason, stats, emit, out);
}
fn on_tick(
&mut self,
now: Timestamp,
stamp: Timestamp,
orientation_of: &dyn Fn(&K) -> Orientation,
emit: Emit,
out: &mut Self::Out,
) {
DatagramCore::on_tick(self, now, stamp, orientation_of, emit, out);
}
fn retain(&mut self, alive: &dyn Fn(&K) -> bool) {
DatagramCore::retain(self, alive);
}
fn lifecycle(&mut self, ev: FlowEvent<K>, _tcp: Option<TcpInfo>, out: &mut Self::Out) {
lifecycle(ev, out);
}
}
macro_rules! shared_driver_api {
() => {
pub fn with_emit_anomalies(mut self, enable: bool) -> Self {
self.engine.flow.set_emit_anomalies(enable);
self
}
pub fn set_emit_anomalies(&mut self, enable: bool) {
self.engine.flow.set_emit_anomalies(enable);
}
pub fn with_dedup(mut self, dedup: crate::Dedup) -> Self {
self.engine.flow.set_dedup(Some(dedup));
self
}
pub fn set_dedup(&mut self, dedup: Option<crate::Dedup>) {
self.engine.flow.set_dedup(dedup);
}
pub fn dedup(&self) -> Option<&crate::Dedup> {
self.engine.flow.dedup()
}
pub fn with_monotonic_timestamps(mut self, enable: bool) -> Self {
self.engine.flow.set_monotonic_timestamps(enable);
self
}
pub fn set_monotonic_timestamps(&mut self, enable: bool) {
self.engine.flow.set_monotonic_timestamps(enable);
}
pub fn with_idle_timeout_fn<G>(mut self, f: G) -> Self
where
G: Fn(&E::Key, Option<L4Proto>) -> Option<Duration> + Send + Sync + 'static,
{
self.engine.flow.tracker_mut().set_idle_timeout_fn(f);
self
}
pub fn set_config(&mut self, config: FlowTrackerConfig) {
self.engine.flow.set_config(config);
}
pub fn config(&self) -> &FlowTrackerConfig {
self.engine.flow.tracker().config()
}
pub fn tracker(&self) -> &FlowTracker<E, ()> {
self.engine.flow.tracker()
}
pub fn set_idle_timeout_fn<G>(&mut self, f: G)
where
G: Fn(&E::Key, Option<L4Proto>) -> Option<Duration> + Send + Sync + 'static,
{
self.engine.flow.tracker_mut().set_idle_timeout_fn(f);
}
pub fn pause_events(&mut self) {
self.engine.flow.pause_events();
}
pub fn resume_events(&mut self) {
self.engine.flow.resume_events();
}
pub fn flow_driver(&self) -> &FlowDriver<E, SegmentBufferReassemblerFactory, ()> {
&self.engine.flow
}
pub fn snapshot_flow_stats(&self) -> impl Iterator<Item = (E::Key, FlowStats)> + '_ {
self.engine.flow.snapshot_flow_stats()
}
pub fn flow_stats(&self, key: &E::Key) -> Option<FlowStats> {
self.engine.flow.flow_stats(key)
}
pub fn track_into<'v>(
&mut self,
view: impl Into<PacketView<'v>>,
out: &mut Vec<SessionEvent<E::Key, M>>,
) {
self.engine.track(view, &mut self.core, out);
}
pub fn track<'v>(
&mut self,
view: impl Into<PacketView<'v>>,
) -> Vec<SessionEvent<E::Key, M>> {
let mut out = Vec::new();
self.track_into(view, &mut out);
out
}
pub fn sweep_into(&mut self, now: Timestamp, out: &mut Vec<SessionEvent<E::Key, M>>) {
self.engine.sweep(now, &mut self.core, out);
}
pub fn sweep(&mut self, now: Timestamp) -> Vec<SessionEvent<E::Key, M>> {
let mut out = Vec::new();
self.sweep_into(now, &mut out);
out
}
pub fn finish_into(&mut self, out: &mut Vec<SessionEvent<E::Key, M>>) {
self.engine.finish(&mut self.core, out);
}
pub fn finish(&mut self) -> Vec<SessionEvent<E::Key, M>> {
let mut out = Vec::new();
self.finish_into(&mut out);
out
}
pub fn force_close_into(
&mut self,
key: &E::Key,
now: Timestamp,
out: &mut Vec<SessionEvent<E::Key, M>>,
) {
self.engine.force_close(key, now, &mut self.core, out);
}
pub fn force_close(
&mut self,
key: &E::Key,
now: Timestamp,
) -> Vec<SessionEvent<E::Key, M>> {
let mut out = Vec::new();
self.force_close_into(key, now, &mut out);
out
}
};
}
pub struct SessionDriver<E, F>
where
E: FlowExtractor,
F: SessionParserFactory<E::Key>,
{
engine: Engine<E>,
core: SessionCore<E::Key, F>,
}
impl<E, F, M> SessionDriver<E, F>
where
E: FlowExtractor,
E::Key: Hash + Eq + Clone,
F: SessionParserFactory<E::Key>,
F::Parser: SessionParser<Message = M>,
{
pub fn new(extractor: E, factory: F) -> Self {
Self::with_config(extractor, factory, FlowTrackerConfig::default())
}
pub fn with_config(extractor: E, factory: F, config: FlowTrackerConfig) -> Self {
Self::from_tracker(FlowTracker::with_config(extractor, config), factory)
}
pub fn from_tracker(tracker: FlowTracker<E, ()>, factory: F) -> Self {
Self {
engine: Engine::from_tracker(tracker),
core: SessionCore::new(factory, Selector::All),
}
}
shared_driver_api!();
}
pub struct DatagramDriver<E, F>
where
E: FlowExtractor,
F: DatagramParserFactory<E::Key>,
{
engine: Engine<E>,
core: DatagramCore<E::Key, F>,
}
impl<E, F, M> DatagramDriver<E, F>
where
E: FlowExtractor,
E::Key: Hash + Eq + Clone,
F: DatagramParserFactory<E::Key>,
F::Parser: DatagramParser<Message = M>,
{
pub fn new(extractor: E, factory: F) -> Self {
Self::with_config(extractor, factory, FlowTrackerConfig::default())
}
pub fn with_config(extractor: E, factory: F, config: FlowTrackerConfig) -> Self {
Self::from_tracker(FlowTracker::with_config(extractor, config), factory)
}
pub fn from_tracker(tracker: FlowTracker<E, ()>, factory: F) -> Self {
Self {
engine: Engine::from_tracker(tracker),
core: DatagramCore::new(factory, Selector::All),
}
}
shared_driver_api!();
}