]> git.ipfire.org Git - ipfire-2.x.git/commitdiff
suricata-reporter: Log any alerts to a database
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 6 Aug 2025 15:58:21 +0000 (16:58 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 3 Sep 2025 17:42:00 +0000 (18:42 +0100)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
config/suricata/suricata-reporter

index cea8ae98706217e5da099865aa991d418e212ab2..6b35e4c2a25cbb5b0ea22e689780eb9b3b364f32 100644 (file)
@@ -35,6 +35,7 @@ import pwd
 import queue
 import signal
 import socket
+import sqlite3
 import subprocess
 import sys
 
@@ -211,6 +212,9 @@ class Worker(multiprocessing.Process):
                # Store the reporter
                self.reporter = reporter
 
+               # Open the database
+               self.db = self._open_database()
+
        @property
        def config(self):
                """
@@ -218,6 +222,39 @@ class Worker(multiprocessing.Process):
                """
                return self.reporter.config
 
+       def _open_database(self):
+               """
+                       Opens the database
+               """
+               # Fetch the path
+               path = self.config.get("DEFAULT", "database",
+                       fallback="/var/log/suricata/reporter.db")
+
+               # Open the database
+               db = sqlite3.connect(path)
+
+               # Enable the write-ahead-log
+               db.execute("PRAGMA journal_mode = WAL")
+
+               # Create the schema
+               db.executescript("""
+                       -- Create the main table
+                       CREATE TABLE IF NOT EXISTS alerts (
+                               id INTEGER PRIMARY KEY,
+
+                               -- Store the timestamp
+                               timestamp INTEGER NOT NULL,
+
+                               -- Store the entire JSON object
+                               event JSONB NOT NULL
+                       );
+
+                       -- Index alerts by their timestamp
+                       CREATE INDEX IF NOT EXISTS alerts_timestamp ON alerts(timestamp);
+               """)
+
+               return db
+
        def run(self):
                """
                        This is the main entry point for workers...
@@ -252,6 +289,12 @@ class Worker(multiprocessing.Process):
                        # Process the event
                        self.process(event)
 
+               # Optimize the database before exiting
+               log.debug("Optimizing the database")
+
+               self.db.execute("PRAGMA optimize")
+               self.db.execute("PRAGMA wal_checkpoint = TRUNCATE")
+
                log.debug("Worker %s terminated" % self.pid)
 
        def process(self, event):
@@ -272,6 +315,11 @@ class Worker(multiprocessing.Process):
                # Log the event
                log.debug("Received alert: %s" % event)
 
+               # Write the event to the database
+               self.db.execute("INSERT INTO alerts(timestamp, event) VALUES(?, ?)",
+                       (event.timestamp.timestamp(), event.json))
+               self.db.commit()
+
                # Send to syslog
                if self.config.getboolean("syslog", "enabled", fallback=False):
                        self.send_to_syslog(event)
@@ -387,6 +435,13 @@ class Event(object):
        def __str__(self):
                return "%s" % self.data
 
+       @property
+       def json(self):
+               """
+                       Returns all the data serialised as JSON
+               """
+               return json.dumps(self.data)
+
        @property
        def type(self):
                return self.data.get("event_type")