use std::env;
use flowscope::SessionEvent;
use flowscope::dns::{DnsMessage, DnsUdpParser};
use flowscope::extract::FiveTuple;
use flowscope::http::{HttpMessage, HttpParser};
use flowscope::icmp::IcmpParser;
use flowscope::pcap::PcapFlowSource;
use flowscope::tls::{TlsMessage, TlsParser};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = env::args()
.nth(1)
.ok_or("usage: multi_protocol_monitor <trace.pcap>")?;
let mut events: Vec<(flowscope::Timestamp, String)> = Vec::new();
{
let source = PcapFlowSource::open(&path)?
.sessions(FiveTuple::bidirectional(), HttpParser::default());
for evt in source {
let evt = evt?;
if let SessionEvent::Application {
message: HttpMessage::Request(req),
ts,
..
} = evt
{
events.push((
ts,
format!(
"HTTP {} {} (host={})",
req.method,
req.path,
req.host().unwrap_or("?")
),
));
}
}
}
{
let source =
PcapFlowSource::open(&path)?.sessions(FiveTuple::bidirectional(), TlsParser::default());
for evt in source {
let evt = evt?;
if let SessionEvent::Application {
message: TlsMessage::ClientHello(hello),
ts,
..
} = evt
{
events.push((
ts,
format!("TLS ClientHello sni={}", hello.sni().unwrap_or("?")),
));
}
}
}
{
let source = PcapFlowSource::open(&path)?
.datagrams(FiveTuple::bidirectional(), DnsUdpParser::default());
for evt in source {
let evt = evt?;
if let SessionEvent::Application { message, ts, .. } = evt {
match message {
DnsMessage::Query(q) => {
let n = q.questions.first().map(|q| q.name.as_str()).unwrap_or("?");
events.push((ts, format!("DNS Q {n}")));
}
DnsMessage::Response(r) => {
let n = r.questions.first().map(|q| q.name.as_str()).unwrap_or("?");
events.push((ts, format!("DNS R {n} ({} answers)", r.answers.len())));
}
_ => {}
}
}
}
}
{
let source =
PcapFlowSource::open(&path)?.datagrams(FiveTuple::bidirectional(), IcmpParser::new());
for evt in source {
let evt = evt?;
if let SessionEvent::Application { message, ts, .. } = evt {
if let Some((label, inner)) = message.error_inner() {
events.push((
ts,
format!(
"ICMP {label} referencing {} → {} (proto={})",
inner.src, inner.dst, inner.proto
),
));
} else {
events.push((
ts,
format!("ICMP {} ({:?})", message.short_kind(), message.family),
));
}
}
}
}
events.sort_by_key(|(ts, _)| *ts);
for (ts, line) in events {
println!("[{ts}] {line}");
}
Ok(())
}