use std::collections::HashSet;
use std::io::{BufWriter, stdout};
use std::net::IpAddr;
use flowscope::detect::patterns::BeaconDetector;
use flowscope::emit::{EveJsonWriter, EveOptions};
use flowscope::extract::FiveTuple;
use flowscope::pcap::PcapFlowSource;
use flowscope::reassembler::BufferedReassemblerFactory;
use flowscope::{
DetectorKind, FlowDriver, KeyFields, OwnedAnomaly, PacketView, Timestamp, event::Severity,
};
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct SrcIpKey(IpAddr);
impl KeyFields for SrcIpKey {
fn src_ip(&self) -> Option<IpAddr> {
Some(self.0)
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = std::env::args()
.nth(1)
.unwrap_or_else(|| "tests/data/mixed_short.pcap".to_string());
let mut driver = FlowDriver::new(
FiveTuple::bidirectional(),
BufferedReassemblerFactory::default(),
)
.with_emit_anomalies(true);
let mut opts = EveOptions::default();
opts.in_iface = "pcap0".to_string();
opts.include_stats = true; let mut eve = EveJsonWriter::with_options(BufWriter::new(stdout().lock()), opts);
let mut beacon: BeaconDetector<IpAddr> = BeaconDetector::new();
let mut detector_emitted: HashSet<IpAddr> = HashSet::new();
let mut last_ts = Timestamp { sec: 0, nsec: 0 };
for view in PcapFlowSource::open(&path)?.views() {
let view = view?;
last_ts = view.timestamp;
let pv = PacketView::new(&view.frame, view.timestamp);
if let Ok(layers) = pv.layers() {
let src: Option<IpAddr> = if let Some(v4) = layers.ipv4() {
Some(IpAddr::V4(v4.source()))
} else {
layers.ipv6().map(|v6| IpAddr::V6(v6.source()))
};
if let Some(src) = src
&& let Some(score) = beacon.observe(src, view.timestamp, view.frame.len() as u64)
&& score.score >= 0.7
&& detector_emitted.insert(src)
{
let anomaly =
OwnedAnomaly::new(DetectorKind::BeaconCv, Severity::Warning, view.timestamp)
.with_key(&SrcIpKey(src))
.with_metric("score", score.score)
.with_metric("cv_dt", score.cv_dt)
.with_metric("cv_bytes", score.cv_bytes)
.with_metric("mean_interval_secs", score.mean_interval.as_secs_f64());
eve.write_owned_anomaly(&anomaly)?;
}
}
for ev in driver.track(&view) {
eve.write_event(&ev)?;
}
}
for ev in driver.sweep(last_ts) {
eve.write_event(&ev)?;
}
eve.finish()?;
Ok(())
}