IDS / IPS
AiFw ships an intrusion detection engine that consumes three rule formats — Suricata-compatible, Sigma, and YARA (practical subsets, see below) — and runs in one of three modes: Disabled, IDS (alert-only), or IPS (reactive source blocking). Behavioural AI detectors live alongside the rule engine and are opt-in. No Snort, no separate package install, no second daemon to babysit.
What IPS mode does (and doesn’t do). Detection is passive (BPF capture). When a rule with a drop/reject verdict matches, the alert’s source IP is added to the
aifw-ids-blockpf table, so subsequent packets from that source are blocked — the triggering packet itself is not stopped, and a few more packets may pass before the table update takes effect. Blocking is per-source-address, not per-flow. True inline prevention (dropping the triggering packet) is on the roadmap via divert/netmap interception.
Quickstart
Open the Web UI and go to IDS → Settings. Pick a mode and an interface. Apply.
| Mode | Behaviour |
|---|---|
Disabled |
Engine off, no inspection |
IDS |
Inspect and log alerts; never block |
IPS |
Inspect, alert, and reactively block the offending source IP via the aifw-ids-block pf table (the triggering packet is not stopped) |
From the API:
curl -X PUT https://aifw.local/api/v1/ids/config \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mode": "ids",
"interfaces": ["em0"],
"home_net": ["10.0.0.0/8", "192.168.0.0/16"],
"external_net": ["!$HOME_NET"],
"alert_retention_days": 30,
"eve_log_enabled": true
}'
curl -X POST https://aifw.local/api/v1/ids/reload \
-H "Authorization: Bearer $TOKEN"
Deprecated: the per-IDS
syslog_targetfield is a no-op. Alert forwarding to a syslog server is configured globally at/api/v1/settings/syslog(enable the IDS alerts category), or in the UI under Settings → Remote Logging.
Rule formats
Rule-header variables. $HOME_NET and $EXTERNAL_NET expand to the home_net / external_net lists above (defaults: RFC 1918 and !$HOME_NET). The stock Suricata server groups ($HTTP_SERVERS, $DNS_SERVERS, $SMTP_SERVERS, $SQL_SERVERS, …) alias $HOME_NET, and port groups ($HTTP_PORTS, $SSH_PORTS, $SHELLCODE_PORTS, …) carry the suricata.yaml defaults. A rule that references an undefined variable never matches; the engine logs the variable name once so you can spot inert rules.
Suricata-compatible. The native format. AiFw parses Suricata 7.x syntax — alert, drop, pass, plus the common content, pcre, flow, threshold, and metadata keywords. This is a practical subset, not full Suricata engine parity: most ET Open-style rules drop in unchanged, but rules relying on unsupported keywords are skipped (visible in the ruleset parse stats).
Sigma. YAML detection rules originally designed for log events. AiFw maps the detection section to network flow fields, so a Sigma rule that targets HTTP request URIs or DNS query names will fire on matching traffic. Sigma rules always alert — they never drop, regardless of mode.
YARA. Byte-pattern rules used for malware signatures. Useful inside reassembled HTTP / SMTP / FTP payloads. Run alongside Suricata rules in the same engine pass.
ET Open integration
The seed ruleset is ET Open from Emerging Threats:
https://rules.emergingthreats.net/open/suricata-7.0/emerging-all.rules
Auto-update runs every 24 hours by default (configurable per ruleset via update_interval_hours). The engine fetches, parses, diffs against the live set, and reloads in place — no daemon restart. ET Open is shipped disabled-by-default; flip enabled on the ruleset to turn it on.
Add additional rulesets (Abuse.ch, ET Pro, custom feeds) via POST /api/v1/ids/rulesets. Each ruleset gets its own URL, format (suricata / sigma / yara), enable flag, and update cadence.
AI-assisted alert triage
With an LLM provider configured under Settings → AI, AiFw periodically reviews unreviewed critical/high alerts (POST /api/v1/ai/analyze triggers a pass by hand) and records a classification plus reasoning on the Threats page; every call is logged at GET /api/v1/ai/audit-log. Without a provider nothing is called and the Threats page is a plain alert view.
Behavioural ML detectors are not shipped. The
aifw-aicrate holds heuristic prototypes for port-scan, DDoS, brute-force, C2-beacon and DNS-tunnel detection, but it is not wired into the daemon or API — nothing on the appliance runs them and there is no setting that enables them (#171). Reactive blocking on the box today comes from IDS rules and rate limits, not from these detectors.
Alert management
Every match lands in the alerts table with severity, signature, source / destination, payload excerpt, and timestamp.
curl https://aifw.local/api/v1/ids/alerts?limit=50 \
-H "Authorization: Bearer $TOKEN"
curl -X PUT https://aifw.local/api/v1/ids/alerts/{id}/acknowledge \
-H "Authorization: Bearer $TOKEN"
curl -X PUT https://aifw.local/api/v1/ids/alerts/{id}/classify \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"classification": "false_positive", "notes": "internal scanner"}'
Acknowledged alerts stay in the timeline for audit but drop out of the unread counter. Classification (true_positive, false_positive, benign) feeds back into UI filters.
Suppressions
Suppress noisy rules without disabling them. Three scopes:
- By source IP — ignore matches originating from a given address.
- By destination IP — ignore matches to a given address.
- Per-rule — ignore a specific signature ID entirely.
curl -X POST https://aifw.local/api/v1/ids/suppressions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"rule_sid": 2008581, "src_ip": "10.0.5.42"}'
Suppressions are paginated: GET /api/v1/ids/suppressions?limit=50&offset=0.
API endpoints
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/ids/config |
Current engine config |
PUT |
/api/v1/ids/config |
Update mode, interfaces, networks, retention |
POST |
/api/v1/ids/reload |
Hot-reload rules without dropping flows |
GET |
/api/v1/ids/stats |
Engine counters, packets, drops, memory |
GET |
/api/v1/ids/alerts |
Paginated alert feed |
DELETE |
/api/v1/ids/alerts |
Purge alerts (filtered) |
GET |
/api/v1/ids/alerts/{id} |
One alert with full payload |
PUT |
/api/v1/ids/alerts/{id}/acknowledge |
Mark as read |
PUT |
/api/v1/ids/alerts/{id}/classify |
Set classification + notes |
GET |
/api/v1/ids/alerts/buffer-stats |
Live alert ring-buffer stats |
GET |
/api/v1/ids/rulesets |
List configured rulesets |
POST |
/api/v1/ids/rulesets |
Add a new ruleset URL |
PUT / DELETE |
/api/v1/ids/rulesets/{id} |
Update / remove a ruleset |
GET |
/api/v1/ids/rules |
List parsed rules |
GET |
/api/v1/ids/rules/search |
Full-text search rules |
GET / PUT |
/api/v1/ids/rules/{id} |
Inspect or override a single rule |
GET / POST |
/api/v1/ids/suppressions |
List / create suppressions |
DELETE |
/api/v1/ids/suppressions/{id} |
Drop a suppression |