Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

sentinel-gate

A pre-host XDP packet inspection daemon for Linux. An eBPF program attaches to a network interface at the earliest possible kernel hook, validates every inbound packet, and exports rich metadata through a BPF ring buffer to a Rust userspace daemon that reconstructs flows, runs signature and behavioural anomaly detection, enforces firewall rules via nftables, and streams live telemetry to a web dashboard.

NIC → XDP eBPF (kernel) → ring buffer → collector → flow tracker
                                                    → signature engine → response engine → nftables
                                                    → anomaly engine  ↗
                                                    → telemetry logger
                                                    → dashboard (HTTP + WebSocket)

Features

Kernel-level inspection (XDP)

  • Validates IP headers, TCP/UDP lengths, and checksum before the packet reaches the kernel network stack
  • Drops land attacks, bogon/martian sources, tiny fragments, impossible TCP flag combinations, and NULL/XMAS scans at wire speed
  • Exports a 104-byte PacketMeta record per packet to userspace via BPF ring buffer

Signature detection

  • JSON rule file hot-reloadable without daemon restart (sentinel rules reload)
  • Match on: protocol, port, src/dst CIDR, payload substring, packet size range, IP reputation, domain patterns, TCP flags, port category
  • Per-rule verdict (suspicious / malicious) and severity (lowcritical)
  • Ships with 30 rules covering port scans, C2 beaconing, web shells, SQL injection, crypto miners, RDP/SMB attacks, and more

Behavioural anomaly detection

  • Scored heuristic model: per-IP float score 0–100 with exponential decay (60 s half-life)
  • 9 heuristics: XMAS scan, NULL scan, FIN scan, SYN flood, high packet rate, port scan, excessive DNS, large transfer, beaconing
  • Beaconing detection via inter-arrival time coefficient of variation (CV < 0.15 over ≥ 10 samples)
  • Alert fires only on upward band crossing (0–30 normal → 31–60 suspicious → 61–100 malicious) to suppress repeated noise

Automated response (nftables)

  • Five configurable enforcement tiers: log-only, alert, block-flow, temp-ban, perm-ban
  • Creates and owns an inet sentinel_gate nftables table with three sets: banned_ips (timeout), permanent_bans, blocked_flows (src_ip × dst_port)
  • Separate policies for suspicious vs. malicious alerts
  • --response-dry-run for safe testing without firewall changes

Flow tracking

  • Reconstructs TCP/UDP/ICMP flows from individual packet events
  • Configurable TTL (default 60 s) and max concurrent flows (default 65 536)
  • Emits flow summaries at TCP FIN/RST, TTL expiry, or shutdown

Structured telemetry

  • Human-readable coloured output or machine-readable JSONL
  • File logging with size-based rotation (configurable MB limit, keeps last 3 files)
  • Minimum severity filter: info, low, medium, high, critical
  • Canonical event fields: timestamp, src_ip, dst_ip, flow_id, detection_type, severity, reason

Live web dashboard

  • Single-page dark-theme UI served from the daemon — no separate web server needed
  • Live Traffic Map: animated Canvas showing source IPs orbiting a centre node, particles colour-coded by verdict
  • Recent Alerts: scrolling table with severity colour coding
  • Top Talkers: live horizontal bar chart by packet count
  • Blocked IPs: table with live countdown timers
  • Pushes updates every second via WebSocket

CLI control (sentinel)

  • sentinel start — exec-replace into sentinel-gate with all flags forwarded
  • sentinel stop — graceful shutdown via Unix domain socket
  • sentinel status — live stats: packets, alerts, anomalies, responses, uptime
  • sentinel rules reload — hot-swap signatures.json without restart
  • sentinel interface attach — attach to a new interface (requires restart; returns clear error)

Requirements

Requirement Minimum
Linux kernel 5.8 (BPF ring buffer)
Rust toolchain 1.75
clang 14+
libbpf-dev any recent
nftables optional — response engine degrades gracefully
CAP_NET_ADMIN required to attach XDP

Ubuntu / Debian:

sudo apt install clang llvm libbpf-dev nftables

Build

# Compile everything (eBPF C program + Rust binaries)
make

# Or separately
make bpf            # produces ebpf/xdp_filter.o
cargo build --release

Both binaries land in target/release/:

  • sentinel-gate — the daemon (7.8 MB)
  • sentinel — the CLI (1.9 MB)

