Mantis/CLAUDE.md
ParrotXray 46a69dd49c
refactor/rename-mantis (#12)
* refactor: Rename project from NetGuardia to Mantis

* fix: convert mantis-frontend from tracked files to submodule

* wip

* feat: Suricata integration stabilization and config unification
Fix a series of bugs in the Suricata daemon integration and unify
configuration so users interact only with config.toml.

* docs: sur-001-c1 Suricata integration stabilization findings
2026-05-22 18:42:51 +08:00

5.0 KiB

Mantis

Network intrusion detection system combining eBPF packet capture with ML-based anomaly detection and Suricata/Snort rule matching.

Language Convention

  • Conversation: Always use Traditional Chinese (繁體中文)
  • Files, docs, comments, code: Always use English
  • This applies to ALL generated content without exception

Dependency Policy

  • ML inference: ort-tract (pure Rust, no native ORT binary) Do not switch to native ORT without explicit discussion.
  • Async runtime: tokio only, do not add async-std or smol.
  • Logging: macros::log! only, do not add log crate or use tracing:: directly.
  • Locking: std::sync::Mutex is preferred; parking_lot::Mutex where performance matters.
  • ort version is pinned to =2.0.0-rc.12, do not upgrade without checking ort-tract compatibility.

Workspace Structure

mantis/          - Main application (ML, eBPF userspace, HTTP API, WebSocket)
common/          - Shared types used by both userspace and eBPF programs
macros/          - Procedural macros: log!, traceable!, loggable!
ingress-ebpf/    - eBPF ingress packet capture program
egress-ebpf/     - eBPF egress packet capture program
mantis-frontend/ - Next.js web UI

Build

Full build requires eBPF toolchain and system libs (libelf, boost for vectorscan).

To type-check without eBPF (for ML/API changes):

SKIP_EBPF_BUILD=1 cargo check --package mantis

Ignore these expected errors when SKIP_EBPF_BUILD is set:

  • environment variable ARTIFACTCS_PATH not defined
  • environment variable CSV_RECORD_PATH not defined
  • environment variable RULES_DB_PATH not defined
  • couldn't read .../mantis-ingress
  • couldn't read .../mantis-egress

mantis Source Layout

src/
├── core/
│   ├── ebpf/          - XDP/AF_XDP packet capture, access control
│   └── infrastructure/- AppServices init, AppConfig, GeoIP, MLAlert
├── detection/
│   ├── ml/            - ML inference pipeline
│   │   ├── engine.rs          - inference loop (tokio interval)
│   │   ├── flow_tracker.rs    - per-flow packet aggregation
│   │   ├── feature_extractor.rs - flow -> feature vector
│   │   ├── inference.rs       - sliding window + autoencoder MSE
│   │   ├── model_loader.rs    - ort Session creation
│   │   ├── config_loader.rs   - inference_config.json
│   │   ├── aggregator.rs      - attack event dedup/aggregation
│   │   └── traffic_logger.rs  - CSV recording mode
│   └── rule/          - Suricata/Snort rule matching (vectorscan)
├── model/
│   ├── error/         - one file per domain (ml, ebpf, http, rule, ...)
│   ├── log/           - one file per domain (ml, ebpf, http, rule, ...)
│   └── ml_detection.rs- shared ML types (FlowKey, DetectionResult, ...)
├── web/               - actix-web HTTP API and WebSocket endpoints
└── utils/             - packet parsing, logging setup, boot time

Macros (always use these)

log!

Logs an error or loggable value. Routes to tracing level automatically.

use macros::log;
log!(MLError::ModelLoadFailed { path });
log!(MLLog::InferenceCompleted { total_flows, anomaly, benign, duration_ms, throughput });

traceable!

Defines an error enum in src/model/error/<domain>.rs.

traceable! {
    MLError {
        #[no_source]
        #[error("Failed to load ONNX model from: {path:?}")]
        ModelLoadFailed { path: PathBuf } => tracing::Level::ERROR,
    }
}

loggable!

Defines a log message enum in src/model/log/<domain>.rs.

loggable! {
    MLLog {
        #[error("ML artifacts loaded - {info}")]
        ModelsLoaded { info: String } => tracing::Level::INFO,
    }
}

Conventions

  • New error variant -> add to src/model/error/<domain>.rs using traceable!
  • New log message -> add to src/model/log/<domain>.rs using loggable!
  • Never use println!, eprintln!, or tracing:: directly — always use log!()
  • Shared data types (structs, enums used across modules) go in src/model/
  • Comments in English only, no special characters

ML Pipeline

Inference runs on a tokio interval (default 5s):

eBPF packet -> FlowTracker (per-flow stats)
                    -> FlowFeatures (extract + normalize ~80 features)
                         -> Inference (sliding window buffer per src_ip)
                              -> ort Session (LSTM autoencoder, MSE score)
                                   -> AttackAggregator -> MLAlert (WebSocket)

Inference engine: ort-tract (pure Rust, no native ORT binary required). ort::set_api(ort_tract::api()) must be called before any Session is created. Session is wrapped in Mutex<Session> because Session::run requires &mut self.

Config

Runtime config: config.toml ML artifacts: mantis/static/artifacts/

  • deep_autoencoder.onnx - LSTM autoencoder model
  • inference_config.json - window size, feature names, scaler params, threshold

Implementation Priority

See TODO for the full backlog.