flowscope
Passive flow & session tracking for packet capture.
flowscope is a runtime-free, cross-platform Rust library for observing
what's happening on the wire. It pairs with any source of &[u8] frames:
netring (Linux AF_PACKET / AF_XDP),
pcap files, tun/tap, eBPF, embedded — anywhere bytes show up.
No tokio, no futures, no async runtime in the core. (For tokio integration,
see netring's AsyncCapture::flow_stream etc., which consume this crate's
traits.)
What's here
PacketView → FlowExtractor → FlowTracker → Reassembler → SessionParser / DatagramParser
↑ ↓
anything typed L7 messages
Core (always on):
FlowExtractortrait + built-in extractors (5-tuple, IP-pair, MAC-pair) + decap combinators (VLAN, MPLS, VXLAN, GTP-U, GRE) +AutoDetectEncapcombinator +FlowLabelIPv6 augmentation.FlowTracker— bidirectional flow accounting, TCP state machine, idle timeouts, LRU eviction.Reassembler— sync per-(flow, side) hook for TCP byte streams.SessionParser/DatagramParser— typed L7 message parsing per flow.
Protocol parsers + analysis modules (each behind its own feature):
| Feature | What you get |
|---|---|
http |
HTTP/1.x request/response parsing via HttpParser (SessionParser); HttpExchangeParser aggregates a request/response pair into one HttpExchange event (0.10) |
tls |
TLS handshake observer (ClientHello/ServerHello/Alert) via TlsParser (SessionParser) — passive only, no decryption; TlsHandshakeParser aggregates a handshake into one event |
ja3 |
JA3 client fingerprinting (sub-feature of tls) |
ja4 |
JA4 client fingerprinting (sub-feature of tls) |
dns |
DNS message parser, per-flow query/response correlator. UDP via DnsUdpParser (DatagramParser); TCP via DnsTcpParser (SessionParser, RFC 1035 §4.2.2 length-framed); DnsExchangeParser aggregates query+response into one DnsExchange event (0.10) |
icmp |
ICMPv4/v6 message parser (IcmpParser — DatagramParser) |
pcap |
pcap file source for offline replay |
emit |
flowscope::emit — FlowEventCsvWriter + ZeekConnLogWriter (RFC-4180 quoting, conn.log headers) (0.10) |
emit-ndjson |
adds FlowEventNdjsonWriter to emit; pulls in serde_json (0.10) |
aggregate |
flowscope::aggregate — Histogram + Percentile (t-digest) for SLO baselining (0.10) |
l7 |
Umbrella: http + tls + dns + icmp |
full |
All of the above (incl. ja3, ja4, pcap, serde, observability, emit, emit-ndjson, aggregate) |
Plus always-on modules that don't need a feature flag:
flowscope::correlate— cross-flow correlation primitives:TimeBucketedCounter,TimeBucketedSet,KeyIndexed,BurstDetector,TopK,Ewma,SequencePattern.flowscope::detect—shannon_entropy,is_high_entropy,is_base64ish,is_hex_string,hamming_distance,ngram_distribution, plusdetect::signatures(10 magic-byte recognizers + registry).flowscope::well_known— curated(L4Proto, port)→ short-label table (~70 entries) for protocol-by-port labelling.flowscope::layers— zero-copy per-packet layered view (Ethernet/VLAN/MPLS/IPv4/IPv6/ARP/TCP/UDP/ICMPv4/ICMPv6/ GRE/VXLAN/GTP-U) withLayerParser+LayerStackzero-alloc fast path.
Quick start
[]
= { = "0.10", = ["full"] }
MSRV is Rust 1.88.
One import, one builder chain, one iterator — the high-level
Pipeline entry point introduced in 0.9.0:
use *;
use HttpParser;
#
Pipeline bundles the common driver setup with sensible defaults
(anomalies emitted, monotonic timestamps for offline replay).
For per-flow user state, custom drainers, or multiple parsers
per L4, drop to FlowSessionDriver / FlowDatagramDriver
directly.
Per-packet introspection
The 0.9 flowscope::layers module exposes a zero-copy view of a
frame with both direct accessors and a dynamic walk:
use PacketView;
use LayerKind;
#
Custom protocols
For an end-to-end example of writing a SessionParser for your own
wire format — including the synchronous offline pcap path via
FlowSessionDriver —
see examples/length_prefixed_pcap.rs. The example demonstrates a
length-prefixed binary protocol (PSMSG-shaped) with two
variable-length markers and is paired with a deterministic pcap
fixture under tests/fixtures/length_prefixed/.
Tokio integration
flowscope itself is runtime-free. To consume a live capture into a stream
of FlowEvent / SessionEvent via tokio, use netring:
use AsyncCapture;
use FiveTuple;
use HttpParser;
use StreamExt;
# async
Status
0.10.0 — Combined 0.9 + 0.10 cycle release. DX polish +
structured-output cycle on top of the 0.9 surface plus the
centerpiece plan 116 unified Driver<E, M> + Event<K, M>. Modules: flowscope::emit (CSV /
NDJSON / Zeek conn.log writers), flowscope::aggregate
(Histogram / Percentile), flowscope::detect (entropy
primitives + 10-protocol signature recognizers),
flowscope::well_known (curated (proto, port) → label
table), correlate extensions (TimeBucketedSet /
BurstDetector / TopK / Ewma), parser ergonomics
(AccumulatingSessionParser / PerDatagramParser /
BufferedFrameDrain), exchange aggregators
(HttpExchangeParser / DnsExchangeParser), rustdoc
landing pages on every L7 module + 9 new HTTP accessors,
and a quick-win helper sweep across Timestamp /
FlowStats / EndReason / LayerKind / Layer /
LayerStack / KeyIndexed. Centerpiece — driver+event
unification (Driver<E, M> + Event<K, M> replacing the
6-driver / 4-event surface) — shipped at
flowscope::driver_unified::{Driver, DriverBuilder, Event, Pipeline, PipelineBuilder} alongside the legacy types for
migration. The legacy types remain shipped in 0.10; deletion is
queued for the next major release (plan 117).
0.9.0 (also in flight) — biggest release since 0.1:
high-level Pipeline entry point, public
flowscope::layers per-packet view (with tunnel walking
- zero-alloc fast path), unified
flowscope::Error,flowscope::correlatecross-flow primitives,FlowMultiSessionDrivercomposite driver,SegmentBufferReassemblerOOO TCP hole-fill, JA4 TLS fingerprint +TlsHandshakeParseraggregator,FlowTracker::with_auto_sweepfor live/offline parity,flowscope::prelude, MSRV bumped to 1.88.
0.8.0 was the last point release: serde wire-format lock, ICMP correlation helpers, programmatic flow termination, per-flow snapshot iterator, multi-protocol monitor recipe.
Core flow APIs (FlowExtractor, FlowTracker, Reassembler,
SessionParser, DatagramParser) are settled; public structs
and enums are #[non_exhaustive] so future variants and fields
are additive. See CHANGELOG.md for the
release history.
See docs/getting-started.md for a
hello-world,
docs/concepts.md for the conceptual model,
docs/recipes.md for worked patterns,
docs/observability.md for metrics +
tracing, examples/README.md for a
catalog of 25+ runnable examples (port-scan detection, IoC
extraction, Zeek-style conn.log, TLS handshake inventory,
per-packet inspection, NDJSON export, custom protocols, …),
and CHANGELOG.md for the per-release feature
list and migration recipes.
License
MIT OR Apache-2.0, your choice.