Usage

# Basic — SKB mode, all defaults
sudo sentinel-gate --interface eth0

# Native driver mode (faster, requires driver support)
sudo sentinel-gate --interface eth0 --mode native

# JSON telemetry to file, malicious traffic temporarily banned
sudo sentinel-gate \
  --interface eth0 \
  --log-format json \
  --log-file /var/log/sentinel-gate.jsonl \
  --response-malicious temp-ban \
  --ban-duration 600

# Pre-populate kernel-level IP blocklist
sudo sentinel-gate \
  --interface eth0 \
  --block-ip 198.51.100.1 \
  --block-ip 203.0.113.0/24

# Safe testing — dry-run response engine, debug logging
sudo sentinel-gate \
  --interface eth0 \
  --log-level debug \
  --response-dry-run

# Dashboard on a custom address/port
sudo sentinel-gate \
  --interface eth0 \
  --dashboard-bind 0.0.0.0 \
  --dashboard-port 8080

# Disable dashboard
sudo sentinel-gate --interface eth0 --dashboard-port 0

All flags

  -i, --interface <IFACE>           Network interface [default: eth0]
  -b, --bpf-object <PATH>           eBPF object file [default: ebpf/xdp_filter.o]
  -s, --signatures <PATH>           Signature rules [default: rules/signatures.json]
  -m, --mode <MODE>                 XDP mode: skb | native | hw [default: skb]
  -l, --log-level <LEVEL>           Trace level: trace|debug|info|warn|error [default: info]
      --log-format <FMT>            human | json [default: human]
      --log-file <PATH>             Write JSONL telemetry to file
      --log-rotate-mb <MB>          Rotate log at N MB [default: 100]
      --log-min-severity <SEV>      info|low|medium|high|critical [default: info]
      --block-ip <IP>               Pre-block source IP (repeatable)
      --poll-sleep-us <US>          Ring buffer poll interval µs [default: 500]
      --channel-capacity <N>        Collector→processor channel size [default: 4096]
      --stats-every <N>             Log stats every N packets [default: 100000]
      --flow-ttl <SECS>             Flow idle expiry [default: 60]
      --max-flows <N>               Max concurrent flows [default: 65536]
      --reap-interval <SECS>        Reaper tick interval [default: 10]
      --response-suspicious <ACT>   log-only|alert|block-flow|temp-ban|perm-ban [default: log-only]
      --response-malicious <ACT>    log-only|alert|block-flow|temp-ban|perm-ban [default: temp-ban]
      --ban-duration <SECS>         Temp ban duration [default: 600]
      --nft-table <NAME>            nftables table name [default: sentinel_gate]
      --response-dry-run            Log responses without executing nft
      --dashboard-port <PORT>       Dashboard port (0 = off) [default: 9090]
      --dashboard-bind <ADDR>       Dashboard bind address [default: 127.0.0.1]

Dashboard

Open http://127.0.0.1:9090 while the daemon is running.

![Dashboard layout: 2×2 grid — Traffic Map, Alerts, Top Talkers, Blocked IPs]

The dashboard uses a persistent WebSocket connection. The status pill in the top-right shows LIVE when connected and OFFLINE when the daemon is not reachable.

REST endpoints for scripting:

Endpoint Returns
GET /api/status Uptime, interface, packet/alert counts
GET /api/alerts Last 200 signature + anomaly alerts
GET /api/talkers Top 20 IPs by packet count
GET /api/blocked Active temporary bans with expiry

CLI

# All CLI commands (no sudo needed if socket is group-accessible)
sudo sentinel status
sudo sentinel stop
sudo sentinel rules reload
sudo sentinel interface attach --interface eth1 --mode native

# Daemon start via CLI (exec-replaces into sentinel-gate)
sudo sentinel start --interface eth0 --mode skb --response-dry-run

Signature Rules

Rules live in rules/signatures.json. The engine hot-reloads on sentinel rules reload — no restart required.

