Overview #
The Suri Oculus backend is a high-performance REST API implemented in C++ (C++17) using the Pistache framework.
It is responsible for:
Collecting and serving Suricata events from Redis
Managing Suricata rules and processes
Handling Indicators of Compromise (IoC) and generating IoC-based rules
Providing statistics and health information
Building a network map from Suricata telemetry
The backend is designed to run both on full servers and on resource-constrained devices (low-power CPUs, limited RAM).
Deployment and Service (EN) #
The backend can be launched in two ways:
Direct execution
Simply run the binary:oculus-server
As a systemd service
Installed as a systemd unit and controlled via:systemctl start oculus-server
systemctl stop oculus-server
systemctl status oculus-server
By default, the HTTP API listens on TCP port 8080 (configurable at build or packaging time).
Architecture and Pistache Integration #
The main backend component is the Server class, which wraps a Pistache::Http::Endpoint and a Pistache::Rest::Router:
Server::Server(Pistache::Address addr)— constructs the HTTP endpoint.Server::setupRoutes()— registers all REST routes.Server::run()— initializes the endpoint and starts the HTTP server.
Key Pistache aspects:
Router:
Pistache::Rest::Routesis used to bind URL paths and HTTP methods to handler functions.Endpoint:
httpEndpoint.init(Pistache::Http::Endpoint::options().threads(2));
The backend uses a small pool of worker threads (default: 2) and can be tuned depending on the hardware.Handlers: Most routes are static handler methods in classes:
Events— event retrieval, search, time-series metricsRules— Suricata rules, Suricata control, daemon managementThreats— IoC life-cycle and IoC-based rulesStats— performance stats and healthNet— network topology and historical network map
CORS and Preflight Requests #
The backend is designed to be consumed by browser-based clients hosted on a different origin (different port or host).
For this reason, it implements CORS handling and an explicit preflight handler:
void handlePreflightRequest(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response)
{
Rules::addCORSHeaders(response);
response.send(Pistache::Http::Code::Ok);
}
For all POST endpoints that are called from JavaScript, corresponding OPTIONS routes are registered, so that browsers can perform CORS preflight checks.
HTTP API Overview #
Below is a high-level overview of the available routes grouped by functional area.
All endpoints return JSON unless otherwise specified.
1. Events API #
Namespace: Events
Purpose: Access to Suricata events stored in Redis and basic analytics (counts and time series).
Core event operations
GET /events/:event_type
Get all events of a given type (e.g.alert,flow,dns,http,tls,ssh,ftp).GET /events/count/:event_type
Return the total number of events of a given type.GET /events/:event_type/:event_id
Retrieve a single event by its ID.GET /events/search/:flow_id
Find an event byflow_id(useful for cross-correlation).DELETE /events/delete/:event_type
Delete all events of the given type (dangerous, used for maintenance/cleanup).
CORS:OPTIONS /events/delete/:event_type.GET /events/find/:event_type
Search events of a given type using query parameters (time ranges, IPs, ports, etc.).GET /events/check/:event_type
Get events of a given type within a time window (timeshift in hours).
Used by the web client for time-based views.GET /events/fast
Stream or expose contents offast.log(Suricata’s fast log).
Aggregated views / dashboards
GET /events/alertsmap
Short view of recentalertevents, used for building compact dashboards and maps.GET /events/alertssignatures
Alerts aggregated by signature (top talkers, most frequent signatures).GET /events/alertsbyhours
Per-hour counts of alert events (alerttime series).GET /events/anomaliesbyhours
Per-hour counts of events marked as anomalies (from the AI/anomaly detection pipeline).GET /events/flowsbyhours
Per-hour counts offlowevents.GET /events/dnsbyhours
Per-hour counts ofdnsevents.GET /events/tlsbyhours
Per-hour counts oftlsevents.GET /events/httpbyhours
Per-hour counts ofhttpevents.GET /events/sshbyhours
Per-hour counts ofsshevents.GET /events/ftpbyhours
Per-hour counts offtpevents.
These time-series routes are used by the web client to build graphs “events per hour” across different categories.
2. Rules and Suricata Management #
Namespace: Rules
Purpose: Full life-cycle management of Suricata rules and control of Suricata/daemon processes.
Rule retrieval and search
GET /rules
Return all rules from the main Suricata rule set.GET /rules/:sid
Find a rule by itssid.GET /rules/action/:action
Filter rules by action (alert,drop,reject, …).GET /rules/status/:status
Filter rules by status (enabled/disabled).GET /rules/protocol/:proto
Filter rules by protocol (e.g.tcp,udp,icmp).GET /rules/search
Search rules by multiple parameters passed as query arguments.GET /rules/signature/:signature
Find rules by signature text (substring search).GET /rules/duplicated/:sid
Detect duplicate rules with the samesid.
Rule modification and validation
All modifying endpoints are POST + CORS OPTIONS:
POST /rules/toggle/
Toggle rule status (enable/disable).POST /rules/add/
Add a new rule to the configuration.POST /rules/validate/
Validate a rule (syntax and basic Suricata compatibility).POST /rules/delete/
Delete rule(s) from the rule set.POST /rules/update/
Apply batched updates to rules (bulk modifications).POST /validate_rule_endpoint
Alternative endpoint for rule validation (used by the web client).
Additional (local) rules
GET /rules/additional/status/
Return status and metadata for additional rules file (e.g.additional.rules).POST /rules/additional/update/
Update the additional rules file on disk (replace content, apply changes).
Suricata control
GET /suricata/reload/
Reload Suricata configuration and rules.GET /rules/reload/blocking
Reload rules in blocking mode (client waits until reload is complete).GET /rules/reload/nonblocking
Reload rules asynchronously (returns immediately while reload continues in the background).GET /suricata/start/
Start the Suricata process.GET /suricata/stop/
Stop the Suricata process.GET /suricata/update/
Update rule files and trigger Suricata reload.
Daemon control
GET /daemon/start/
Start auxiliary daemon (e.g. log mover, Redis feeder).GET /daemon/stop/
Stop the daemon.
3. Threats / IoC Management #
Namespace: Threats
Purpose: Manage Indicators of Compromise (IoCs), their statuses, and the corresponding rules.
IoC life-cycle
GET /ioc/download/
Download fresh IoC data from an upstream feed (e.g. ThreatFox).GET /ioc/filter/:n_days
Filter IoCs for the lastn_days.GET /ioc/
Return all IoCs present in the local store.GET /ioc/ioc_type/:ioc_type
Filter IoCs by type (IP, domain, URL, etc.).GET /ioc/ioc_id/:id
Get IoC by its internal ID.GET /ioc/ioc_status/:status
Filter IoCs by status (enabled, disabled, pending, etc.).POST /ioc/toggle/
Toggle IoC status.
IoC rules and export
GET /ioc/fetch/
Generate Suricata rule files from current IoCs (IP/domain/URL lists).GET /ioc/rules/status/
Return status of IoC rule files (present, size, timestamp).POST /ioc/rules/modify/
Modify the status of IoC rule files (enable/disable specific sets).
Supports CORS viaOPTIONS /ioc/rules/modify/.
4. Statistics and Health #
Namespace: Stats
Purpose: Monitoring of Suricata and host resource usage.
GET /stats/
General statistics snapshot.GET /stats/pkts/
Packet-related counters.GET /stats/alerts/
Alert counters and rates.GET /stats/cpu/
CPU usage statistics.GET /stats/vm/
Virtual memory statistics.GET /stats/pm/
Physical memory statistics.GET /stats/histogramm/
Histogram data (Latencies, packet sizes, etc.; used for charts in UI).GET /suricata/running/
Check Suricata process status (running or not).GET /stats/update/
Get last update time of statistics file or source (used for freshness checks).
5. Network Map #
Namespace: Net
Purpose: Build an overview of the network based on Suricata flow and alert data.
GET /net/map/
Return a current network map (hosts, connections, possibly roles).GET /net/historicalmap/
Return a historical network map over a longer time window.
These endpoints are typically consumed by the web client to render interactive network diagrams.
Configuration File (/etc/oculus/config++.conf) #
The backend configuration is stored in a custom config file (suricata-oriented) at:
/etc/oculus/config++.conf
The structure is divided into two main blocks: main and settings.
main section #
Basic metadata about the application:
application:
{
main:
{
title = "OCULUS SERVER";
version = "0.8.2";
date = "10 April 2024";
};
title– Application name (display and logging).version– Backend version.date– Build or release date.
settings section #
Operational parameters for Suricata integration, Redis, and IoC processing:
settings:
{
main_key = "suricata";
keys = ("alert", "flow", "http", "dns", "dhcp", "fileinfo", "stats", "tls");
valid_duration = 24;
redis_connect = "redis://127.0.0.1/";
rules_file = "/var/lib/suricata/rules/suricata.rules";
tmp_rule_file = "/home/fil/suricata_validate_rule.rules";
suricata_conf = "/etc/suricata/suricata.yaml";
additional_rules = "/var/lib/suricata/rules/additional.rules";
ioc_full_link = "https://threatfox-api.abuse.ch/export/json/full/";
ioc_full_file_path = "/var/lib/suricata";
ioc_full_file_name = "/var/lib/suricata/full.json";
ioc_local_file_name = "/var/lib/suricata/ioc.json";
ioc_domain_rules = "/var/lib/suricata/rules/ioc_domain.rules";
ioc_url_rules = "/var/lib/suricata/rules/ioc_url.rules";
ioc_ip_rules = "/var/lib/suricata/rules/ioc_ip.rules";
ioc_domains_lst = "/var/lib/suricata/ioc_domains.lst";
fast_file = "/var/log/suricata/fast.log";
};
};
Key parameters:
main_key/keys— Top-level Redis key namespace used by the backend to store and query Suricata events.
Events are usually grouped undersuricata:<key>(alert, flow, dns, …).valid_duration— Time window (in hours) for which cached data or temporary artefacts are considered valid.
Used in various time-based queries.redis_connect— Redis connection URL.
Default isredis://127.0.0.1/. Change it if Redis is remote or requires authentication.rules_file— Main Suricata rules file used by rule management routes.tmp_rule_file— Temporary file used for rule validation before merging into the main rule set.suricata_conf— Path tosuricata.yaml.additional_rules— File used for custom local rules (managed by/rules/additional/*endpoints).ioc_full_link— IoC feed URL (ThreatFox full JSON export).ioc_full_file_path,ioc_full_file_name,ioc_local_file_name— Paths for raw IoC data and processed IoC cache.ioc_*_rules— Paths to Suricata rule files generated from IoCs (domain, URL, IP).ioc_domains_lst— Auxiliary text file with domains extracted from IoCs.fast_file— Path tofast.log, used by/events/fast.
Any change in file locations or Redis settings must be reflected in this config file to keep the backend in sync with Suricata and IoC storage.
Web Client Configuration (config.js) #
Starting from recent versions of the web client, all backend access is centralized via config.js:
// config.js export const backendUrl = 'http://backend_ip:8080'; Guidelines:
Use
http://orhttps://depending on your deployment.If you run a reverse proxy (e.g.
https://suri-oculus.example.com/api/),
you can set:export const backendUrl = 'https://suri-oculus.example.com/api';The backend implements CORS, so web and backend can be on different ports or even different hosts.