use flowscope::driver::SlotMessage;
use flowscope::driver::{Driver, Event};
use flowscope::extract::{FiveTuple, FiveTupleKey};
use flowscope::pcap::PcapFlowSource;
use flowscope::{FlowSide, SessionParser, Timestamp};
use std::env;
const MARKER_2: &[u8] = b"PFX2,";
const MARKER_4: &[u8] = b"PFX4,";
const HDR_LEN_2: usize = MARKER_2.len() + 2; const HDR_LEN_4: usize = MARKER_4.len() + 4;
#[derive(Debug, Clone)]
pub struct Record {
pub side: FlowSide,
pub body: Vec<u8>,
}
#[derive(Default, Clone)]
pub struct LengthPrefixedParser {
init_buf: Vec<u8>,
resp_buf: Vec<u8>,
}
impl SessionParser for LengthPrefixedParser {
type Message = Record;
fn feed_initiator(&mut self, bytes: &[u8], _ts: Timestamp, out: &mut Vec<Record>) {
Self::drain(&mut self.init_buf, bytes, FlowSide::Initiator, out);
}
fn feed_responder(&mut self, bytes: &[u8], _ts: Timestamp, out: &mut Vec<Record>) {
Self::drain(&mut self.resp_buf, bytes, FlowSide::Responder, out);
}
fn parser_kind(&self) -> &'static str {
"length-prefixed"
}
}
impl LengthPrefixedParser {
fn drain(buf: &mut Vec<u8>, incoming: &[u8], side: FlowSide, out: &mut Vec<Record>) {
buf.extend_from_slice(incoming);
while let Some((hdr, body_len)) = peek_header(buf) {
let total = hdr + body_len;
if buf.len() < total {
break;
}
let body = buf[hdr..total].to_vec();
buf.drain(..total);
out.push(Record { side, body });
}
}
}
pub fn peek_header(buf: &[u8]) -> Option<(usize, usize)> {
if buf.len() < HDR_LEN_2 {
return None;
}
if buf.starts_with(MARKER_4) {
if buf.len() < HDR_LEN_4 {
return None;
}
let len = u32::from_be_bytes(buf[MARKER_4.len()..HDR_LEN_4].try_into().unwrap()) as usize;
return Some((HDR_LEN_4, len));
}
if buf.starts_with(MARKER_2) {
let len = u16::from_be_bytes(buf[MARKER_2.len()..HDR_LEN_2].try_into().unwrap()) as usize;
return Some((HDR_LEN_2, len));
}
None
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = env::args()
.nth(1)
.ok_or("usage: length_prefixed_pcap <trace.pcap>")?;
let mut builder = Driver::builder(FiveTuple::bidirectional());
let mut slot = builder.session_broadcast(LengthPrefixedParser::default());
let mut driver = builder.build();
let mut events: Vec<Event<FiveTupleKey>> = Vec::new();
let mut msgs: Vec<SlotMessage<Record, FiveTupleKey>> = Vec::new();
for view in PcapFlowSource::open(&path)?.views() {
let view = view?;
events.clear();
driver.track_into(&view, &mut events);
msgs.clear();
slot.drain(&mut msgs);
for m in &msgs {
let arrow = if m.message.side == FlowSide::Initiator {
"→"
} else {
"←"
};
println!("{} {} bytes", arrow, m.message.body.len());
}
}
Ok(())
}