{
  "rules": [
    {
      "id": "SIG-001",
      "name": "Null Scan",
      "severity": "high",
      "verdict": "suspicious",
      "tags": ["scan", "stealth", "tcp"],
      "match": {
        "protocol": "tcp",
        "tcp_flags": { "all_zero": true }
      }
    },
    {
      "id": "SIG-016",
      "name": "Known C2 Beacon Pattern",
      "severity": "critical",
      "verdict": "malicious",
      "tags": ["c2", "beacon", "http"],
      "match": {
        "protocol": "tcp",
        "dst_port": [80, 443, 8080, 8443],
        "payload_contains": "POST /gate.php"
      }
    }
  ],
  "ip_reputation": {
    "malicious": ["198.51.100.0/24"],
    "scanner":   ["203.0.113.1"]
  }
}

Match fields: protocol, src_port, dst_port, src_cidr, dst_cidr, tcp_flags, payload_contains, port_category, ip_reputation, domain_contains, packet_size_min, packet_size_max

Architecture

sentinel-gate/
├── ebpf/
│   └── xdp_filter.c        # XDP eBPF program (C, compiles to BPF ELF)
├── rules/
│   └── signatures.json     # Detection rules
├── src/
│   ├── main.rs             # Entry point, CLI args, pipeline wiring
│   ├── collector.rs        # Ring buffer reader + processor/reaper tasks
│   ├── packet_parser.rs    # PacketMeta ABI struct + decode helpers
│   ├── flow_tracker.rs     # Per-flow state machine (DashMap)
│   ├── signature_engine.rs # JSON rule loader + match engine
│   ├── anomaly_engine.rs   # Scored heuristic model + beaconing detection
│   ├── response_engine.rs  # nftables enforcement + ban deduplication
│   ├── logger.rs           # Structured telemetry (human/JSON, file rotation)
│   ├── control.rs          # Unix socket IPC server + SharedStats
│   ├── dashboard.rs        # Axum HTTP + WebSocket dashboard backend
│   └── bin/
│       └── sentinel.rs     # CLI binary
├── static/
│   └── dashboard.html      # Single-file dashboard UI (embedded at build time)
├── build.rs                # Compiles eBPF C program via clang
├── Makefile
└── Cargo.toml

Async pipeline

main task (current_thread runtime)
│
├─ Collector::run()          polls ring buffer, sends PacketMeta via mpsc
│    └──────────────────────────────────────────────────────────────────┐
│                                                                        ↓
├─ processor_loop (spawned)  flow tracking → signature → anomaly → response
│
├─ reaper_loop (spawned)     TTL-expired flow eviction on a tick
│
├─ ControlServer (spawned)   Unix socket IPC — stop / status / reload
│
└─ DashboardServer (spawned) Axum HTTP + WebSocket live feed

RingBuf<&mut MapData> is not Send, so the collector runs inline in the main task. All other pipeline stages hold only Arc<T> values and are freely spawnable.

XDP Packet Validation

The eBPF program performs these checks in order before the packet reaches the kernel network stack:

Code Check Action
H1 Ethernet frame too short XDP_DROP (no ring buffer entry)
H2 IPv4 IHL < 5 XDP_DROP
H3 IP total length < IHL×4 XDP_DROP
S1 Kernel IP blocklist hit XDP_DROP + ring buffer
S2 Bogon / martian source XDP_DROP + ring buffer
S3 Land attack (src == dst) XDP_DROP + ring buffer
S4 Tiny first fragment XDP_DROP + ring buffer
S5 IP checksum mismatch XDP_PASS (suspicious)
S6 Non-first IP fragment XDP_PASS (suspicious)
S7 IP total length > wire length XDP_PASS (suspicious)
S8 TTL ≤ 1 XDP_PASS (suspicious)
S9 TCP data offset invalid XDP_DROP + ring buffer
S10 Impossible TCP flag combos XDP_DROP + ring buffer
S11 NULL / XMAS scan XDP_PASS (suspicious)
S12 UDP length < 8 XDP_DROP + ring buffer
S13 UDP length > IP payload XDP_PASS (suspicious)

Notes

  • WSL2: SKB mode (--mode skb) works. Native/HW modes require a driver with XDP support.
  • Permissions: sentinel-gate requires CAP_NET_ADMIN. The control socket at /run/sentinel-gate/control.sock is created as root; prefix sentinel subcommands with sudo or adjust socket permissions.
  • nftables: If nftables setup fails (missing binary, insufficient privileges), the response engine logs a warning and falls back to log-only for all firewall actions. Use --response-dry-run to test without touching firewall state.

License

GPL-2.0

sentinel-gate

About

Pre-host packet inspection system

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages