Skip to content

Repository files navigation

flowscope

eBPF-powered network flow capture & analysis, built on aya.

flowscope attaches an XDP program to a network interface, accounts traffic per protocol and per flow entirely inside the kernel, and streams packet, DNS and raw-frame events to user space over ring buffers for live analysis, Prometheus metrics and pcap export. It is a pure-aya program: no libbpf, no C toolchain at run time.

Features

  • XDP capture — an XDP_PASS program reads every ingress frame on the chosen interface without copying or dropping traffic.
  • Per-protocol counters — TCP / UDP / ICMP / other packet and byte totals kept in a per-CPU array (PROTO_STATS).
  • 5-tuple flow table — per-flow packet/byte counts and SYN/FIN/RST tallies in a kernel hash map, with user-space idle eviction.
  • Packet event stream — compact per-packet metadata delivered over a ring buffer for live inspection and metrics.
  • IPv4 and IPv6 — a family-tagged flow key and 16-byte address fields cover both stacks through one code path.
  • DNS query visibility — UDP/53 queries and responses are parsed in the kernel and the raw QNAME labels are forwarded for user-space decoding.
  • 802.1Q VLAN — a single VLAN tag is transparently skipped before L3 parsing.
  • Top talkers — source hosts ranked by bytes, aggregated in user space.
  • Prometheus metrics — a built-in HTTP endpoint exposes counters in the standard exposition format.
  • TOML config — every CLI option is overridable from a config file (precedence: CLI > file > built-in default).
  • pcap export — optionally write sampled frames to a classic pcap file readable by Wireshark / tcpdump.
  • JSON or table output — periodic reports as a human table or machine JSON.
  • Graceful shutdownCtrl-C prints a final summary and exits cleanly.

Architecture

                         ┌──────────────────────────── kernel (XDP) ───────────────────────────┐
   ingress frame  ──────▶│  parse eth [+ 802.1Q] → IPv4/IPv6 → TCP/UDP/ICMP                     │
                         │     │              │                  │                              │
                         │     ▼              ▼                  ▼                              │
                         │  PROTO_STATS     FLOWS            EVENTS / DNS_EVENTS / CAPTURE       │
                         │  (per-cpu)    (hash 5-tuple)      (ring buffers)         ▲            │
                         │                                                      CONFIG (Array)   │
                         └──────────┬───────────┬───────────────┬───────────────────┬──────────┘
                                    │           │               │                   │ set at start
                            read each tick   read each tick   drained per wakeup     │
                                    │           │               │                   │
                         ┌──────────▼───────────▼───────────────▼───────────────────▼──────────┐
                         │                          user space (tokio)                          │
                         │  flow table + idle eviction · analysis (top talkers) · dns decode    │
                         │  metrics server (Prometheus) · pcap writer · output (table / JSON)   │
                         └─────────────────────────────────────────────────────────────────────┘
  • Kernel side counts and indexes; it never allocates and never drops.
  • User side snapshots maps on a timer, evicts idle flows, drains the ring buffers, decodes DNS names, serves metrics and writes pcap.

See docs/architecture.md for the full design.

Requirements

  • Linux ≥ 5.8 — the BPF ring buffer (BPF_MAP_TYPE_RINGBUF) landed in 5.8.
  • PrivilegesCAP_BPF + CAP_NET_ADMIN (or simply root) to load the program and attach XDP.
  • No libbpf — loading is pure aya; there is no C toolchain dependency at run time.

Build

The user-space crate builds on stable Rust. The flowscope-ebpf crate is compiled to BPF bytecode and needs the nightly toolchain with the rust-src component plus bpf-linker:

rustup toolchain install nightly --component rust-src
cargo install bpf-linker

A normal release build then compiles the eBPF object automatically — the flowscope crate's build.rs invokes aya-build, which builds flowscope-ebpf for bpfel-unknown-none and embeds the result:

cargo build --release
# binary at target/release/flowscope

Usage

# basic: attach to eth0, print a table every 5s
sudo ./flowscope --iface eth0

# machine-readable periodic reports
sudo ./flowscope --iface eth0 --format json

# expose Prometheus metrics on :9184
sudo ./flowscope --iface eth0 --metrics-addr 0.0.0.0:9184

# load options from a config file (CLI still wins)
sudo ./flowscope --config /etc/flowscope.toml

# capture every 64th frame to a pcap while running
sudo ./flowscope --iface eth0 --pcap capture.pcap --sample 64

# tune reporting and eviction
sudo ./flowscope --iface wlan0 --interval 10 --top 20 --idle-timeout 120

Config file

All CLI options may be set in a TOML file; anything passed on the command line overrides the file, and the file overrides the built-in defaults:

# /etc/flowscope.toml
iface         = "eth0"
interval      = 5      # seconds between reports
top           = 10     # number of top talkers to show
idle_timeout  = 60     # seconds before an idle flow is evicted
format        = "table"
metrics_addr  = "0.0.0.0:9184"
pcap          = "capture.pcap"
sample        = 64     # write every Nth frame to the pcap
dns           = true   # parse and report DNS queries

Metrics

When --metrics-addr is set, any GET returns a Prometheus exposition body:

Series Type Description
flowscope_packets_total{proto="…"} counter packets seen per protocol
flowscope_bytes_total{proto="…"} counter bytes seen per protocol
flowscope_flows gauge live flows in the table
flowscope_packet_events_total counter packet events streamed
flowscope_dns_queries_total counter DNS queries observed

Project layout

.
├── Cargo.toml            # workspace manifest
├── flowscope/            # user-space loader + analysis (binary and library)
│   ├── build.rs          # compiles + embeds the eBPF object via aya-build
│   └── src/
│       ├── main.rs       # thin binary entry point
│       ├── lib.rs        # re-exports the modules below for tests
│       ├── cli.rs        # clap argument parsing
│       ├── config.rs     # TOML config + settings resolution
│       ├── flow.rs       # FlowTable: snapshot + idle eviction
│       ├── analysis.rs   # top talkers / top flows
│       ├── dns.rs        # DNS QNAME decoding
│       ├── metrics.rs    # Prometheus HTTP endpoint
│       ├── pcap.rs        # classic pcap writer
│       └── output.rs     # table / JSON rendering
├── flowscope-common/     # shared no_std types (maps keys, ring events)
├── flowscope-ebpf/       # the XDP program (compiled to BPF bytecode)
└── docs/architecture.md  # design notes

Limitations & notes

  • IPv4 options are not parsed; a 20-byte IPv4 header is assumed.
  • DNS QNAMEs are forwarded raw and truncated to DNS_NAME_CAP (192) bytes.
  • pcap capture is bounded to CAP_SNAPLEN (256) bytes per frame; longer frames are recorded with their true orig_len but a truncated payload.
  • Only a single 802.1Q tag is skipped; stacked (QinQ) tags fall through to the other bucket.

License

Dual-licensed under either of Apache-2.0 or MIT at your option.

About

An ebpf filter for data analysis

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages