session only.Expand description
Pluggable L7 message parsers.
Two trait families:
-
SessionParser— for stream-based protocols (HTTP/1, TLS, DNS-over-TCP). One parser per session; receives bytes viafeed_initiator/feed_responder; returns aVecof typed messages every call. Pair withnetring::SessionStreamto get an async stream of L7 events. -
DatagramParser— for packet-based protocols (DNS-over-UDP, syslog, NTP, SNMP). Receives one L4 payload at a time. Pair withnetring::DatagramStream.
Both trait shapes return owned Vec<Message> rather than borrowed
iterators or SmallVec to keep the public API stable across
versions of smallvec etc. The per-call allocation is amortized
across many bytes worth of work.
§SessionParser vs Reassembler
crate::Reassembler is the lower-level hook: one instance per
(flow, side), receives raw TCP segments and yields the ordered
byte stream as crate::StreamChunks (data interleaved with gap
marks). SessionParser is the higher-level
abstraction: one instance per flow, two feed_* methods,
returns typed messages directly. Pick whichever fits your
integration:
| Concern | Reassembler | SessionParser |
|---|---|---|
| Granularity | per (flow, side) | per flow |
| Output | StreamChunks (bytes + gaps) | typed messages |
| Cross-direction state | painful | natural |
| UDP support | no | use DatagramParser |
§Running parsers
SessionDriver/DatagramDriver— one parser type over a whole capture, yielding an ordered stream ofSessionEvents (lifecycle, messages, parser closes, anomalies). Whatnetring’sSessionStream/DatagramStreamwrap.crate::driver::Driver— several parsers (by port, by signature, or on every flow) sharing one flow table, with typed per-parser drain handles.
Both are built on the same engine, so they behave identically: one flow table, one reassembler per flow side (shared by every parser), and these per-parser rules:
- A parser that reports
SessionParser::is_poisonedorSessionParser::is_doneafter a call is closed (a parser close event withEndReason::ParseError/EndReason::ParserDone, plus anAnomalyKind::SessionParseErrorfor poison when anomalies are on). It is never fed again for that flow — and never re-created: the flow itself stays tracked until its transport end. A parser close never ends the flow;Ended/Closedalways carries a transport reason (Fin,Rst,IdleTimeout,Evicted,ForceClosed). - The one reporting difference: a parser still open when its flow
ends.
SessionDriver/DatagramDriversay so withClosedalone; the typedDriveralso emits oneEvent::ParserClosedper slot carrying the transport reason (EndReason::is_transport) right beforeEnded. - Missing bytes are reported through
SessionParser::on_gap. The default answer,GapResponse::StopSide, stops feeding that side only (a parser side-stopped event withEndReason::StreamGap); the other side keeps being parsed.GapResponse::Continueresynchronises,GapResponse::Stopcloses the whole parser. - A reassembly stop on one side (per-side cap under
crate::OverflowPolicy::DropFlow, memcap) stops that side withEndReason::BufferOverflow. - When both sides are stopped the parser closes once (detail
"both sides stopped"). - At flow end each side still being read gets
SessionParser::fin_initiator/SessionParser::fin_responder(graceful end, or that side sent a FIN) orrst_*; a stopped side gets neither. - Datagram parsers only see the transports they declare
(
DatagramParser::transports, defaultTransports::UDP): a UDP parser never gets ICMP messages and vice versa.
§Example
use flowscope::{FlowSide, SessionParser, Timestamp};
#[derive(Default, Clone)]
struct LineParser {
init_buf: Vec<u8>,
resp_buf: Vec<u8>,
}
impl SessionParser for LineParser {
type Message = (FlowSide, String);
fn feed_initiator(&mut self, bytes: &[u8], _ts: Timestamp, out: &mut Vec<Self::Message>) {
feed(&mut self.init_buf, bytes, FlowSide::Initiator, out);
}
fn feed_responder(&mut self, bytes: &[u8], _ts: Timestamp, out: &mut Vec<Self::Message>) {
feed(&mut self.resp_buf, bytes, FlowSide::Responder, out);
}
}
fn feed(buf: &mut Vec<u8>, bytes: &[u8], side: FlowSide, out: &mut Vec<(FlowSide, String)>) {
buf.extend_from_slice(bytes);
while let Some(nl) = buf.iter().position(|&b| b == b'\n') {
let line = String::from_utf8_lossy(&buf[..nl]).into_owned();
out.push((side, line));
buf.drain(..=nl);
}
}Structs§
- Accumulating
Session Parser - Convenience
SessionParserimpl over aparse_oneclosure of shapeFn(&[u8]) -> Option<(M, usize)>. - Buffered
Frame Drain - Buffered drain helper for custom parsers.
- Datagram
Driver extractorsandreassembler - One
DatagramParsertype over a UDP capture, with an orderedSessionEventoutput. The datagram sibling ofSessionDriver; no reassembly is involved. - PerDatagram
Parser - Convenience
DatagramParserimpl over aparse_oneclosure of shapeFn(&[u8]) -> Option<M>. - Session
Driver extractorsandreassembler - One
SessionParsertype over a TCP capture: flow tracking, reassembly (out-of-order hole fill, gaps, limits) and per-flow parser dispatch, with an orderedSessionEventoutput. - Template
Factory - A
SessionParserFactory/DatagramParserFactorythat clones a template parser for every flow. The blanket factory impls needDefault + Clone; this one only needsClone, for parsers built from configuration. - Transports
- Transports a
DatagramParserreads (seeDatagramParser::transports). New in 0.25.0.
Enums§
- Frame
Drain Error - Reasons
BufferedFrameDrain/AccumulatingSessionParserpoison themselves. - GapResponse
- Answer to
SessionParser::on_gap. - Session
Event - Output of
SessionDriver/DatagramDriver: flow lifecycle, parser messages, parser closes and anomalies, in the order they happened.Kis the flow key,Mthe parser’s message type.
Constants§
- DEFAULT_
FRAME_ DRAIN_ MAX_ BUFFER - Default per-side buffer cap for
BufferedFrameDrain/AccumulatingSessionParser. 64 KiB matches the TCP receive-buffer scale.
Traits§
- Datagram
Parser - Parses a packet-oriented L7 protocol. One instance per flow; receives one L4 payload at a time along with which side sent it.
- Datagram
Parser Factory - Builds a fresh
DatagramParserper session. - Session
Parser - Parses a stream-oriented L7 protocol session. One instance per flow; both directions feed through the same parser, allowing state to interleave.
- Session
Parser Factory - Builds a fresh
SessionParserper session. Modeled oncrate::ReassemblerFactory.