Expand description
§netring
High-performance, zero-copy packet I/O for Linux — async-first, pure Rust, no native C dependencies.
netring captures and injects packets over AF_PACKET (TPACKET_V3 block-based
mmap rings) and AF_XDP (kernel-bypass XDP sockets), and pairs them with a
declarative Monitor for flow tracking, L7 parsing, and anomaly detection.
Flow/session logic lives in the companion crate
flowscope (cross-platform, no tokio).
[dependencies]
netring = { version = "0.29", features = ["tokio"] }// Zero-copy borrowed batches via AsyncFd — nothing is copied per packet.
let mut cap = netring::AsyncCapture::open("eth0")?;
loop {
let mut guard = cap.readable().await?;
while let Some(batch) = guard.next_batch() {
for pkt in &batch {
let _data: &[u8] = pkt.data(); // borrows from the ring
let _ts = pkt.timestamp(); // nanosecond kernel timestamp
}
}
}§Why netring
- Zero-copy, zero-alloc hot path. Borrowed batches; the Monitor run loop does 0 allocations per packet (enforced by a dhat regression bench).
- Two backends, one API. AF_PACKET everywhere; AF_XDP for kernel-bypass
line rate — same shapes, no native C deps (pure
libc/aya). - Async-first. tokio adapters with a
Send + 'staticrun loop you cantokio::spawn; a runtime-agnostic channel adapter too. - Batteries included. Typed BPF builder, flow/session tracking, L7 parsers (HTTP/TLS/DNS/ICMP/QUIC + Tier-2: SSH, FTP, SMTP, NTP, SNMP, Modbus, DNP3, STUN, WireGuard, SMB/Kerberos/LDAP/RDP), fingerprinting (JA3/JA4/JA4H/JA4X, HASSH, p0f), and a fluent Monitor with detectors, middleware, sinks, and exporters.
- Network security monitoring. Threat-intel IOC matching (flowscope’s
threat backbone),
FlowAnalyzerflow-risk scoring, pluggable NDR detectors with MITRE ATT&CK tagging, YARA-X payload scanning, Sigma rule evaluation (with live hot-reload of IOC / Sigma / YARA sets), RITA beacon detection, SSH (HASSH) / QUIC / TLS (JA3/JA4, PQ key-share) fingerprinting, encrypted-DNS (DoH/DoT/DoQ) visibility, IP-fragment reassembly (anti-evasion), passive asset inventory, nPrint + CICFlowMeter ML export, and an OCSF Detection-Finding sink. - Observability out of the box. Rolling traffic aggregation (top talkers, host-pair matrix, top domains/SNI), RED metrics (rate/errors/duration) per protocol, owner-attributed bandwidth (by tenant/container/subscriber), Community ID on flow records, and rotating + pre-trigger pcap capture.
- Runs where the traffic is. Capture inside a container’s network namespace
(
NetNs+CaptureBuilder::netns), per-CPU sharding, and multi-NIC fan-in.
§The Monitor: subscriptions
The Monitor is the high-level “watch an interface and react to typed events”
API. The front door is the typed subscription engine — three strongly-typed
tiers whose filters split into a kernel part (pushed into BPF, so uninteresting
traffic is shed before it reaches userspace) and a userspace remainder:
use netring::monitor::Monitor;
use netring::monitor::subscription::{packet, flow, session};
use netring::protocol::builtin::{Tcp, Tls};
Monitor::builder()
.interface("eth0")
.protocol::<Tcp>()
.protocol::<Tls>()
// every frame to :443 (the tcp+port part is pushed into the kernel BPF)
.subscribe(packet().tcp().dst_port(443).to(|view, ctx| Ok(())))
// once per flow, at its end, for flows over 1 MiB
.subscribe(flow::<Tcp>().bytes_over(1 << 20).to(|ended, ctx| Ok(())))
// each parsed TLS handshake whose SNI matches a glob
.subscribe(session::<Tls>().sni_glob("*.bank.example").to(|msg, ctx| Ok(())))
// a runtime filter string → the SAME predicate AST as the typed combinators
.subscribe(packet().expr("udp and dst port 53")?.to(|view, ctx| Ok(())))
.build()?
.run_until_signal()
.await?;| Tier | Constructor | Handler sees | Fires |
|---|---|---|---|
| packet | packet() | &PacketView | every matching frame (pre-tracking) |
| flow | flow::<P>() | &FlowEnded<P> | once per matching flow, at its end |
| session | session::<P>() | &P::Message | each parsed L7 message that matches |
Runnable: examples/monitor/subscriptions.rs.
§The Monitor: handlers, detectors, sinks
on::<E> / on_ctx::<E> register typed handlers; detect(...) plugs in
detector! / pattern_detector! rules; a tower-style layer chain processes
the anomaly sink; and sinks ship the results.
use std::time::Duration;
use netring::prelude::*;
Monitor::builder()
.interface("eth0")
.protocol::<Tcp>() // FlowStarted/Ended<Tcp>
.protocol::<Http>() // HttpMessage events
.on_ctx::<Http>(|msg, ctx| {
ctx.emit("HttpRequest", Severity::Info).with("path", msg.path).emit();
Ok(())
})
.layer(MinSeverity::warning()) // outermost: drop Info
.layer(DedupeAnomalies::within(Duration::from_secs(60)))
.sink(StdoutJsonSink::default()) // innermost: NDJSON
.run_until_signal()
.await?;- Handlers:
on(payload),on_ctx(payload +&mut Ctx),on_async(payload →Sendfuture), andon_effect— readCtxsynchronously, do async I/O, return deferredEffects(0.25). - Middleware (5):
MinSeverity,DedupeAnomalies,RateLimitAnomalies,Sample,Tee— compose freely, outermost-first. - Sinks (4 core):
StdoutSink,StdoutJsonSink,TracingSink,ChannelSink; plusEveSink/EveTlsSink(Suricata EVE),SyslogSink(RFC 5424),IpfixExporter(RFC 7011), and OTLP/Kafka innetring-exporters. - Run modes:
run_until_signal(),run_for(Duration),run_until(Instant),run_until_idle(window),replay()(offline pcap).
The Monitor is Send and its run-loop future is Send + 'static — so
tokio::spawn(monitor.run_for(d)) works on the default multi-thread runtime.
See docs/WRITING_DETECTORS.md for the detector tutorial and examples/monitor/ for runnable demos (subscriptions, port-scan/beacon/DGA detectors, EVE/OTLP export, resilience, sharding, tracing-JSON).
§Capture & inject
Every type has a ::open(iface) shortcut and a ::builder() for full config.
// Async inject with backpressure (awaits POLLOUT when the ring is full):
let mut tx = netring::AsyncInjector::open("eth0")?;
tx.send(&frame).await?;
tx.flush().await?;
// TX symmetry (0.25): stream-inject, rate-paced, with egress timestamps.
use netring::TxPacer;
let inj = netring::Injector::builder().interface("eth0").tx_timestamps(true).build()?;
let mut tx = netring::AsyncInjector::new(inj)?;
tx.send_stream(frames, Some(TxPacer::packets_per_second(10_000.0))).await?;
let _egress_ts = tx.read_tx_timestamp();// AF_XDP (kernel bypass) — same shape as AsyncCapture; needs an XDP redirect
// program. `xdp_interface_loaded` (feature `xdp-loader`) attaches one for you.
let monitor = netring::monitor::Monitor::builder()
.xdp_interface_loaded("eth0")
.protocol::<Tcp>()
.build()?;The sync Capture / Injector / XdpSocket power the async wrappers and are
usable directly (flat packets() iterator or block-level batches). See
docs/API_OVERVIEW.md and
docs/ASYNC_GUIDE.md.
§Flow & session tracking
netring = { version = "0.29", features = ["tokio", "flow"] }use futures::StreamExt;
use netring::AsyncCapture;
use netring::flow::FlowEvent;
use netring::flow::extract::FiveTuple;
let cap = netring::AsyncCapture::open("eth0")?;
let mut stream = cap.flow_stream(FiveTuple::bidirectional());
while let Some(evt) = stream.next().await {
match evt? {
FlowEvent::Started { key, .. } => println!("+ {} <-> {}", key.a, key.b),
FlowEvent::Ended { key, history, .. } => println!("- {} <-> {} {history}", key.a, key.b),
_ => {}
}
}Pluggable flow keys (5-tuple, IpPair, MacPair, VLAN/MPLS/VXLAN/GTP-U decap),
bidirectional sessions, a TCP state machine with Zeek-style history, idle-timeout
sweep + LRU eviction, optional TCP reassembly, and feature-gated L7 parsers
(http, tls with JA3/JA4 fingerprinting, dns, icmp). The flow API itself
lives in flowscope and works on any
source of &[u8] frames (pcap, tun/tap, embedded).
§BPF filters
A typed classic-BPF builder — no tcpdump -dd, no libpcap:
use netring::{BpfFilter, Capture};
let filter = BpfFilter::builder()
.tcp().dst_port(443)
.or(|b| b.udp().dst_port(53))
.build()
.unwrap();
let _cap = Capture::builder().interface("eth0").bpf_filter(filter).build().unwrap();Vocabulary: ipv4/ipv6/arp, vlan/vlan_id, tcp/udp/icmp,
src_host/dst_host/host, src_net/dst_net/net,
src_port/dst_port/port, negate(), or(|b| …).
AsyncCapture::set_filter swaps the filter atomically on a running ring;
BpfFilter::matches(&[u8]) runs the bytecode in pure Rust for offline testing.
§Performance & scaling
- Per-CPU sharding:
ShardedRunner::new(iface, FanoutMode::Cpu, group, n, build)fans one interface across N sockets in aPACKET_FANOUTgroup;.pin_cpus(true)binds each shard to its core. - AF_XDP tuning: UMEM hugepages (
MAP_HUGETLB) + NUMA binding (mbind); busy-poll trio (busy_poll_us/prefer_busy_poll/busy_poll_budget). - Numbers & methodology: docs/PERFORMANCE.md (capture
vs. dispatch split, the dispatch-throughput bench, tuning levers) and
docs/scaling.md (
FanoutModematrix + anti-patterns).
§Companion crate: netring-exporters
OTLP and Kafka anomaly export live in
netring-exporters, keeping those heavy dependency
trees out of netring’s core. OtlpAnomalySink (feature otlp) and KafkaSink
(feature kafka) both implement netring’s AnomalySink, so they drop straight
into .sink(...).
§Features
Features are organized as orthogonal axes (full matrix + recipes in docs/FEATURES.md). The common ones:
| Feature | Description |
|---|---|
tokio | Async wrappers (AsyncCapture/AsyncInjector/AsyncXdpSocket) + the Monitor |
af-xdp / xdp-loader | AF_XDP kernel bypass; xdp-loader bundles the redirect program (via aya) |
channel | Runtime-agnostic thread + bounded-channel adapter |
flow | Flow & session tracking (pulls flowscope) |
http / dns / tls / icmp / quic | L7 parsers; ja4plus adds JA4S (FoxIO License) |
arp / ndp / lldp / cdp / asset | L2/discovery: ARP + IPv6 NDP watch, LLDP/CDP, passive asset::Inventory |
ssh / infra-protocols / ot-protocols / ftp / smtp / stun / wireguard | Tier-2 protocol markers (SSH/HASSH, NTP/SNMP/TFTP/RADIUS, Modbus/DNP3, …) |
ad-protocols / asset-protocols | Active-Directory (SMB/Kerberos/LDAP/RDP) + DHCP/SSDP/NBNS device facts |
ioc / sigma / yara / p0f | Threat-intel IOC, Sigma rules, YARA-X payload scan, p0f OS fingerprint |
nprint / ml-features | Per-flow ML export (nPrint header-bit matrix, CICFlowMeter features) |
pcap | PCAP/PCAPNG read + write |
eve-sink / syslog / ipfix / metrics / ocsf-sink | Suricata EVE / RFC 5424 / RFC 7011 / Prometheus / OCSF Detection Finding |
monitor / monitor-lite / monitor-quickstart | Monitor umbrellas (full / lean / app-tier) |
§Public API
| Concept | Sync | Async |
|---|---|---|
| AF_PACKET RX | Capture | AsyncCapture<Capture> |
| AF_PACKET TX | Injector | AsyncInjector |
| AF_XDP (RX+TX) | XdpSocket | AsyncXdpSocket |
| Bridge two interfaces | Bridge | Bridge::run_async |
| Multi-source fan-in | — | AsyncMultiCapture |
| Declarative pipeline | — | Monitor / ShardedRunner |
§Requirements
- Linux kernel 3.2+ (TPACKET_V3), 5.4+ (AF_XDP).
- Rust 1.95+ (edition 2024).
- Capabilities:
CAP_NET_RAW(open sockets),CAP_NET_ADMIN(promiscuous, XDP attach),CAP_IPC_LOCK(MAP_LOCKED, or a sufficientRLIMIT_MEMLOCK).
just setcap grants the capabilities once so tests/examples run without sudo.
§Examples
Organized by topic under examples/ — basic/,
async_basics/, filter/, scaling/, xdp/, flow/, l7/, pcap/,
monitor/. Each is listed with its required --features in
examples/README.md. Start with
monitor_subscriptions for the typed subscription API.
§Documentation
- docs/INDEX.md — the full documentation map.
- API Overview · Architecture · Async guide · Features
- Performance · Scaling · Tuning · Troubleshooting
- Writing detectors · Fingerprints · Metrics
- Migrating: 0.27 → 0.28 · 0.26 → 0.27 · 0.24 → 0.25 · earlier guides
§License
Licensed under either Apache-2.0 or MIT at your
option. (The optional ja4plus feature is FoxIO License 1.1 — see
docs/FINGERPRINTS.md.)
Re-exports§
pub use afpacket::rx::Capture;pub use afpacket::rx::CaptureBuilder;pub use afpacket::rx::Packets;pub use afpacket::tx::Injector;pub use afpacket::tx::InjectorBuilder;pub use afpacket::tx::TxSlot;pub use bridge::Bridge;pub use bridge::BridgeAction;pub use bridge::BridgeBuilder;pub use bridge::BridgeDirection;pub use bridge::BridgeHandles;pub use bridge::BridgeStats;pub use config::BpfBuildError;pub use config::BpfFilter;pub use config::BpfFilterBuilder;pub use config::BpfInsn;pub use config::BusyPollConfig;pub use config::FanoutFlags;pub use config::FanoutMode;pub use config::IpNet;pub use config::ParseIpNetError;pub use config::RingProfile;pub use config::TimestampSource;pub use dedup::Dedup;pub use error::Error;pub use interface::InterfaceInfo;pub use interface::interface_info;pub use packet::BatchIter;pub use packet::OwnedPacket;pub use packet::Packet;pub use packet::PacketBatch;pub use packet::PacketDirection;pub use packet::PacketStatus;pub use packet::TimestampClock;pub use stats::CaptureStats;pub use stats::DropBreakdown;pub use traits::PacketSetFilter;pub use traits::PacketSink;pub use traits::PacketSource;pub use afxdp::XdpBatch;pub use afxdp::XdpBatchIter;pub use afxdp::XdpPacket;pub use afxdp::XdpMode;pub use afxdp::XdpSocket;pub use afxdp::XdpSocketBuilder;pub use afxdp::XdpStats;pub use async_adapters::channel::ChannelCapture;pub use async_adapters::dedup_stream::DedupStream;pub use async_adapters::tokio_adapter::AsyncCapture;pub use async_adapters::tokio_adapter::PacketStream;pub use async_adapters::tokio_adapter::ReadableGuard;pub use async_adapters::tokio_injector::AsyncInjector;pub use async_adapters::tokio_injector::TxPacer;pub use async_adapters::tokio_xdp::AsyncXdpSocket;pub use async_adapters::tokio_xdp::XdpReadableGuard;pub use async_adapters::tokio_xdp::XdpStream;pub use async_adapters::tokio_xdp_capture::AsyncXdpCapture;pub use traits::AsyncPacketSource;pub use async_adapters::conversation::Conversation;pub use async_adapters::conversation::ConversationChunk;pub use async_adapters::conversation::ConversationStream;pub use async_adapters::flow_broadcast::BroadcastRecvError;pub use async_adapters::flow_broadcast::FlowBroadcast;pub use async_adapters::flow_broadcast::FlowSubscriber;pub use async_adapters::flow_stream::AsyncReassemblerSlot;pub use async_adapters::flow_stream::FlowStream;pub use async_adapters::flow_stream::NoReassembler;pub use async_adapters::multi_capture::AsyncMultiCapture;pub use async_adapters::multi_capture::AsyncXdpMultiCapture;pub use async_adapters::multi_config::MultiStreamConfig;pub use async_adapters::multi_streams::MergedFlowStream;pub use async_adapters::multi_streams::MultiDatagramStream;pub use async_adapters::multi_streams::MultiFlowStream;pub use async_adapters::multi_streams::MultiSessionStream;pub use async_adapters::multi_streams::TaggedEvent;pub use async_adapters::multi_streams::XdpMultiDatagramStream;pub use async_adapters::multi_streams::XdpMultiFlowStream;pub use async_adapters::multi_streams::XdpMultiSessionStream;pub use async_adapters::stream_capture::StreamCapture;pub use async_adapters::stream_capture::StreamSetFilter;pub use pcap_flow::PcapDatagramStream;pub use pcap_flow::PcapFlowStream;pub use pcap_flow::PcapSessionStream;pub use pcap_source::AsyncPcapConfig;pub use pcap_source::AsyncPcapSource;pub use pcap_source::PcapFormat;pub use pcap_tap::PcapTap;pub use pcap_tap::TapErrorPolicy;pub use protocol::Dispatch;pub use protocol::FlowKey;pub use protocol::FlowProtocol;pub use protocol::MessageProtocol;pub use protocol::Protocol;pub use protocol::ProtocolInitError;pub use protocol::SignatureMatch;pub use anomaly::Anomaly;pub use anomaly::AnomalyContext;pub use anomaly::Severity;
Modules§
- afpacket
- AF_PACKET backend implementation.
- afxdp
- AF_XDP backend for kernel-bypass packet I/O.
- anomaly
- Anomaly value types + emission sinks.
- async_
adapters - Async and channel adapters for packet capture.
- bridge
- Bidirectional packet bridge between two interfaces (IPS mode).
- config
- Configuration types: fanout, BPF filters, timestamps, ring profiles.
- correlate
- 0.21 G: netring’s
TimeBucketedCounteris now re-exported from flowscope (thenew_unboundedctor lands the 2-arg shape). Three extra primitives (BurstDetector,Ewma,TopK,TimeBucketedSet,SequencePattern,KeylessSequencePattern,FlowStateMap) join the module for free.KeyIndexedstays netring-side until flowscope adds adrain_expired-style iterator method (see module docstring). Correlation primitives for multi-protocol anomaly detection. - ctx
- Per-event context passed to handlers.
- dedup
- Loopback / content-hash packet deduplication.
- detector_
macro - Declarative
detector!macro — terse stateless detector definitions for use withcrate::monitor::Monitor. - error
- Error types for netring.
- export
- 0.24 Phase D: flow export —
FlowRecord/FlowExporter/MonitorBuilder::export_flows. The fourth output shape beside anomalies, reports, and broadcast streams: one record per completed flow (NetFlow/IPFIX-style). 0.24 Phase D — flow export. - flow
- Source-agnostic flow & session tracking types from
flowscope. - interface
- Interface capability detection.
- layer
- Middleware over the
AnomalySinkchain. - metrics
- Metrics integration via the
metricsfaçade (feature:metrics). - monitor
- Top-level
Monitorbuilder + run loop. - netns
- Linux network-namespace capture (issue #126).
- packet
- Packet types: zero-copy views, batch iteration, timestamps, and owned packets.
- pcap
- PCAP/PCAPNG export helpers (feature:
pcap). - pcap_
flow PcapFlowStream— flow tracking over offline pcap files.- pcap_
rotate - Rotating + triggered pcap writers (issue #125).
- pcap_
source - Async pcap source for offline replay — feeds the same downstream tooling (flow trackers, decoders) as a live AF_PACKET capture.
- pcap_
tap - Pcap tap — record each captured packet to a
CaptureWriterbefore the flow tracker processes it. - prelude
- Glob-importable re-exports of the canonical netring API.
- protocol
- Protocol plugin layer + typed event surface.
- report
- 0.22 §3: periodic structured reports (
Report/ReportSink/ReportSnapshot) — the third output stream beside anomalies and broadcast event streams. 0.22 §3 — periodic structured reports. - stats
- Capture statistics.
- traits
- Core traits for packet capture and injection.
- well_
known - 0.22 §2.2: well-known port → app/protocol label table, re-exported
from flowscope for a stable
netring::well_known::LabelTablepath. Pass a custom table toMonitorBuilder::label_table. - xdp
- AF_XDP capture surface: queue discovery + multi-queue capture (issue #6) and,
with the
xdp-loaderfeature, the built-in XDP program loader.
Macros§
- detector
- Build a stateless detector for the 0.20
Monitorbuilder. - pattern_
detector - 0.21 I.1: declarative pattern-detector glue for flowscope’s
stateful detectors (
PortScanDetector,BeaconDetector,DgaScorer, …) plus any third-party detector whose score implementsflowscope::DetectorScore.
Structs§
- Packet
View - What a
crate::FlowExtractoris given. - Timestamp
- Nanosecond-precision kernel timestamp.