Distributed DDoS detection and response platform built on XDP/eBPF — wire-speed traffic analysis with automated mitigation.
xSight is a distributed DDoS detection and response platform that combines XDP/eBPF wire-speed packet counting with flow-based analysis (sFlow, NetFlow, IPFIX). It watches traffic on mirror/ERSPAN ports or ingests flow data from routers and switches, detects volumetric attacks using both hard thresholds and dynamic baselines, and triggers automated responses — from BPF-level firewall rules to BGP blackhole announcements.
The system has two components:
- Node — deployed at each observation point, captures traffic via XDP or receives flow data, counts per-IP/per-protocol statistics, and streams them to the controller over gRPC
- Controller — central management plane that runs the detection engine, stores time-series data in TimescaleDB, triggers response actions, and serves the Web UI
| Classic Theme | Amber Theme |
|---|---|
![]() |
![]() |
┌──────────────────────────────────────────────────────────────────────────┐
│ Controller (Detection Plane) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │ Web UI │ │ HTTP API │ │Detection │ │ Response │ │TimescaleDB│ │
│ │ (Vue 3 + │ │ (Gin) │ │ Engine │ │ Actions │ │ (PG) │ │
│ │ EPlus) │ │ │ │ │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └───────────┘ │
└────────────────────────────────┬─────────────────────────────────────────┘
│ gRPC (stats streaming + config publish)
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Node 1 │ │ Node 2 │ │ Node N │
│ (XDP mode) │ │ (Flow mode) │ │ (XDP mode) │
│ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │
│ │ BPF/XDP │ │ │ │ sFlow │ │ │ │ BPF/XDP │ │
│ │ counter │ │ │ │ NetFlow │ │ │ │ counter │ │
│ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │
└─────────────┘ └─────────────┘ └─────────────┘
Mirror/ERSPAN Router/Switch Mirror/ERSPAN
| Mode | How it works | Use case |
|---|---|---|
| XDP | BPF program on mirror/ERSPAN port counts packets at wire speed | High-accuracy, per-packet visibility |
| Flow | sFlow, NetFlow v5/v9, IPFIX receiver with multi-source support | Router/switch integration, no kernel dependency |
- Hard threshold detection — per-decoder limits (PPS + BPS). Built-in decoders: TCP, TCP SYN, UDP, ICMP, fragment, TCP ACK/RST/FIN, GRE, ESP, IGMP,
ip_other,bad_fragment,invalid— 14 total, expandable to 16 - Dynamic baseline detection — EWMA with 168-slot weekly profile (one slot per hour); alerts on percentage deviation from learned baseline
- Bidirectional detection — monitors both inbound and outbound traffic independently
- Global carpet bomb detection — 0.0.0.0/0 aggregate threshold catches distributed attacks spread across many IPs
- Per-decoder granularity — separate thresholds and baselines for each protocol decoder
| Action | Description |
|---|---|
| xDrop | Push BPF firewall rules to xDrop nodes for wire-speed blocking |
| BGP RTBH | Announce /32 blackhole routes via BGP for upstream null-routing |
| Webhook | HTTP callback to external systems (SIEM, Slack, PagerDuty, etc.) |
| Shell | Execute local scripts for custom automation |
- Auto-paired actions — creating an xDrop/BGP
on_detectedaction auto-creates the matchingon_expiredcleanup (unblock / withdraw), kept in sync through the parent's lifecycle - Auto
tcp_flagsinjection — SYN flood events automatically addtcp_flags=SYNto xDrop rules for precision blocking without collateral damage - xDrop decoder compatibility gate — xDrop is L4-only;
ip(L3 aggregate) attacks are skipped withdecoder_not_xdrop_compatibleso they don't degrade into full-prefix blackholes. Use BGP for those. - Shared BGP announcements (Wanguard-style) — multiple attacks sharing a
(prefix, route_map)ref a single FRR route. MAX delay across attached attacks, atomic attach/detach underSELECT FOR UPDATE. - Persisted delayed tasks —
scheduled_actionstable survives controller restart; startup reconciliation re-arms pending timers, fires overdue tasks, retries in-flight crashed tasks. - FRR orphan detection — startup scan surfaces FRR routes with no backing xSight attack so operators can withdraw or dismiss them.
- Dedicated
Active Mitigationspage with BGP Routing + xDrop Filtering tabs and a detail drawer per artifact (Summary / Configuration / Execution Timeline). - Attack Detail shows a
BGP Rolecolumn (triggeredvsattachedto a shared announcement) and per-attack Force Remove so a single attack can be detached without withdrawing the shared route.
- Prometheus
/metricsendpoint with ~15 xSight-specific metrics (vtysh ops, action dispatches, skip reasons, scheduled-action recovery outcomes, state-table gauges, tracker counters) plus Go runtime / process metrics for free. - Custom collectors read DB state at scrape time — always fresh, no staleness window, no background refresh goroutine.
- Flow fingerprint — 5-tuple sampling during attacks captures top talkers and protocol distribution
- Sensor logs — per-event structured logs with full decoder breakdown
- Per-IP tracking — real-time per-destination PPS/BPS with configurable aggregation windows
- Dual themes — Classic (Stripe-inspired clean) and Amber (DSEG14 LCD retro aesthetic)
- Internationalization — full English and Chinese (ZH/EN toggle)
- Real-time dashboards — traffic overview, per-IP drilldown, alert timeline, response history
- Config management — detection profiles, response actions, and node configuration from the browser
- TimescaleDB — continuous aggregates for efficient time-range queries, automatic compression, and configurable retention policies
- Config publish pipeline — Controller pushes detection/response configuration to nodes via gRPC
ControlStream, ensuring all nodes stay in sync without polling
xsight/
├── controller/ # Management plane (Go + Vue 3)
│ ├── internal/ # API, detection engine, tracker, actions, store
│ └── web/ # Vue 3 + Element Plus frontend
├── node/ # Data plane (Go + BPF/XDP)
│ ├── internal/ # BPF loader, reporter, sampler, flow decoder
│ └── bpf/ # XDP kernel program (C)
├── shared/ # Shared decoder package
├── proto/ # gRPC service definition
├── scripts/ # Build & service management
├── deploy/ # systemd unit files
└── .github/assets/ # Logo, screenshots, sponsor
| Component | Requirements |
|---|---|
| Controller | Go 1.25+, Node.js 18+ (frontend build), PostgreSQL 15+ with TimescaleDB |
| Node (XDP mode) | Linux kernel 5.4+, clang/llvm 11+, Go 1.25+, root / CAP_NET_ADMIN |
| Node (Flow mode) | Go 1.25+, no special kernel or root privileges needed |
Hardware (Controller — includes PostgreSQL + TimescaleDB):
| CPU | RAM | Disk | Use Case | |
|---|---|---|---|---|
| Minimum | 4 cores | 8 GB | 40 GB SSD | Small networks, fewer prefixes |
| Recommended | 8 cores | 16 GB | 80 GB SSD | Production, high-traffic environments |
Hardware (Node):
| CPU | RAM | Disk | Notes | |
|---|---|---|---|---|
| XDP mode | 2+ cores | 2 GB+ | 10 GB | Minimal — most work is in BPF kernel space |
| Flow mode | 2+ cores | 2 GB+ | 10 GB | Scales with number of flow exporters |
XDP mode requires Linux — the BPF program attaches to the kernel's XDP hook. Flow mode and the Controller can run on any OS.
For a step-by-step environment setup guide, see Getting Started.
# Build controller (frontend + Go binary)
./scripts/build-controller.sh
# Build node (BPF program + Go binary) — run on a Linux host
./scripts/build-node.sh# Controller
cp controller/config.example.yaml controller/config.yaml
# Edit: set database DSN, gRPC listen address, detection profiles
# Node
cp node/config.example.yaml node/config.yaml
# Edit: set capture mode (xdp/flow), interface, controller gRPC address# Controller (no root required)
./scripts/controller.sh start
# Node — XDP mode (requires root)
sudo ./scripts/node.sh start
# Node — Flow mode (no root required)
./scripts/node.sh start
# Check status
./scripts/controller.sh status
./scripts/node.sh statusThe Web UI is available at http://<controller-host>:8080. Default login: admin / admin — change the password immediately after first login.
When an xDrop action is configured with Dst Port or Src Port match fields, port values are derived from flow_logs via analyzeFlows() at action dispatch time. Because flow_logs is written asynchronously to PostgreSQL (no in-memory ring buffer), the first few ticks after attack detection may have insufficient flow records. In this case {dominant_dst_port} expands to empty, the port field is dropped, and the dispatched xDrop rule matches all traffic for that protocol on the target IP — broader than intended.
Mitigation (until a flow_logs ring buffer is implemented): add a dominant_dst_port_pct gte 40 precondition to any xDrop action that uses the Dst Port field. This causes the action to skip (fail-closed) until enough flow data has accumulated and the dominant port is statistically meaningful.
# Example: safe xDrop action preconditions for port-specific blocking
dominant_dst_port_pct gte 40
cidr eq 32 # optional: single-host only
Tracked as F5 in
internal_docs/roadmap.md. Fix planned: in-memory ring buffer for flow_logs, parallel to the existing ts_stats ring buffer.
MIT — see LICENSE.
BPF/C kernel programs (node/bpf/) are licensed under GPL-2.0 as required by the Linux kernel BPF subsystem.
Built entirely with Claude Code — including the XDP/BPF kernel program, gRPC streaming, detection engine, and Vue frontend.

