Skip to content

Add eBPF SYN-flood candidate detection#8

Merged
lai3d merged 1 commit into
mainfrom
claude/syn-flood-detection
May 18, 2026
Merged

Add eBPF SYN-flood candidate detection#8
lai3d merged 1 commit into
mainfrom
claude/syn-flood-detection

Conversation

@lai3d
Copy link
Copy Markdown
Owner

@lai3d lai3d commented May 18, 2026

Summary

Adds a new eBPF kprobe on tcp_v4_rcv that counts inbound TCP SYN packets per source IPv4 address, useful for spotting SYN-flood candidates. Extends the existing eBPF observability subsystem (currently 8 probes) with a 9th.

What

Kernel side (sigma-agent-ebpf/src/main.rs):

  • New kprobe tcp_v4_rcv_syn attached to tcp_v4_rcv(struct sk_buff *skb)
  • Reads iph->saddr and TCP flags from skb->head + skb->network_header using fixed offsets (mirrors the existing SKC_DPORT_OFFSET / SRTT_US_OFFSET pattern)
  • Filters SYN-only (SYN && !ACK); increments a BPF_MAP_TYPE_HASH<u32, SynCountValue> map keyed by source IP
  • Bounded at 8192 entries; full-map writes drop silently

Shared types (sigma-agent-ebpf-common):

  • New SynCountValue #[repr(C)] struct shared between kernel and userspace

Userspace (sigma-agent/src/ebpf_traffic.rs, metrics.rs, mcp.rs):

  • SynStats type + Arc<RwLock<Vec<SynStats>>> snapshot
  • harvest_syn() reads + resets the map each interval (so counts are per-window, not cumulative)
  • Prometheus: sigma_tcp_syn_count{source_ip} — only non-zero entries emitted
  • MCP: new tool query_syn_flood_candidates with optional min_syn filter (default 100)

Design choices

  • Hook choice: tcp_v4_rcv rather than tcp_conn_request. tcp_v4_rcv counts attempted SYNs including flood traffic dropped before request_sock creation — exactly what you want for flood detection. Cost is a few bpf_probe_read_kernel calls + early return on non-SYN packets.
  • Bounded BPF map (8192 entries). Prevents unbounded memory growth under a flood. New entries silently dropped when full — a degradation we accept for resource safety.
  • Window-based counts. Map is reset each harvest cycle (default 30s), so sigma_tcp_syn_count represents SYNs in the last window, not all-time. Easier for alerting (rate-of-change isn't needed).
  • Graceful degradation. If the kprobe attach fails (kernel too old, missing BTF), the agent logs a warning and continues without the metric — matches the pattern of the existing DNS/exec/OOM probes.

Test plan

  • cargo check --no-default-features — clean (userspace compiles without aya)
  • cargo test --no-default-features — 25/25 pass (IP-format helper + Prometheus render tests)
  • cargo check --features ebpf-traffic — sigma-agent code type-checks before the pre-existing aya/macOS failure (Linux-only crate)
  • README.md updated with new SYN-flood subsection under ## eBPF Traffic Monitoring
  • Real-VPS validation on Linux 5.10+ with BTF (separate step)

Part of the agent roadmap.

Adds a `tcp_v4_rcv` kprobe that inspects each inbound IPv4 TCP segment,
filters for SYN-only (SYN=1, ACK=0), reads the source IPv4 from the
embedded IP header, and increments a per-source-IP BPF HashMap (bounded
at 8192 entries — when full, new keys are dropped silently). The map is
read-and-cleared every harvest interval so the exposed value is the SYN
volume seen in the most recent window.

Hook choice: `tcp_v4_rcv(struct sk_buff *skb)`. This is the entry into
the IPv4 TCP receive path and fires once per inbound segment. The probe
uses fixed `sk_buff` offsets (head=200, network_header=182) and an IPv4
ihl-aware computation to locate the TCP flags byte, mirroring the
existing approach used for `skc_dport` and `srtt_us` in this codebase.
If the layout shifts on a different kernel, the `bpf_probe_read_kernel`
calls fail safely and the probe returns Ok(()) without recording.

Userspace pieces:
- `SynCountValue` shared type in `sigma-agent-ebpf-common`
- New `SynStats` / `SharedSynStats` plumbing in `ebpf_traffic.rs`
- `harvest_syn` reads + clears the SYN_MAP and converts saddr u32 (in
  network byte order, as observed by `bpf_probe_read_kernel`) back to
  dotted-quad strings
- `render_syn_metrics` emits `sigma_tcp_syn_count{hostname,source_ip}`
  on the existing `/metrics` endpoint, only for non-zero entries
- MCP tool `query_syn_flood_candidates` (optional `min_syn` arg,
  default 100). Returns `{"enabled": false, "candidates": []}` when
  built without `--features ebpf-traffic`
- README subsection under "eBPF Traffic Monitoring"

The kprobe attach is best-effort: if the kernel hook is unavailable
(too old, BTF missing, layout drift), the agent logs a warning and
continues — mirroring the existing DNS/exec/OOM probe pattern.

Constraints relaxed: chose `tcp_v4_rcv` over `tcp_conn_request` /
`inet_csk_complete_hashdance` despite the spec preferring the
simplest LISTEN-state hook. `tcp_v4_rcv` fires per-segment so the
filter cost is a few `bpf_probe_read_kernel` calls + early return for
non-SYN traffic; this is the most reliable way to count *attempted*
SYNs (not just those reaching SYN-RECV) and the spec explicitly
named this hook first.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lai3d lai3d force-pushed the claude/syn-flood-detection branch from 2971bba to ef72466 Compare May 18, 2026 17:57
@lai3d lai3d merged commit ffd06f4 into main May 18, 2026
@lai3d lai3d deleted the claude/syn-flood-detection branch May 18, 2026 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant