]> git.ipfire.org Git - suricata-reporter.git/commitdiff
generator: Add a summary of high severity alerts
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 14 Sep 2025 12:02:14 +0000 (12:02 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 14 Sep 2025 12:04:48 +0000 (12:04 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
po/de_DE.po
po/suricata-reporter.pot
src/suricata-report-generator.in

index 3336042ef7ac1f9c25903e6642068b06db531fa1..19a27584c2811ee465264be46b42b5d485e39309 100644 (file)
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-09-14 11:15+0000\n"
+"POT-Creation-Date: 2025-09-14 12:03+0000\n"
 "PO-Revision-Date: 2025-08-31 15:08+0000\n"
 "Last-Translator: Michael Tremer <michael.tremer@ipfire.org>\n"
 "Language: \n"
@@ -26,12 +26,30 @@ msgstr "IPFire Einbruchsabwehrsystembericht"
 msgid "Generated %s"
 msgstr "Generiert %s"
 
-msgid "Time"
-msgstr "Zeit"
+msgid "%Y-%m-%d"
+msgstr "%d.%m.%Y"
+
+msgid "Alert Summary"
+msgstr "Alarmzusammenfassung"
+
+msgid "This is a summary of all alerts of High Severity."
+msgstr "Dies ist eine Zusammenfassung aller Alarme von höchstem Schweregrad."
 
 msgid "Signature"
 msgstr "Signatur"
 
+msgid "Total Hits"
+msgstr "Treffer"
+
+msgid "Activity"
+msgstr "Aktivität"
+
+msgid "No Alerts Have Been Reported"
+msgstr "Es wurden keine Alarme gemeldet"
+
+msgid "Time"
+msgstr "Zeit"
+
 msgid "Protocol"
 msgstr "Protokoll"
 
@@ -42,9 +60,6 @@ msgstr "Quelle / Ziel"
 msgid "Alerts from %s"
 msgstr "Alarme vom %s"
 
-msgid "No Alerts Have Been Reported"
-msgstr "Es wurden keine Alarme gemeldet"
-
 #, c-format
 msgid "[REPORT] Intrusion Prevention System Alerts from %s"
 msgstr "[BERICHT] Einbruchsabwehrsystemalarme von %s"
@@ -138,6 +153,3 @@ msgstr "Berichtservice für Suricata"
 
 msgid "Configuration File"
 msgstr "Konfigurationsdatei"
-
-#~ msgid "Generated on %(hostname)s on %(when)s."
-#~ msgstr "Erstellt auf %(hostname)s am $(when)s."
index e919f8c4f77eaca13c4be06680c8b0c06198c0c1..a8e3c1b653791044fbcb2baaf7d73559caad36d8 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-09-14 11:15+0000\n"
+"POT-Creation-Date: 2025-09-14 12:03+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -28,12 +28,30 @@ msgstr ""
 msgid "Generated %s"
 msgstr ""
 
-msgid "Time"
+msgid "%Y-%m-%d"
+msgstr ""
+
+msgid "Alert Summary"
+msgstr ""
+
+msgid "This is a summary of all alerts of High Severity."
 msgstr ""
 
 msgid "Signature"
 msgstr ""
 
+msgid "Total Hits"
+msgstr ""
+
+msgid "Activity"
+msgstr ""
+
+msgid "No Alerts Have Been Reported"
+msgstr ""
+
+msgid "Time"
+msgstr ""
+
 msgid "Protocol"
 msgstr ""
 
@@ -44,9 +62,6 @@ msgstr ""
 msgid "Alerts from %s"
 msgstr ""
 
-msgid "No Alerts Have Been Reported"
-msgstr ""
-
 #, c-format
 msgid "[REPORT] Intrusion Prevention System Alerts from %s"
 msgstr ""
index 8c985c0eb76383397383aa41a7554aa354bae6c7..3843fb789a7369c4031adff01efc49f1902ad9f4 100644 (file)
@@ -188,6 +188,9 @@ class ReportGenerator(object):
                # Create the title page
                self._make_titlepage(elements, date_start, date_end)
 
+               # Add severity summary
+               self._make_severity_summary(elements, date_start, date_end, width=doc.width)
+
                # Add detailed alerts
                self._make_alerts(elements, date_start, date_end, width=doc.width)
 
@@ -266,6 +269,198 @@ class ReportGenerator(object):
                        reportlab.platypus.PageBreak(),
                )
 
+       def _make_severity_summary(self, elements, date_start, date_end, *, width):
+               """
+                       Creates a little overview with what kind of alerts have been raised
+               """
+               date_format = _("%Y-%m-%d")
+
+               # Add a headline
+               elements.append(
+                       reportlab.platypus.Paragraph(_("Alert Summary"), self.styles["Heading2"])
+               )
+
+               # Explain what this table is showing
+               elements.append(
+                       reportlab.platypus.Paragraph(
+                               _("This is a summary of all alerts of High Severity."),
+                               self.styles["Normal"],
+                       ),
+               )
+
+               # Add some extra space
+               elements.append(
+                       reportlab.platypus.Spacer(1, 1 * cm),
+               )
+
+               # Style the table
+               style = reportlab.platypus.TableStyle((
+                       # Make the grid slightly grey
+                       ("GRID", (0, 0), (-1, -1), 0.25, reportlab.lib.colors.grey),
+
+                       # Align all content to the top left corners of the cells
+                       ("ALIGN", (0, 0), (-1, -1), "LEFT"),
+                       ("ALIGN", (1, 0), (1, -1), "CENTER"),
+                       ("ALIGN", (2, 0), (2, -1), "RIGHT"),
+                       ("VALIGN", (0, 0), (-1, -1), "TOP"),
+
+                       # Chose a much smaller font size
+                       ("FONTSIZE", (0, 0), (-1, -1), 8),
+
+                       # Alternate the background colours of the rows
+                       ("ROWBACKGROUNDS", (0, 1), (-1, -1), [
+                               reportlab.lib.colors.white,
+                               reportlab.lib.colors.lightgrey,
+                       ]),
+               ))
+
+               # Fetch the alerts
+               c = self.db.execute("""
+                       SELECT
+                               (event ->> '$.alert.category') AS alert_category,
+                               (event ->> '$.alert.signature') AS alert_signature,
+                               (event ->> '$.alert.signature_id') AS alert_signature_id,
+                               (event ->> '$.alert.severity') AS alert_severity,
+                               (event ->> '$.alert.action') AS alert_action,
+                               (event ->> '$.alert.gid') AS alert_gid,
+                               (event ->> '$.alert.rev') AS alert_rev,
+
+                               -- Count the total number of hits
+                               COUNT(*) AS hits,
+
+                               -- Search for the first and last hit in the interval
+                               datetime(MIN(timestamp), 'unixepoch', 'localtime') AS first_hit_at,
+                               datetime(MAX(timestamp), 'unixepoch', 'localtime') AS last_hit_at
+                       FROM
+                               alerts
+                       WHERE
+                               date(timestamp, 'unixepoch', 'localtime') >= ?
+                       AND
+                               date(timestamp, 'unixepoch', 'localtime') <= ?
+                       AND
+                               alert_severity = 1
+                       GROUP BY
+                               alert_category,
+                               alert_signature,
+                               alert_signature_id,
+                               alert_severity,
+                               alert_gid,
+                               alert_rev
+
+                       ORDER BY
+                               hits DESC,
+                               alert_signature_id DESC,
+                               alert_gid DESC,
+                               alert_rev DESC
+               """, (date_start.isoformat(), date_end.isoformat()))
+
+               # Start the table with the header
+               rows = [
+                       ("", _("Signature"), _("Total Hits")),
+               ]
+
+               # Count the number of rows
+               i = 0
+
+               while True:
+                       row = c.fetchone()
+                       if row is None:
+                               break
+
+                       # Increment the row number
+                       i += 1
+
+                       # Parse timestamps
+                       first_hit_at = datetime.datetime.strptime(
+                               row.first_hit_at, "%Y-%m-%d %H:%M:%S",
+                       )
+                       last_hit_at = datetime.datetime.strptime(
+                               row.last_hit_at, "%Y-%m-%d %H:%M:%S",
+                       )
+
+                       # Give some visual indication about the severity
+                       # High Severity
+                       if row.alert_severity == 1:
+                               color = reportlab.lib.colors.crimson
+                       # Medium Severity
+                       elif row.alert_severity == 2:
+                               color = reportlab.lib.colors.gold
+                       # Low Severity
+                       elif row.alert_severity == 3:
+                               color = reportlab.lib.colors.dodgerblue
+                       # Informational
+                       elif row.alert_severity == 4:
+                               color = reportlab.lib.colors.lightsteelblue
+                       else:
+                               color = None
+
+                       # Set the severity colour
+                       if color:
+                               style.add("BACKGROUND", (0, i), (0, i), color)
+
+                       # Append the row
+                       rows.append((
+                               # Severity
+                               "",
+
+                               # Signature
+                               reportlab.platypus.Paragraph(
+                                       "%s<br />[%s:%s:%s] - %s<br />%s: %s - %s" % (
+                                               row.alert_signature,
+                                               row.alert_gid,
+                                               row.alert_signature_id,
+                                               row.alert_rev,
+                                               row.alert_category,
+                                               _("Activity"),
+                                               first_hit_at.strftime(date_format),
+                                               last_hit_at.strftime(date_format),
+                                       ),
+                                       self.styles["Small"],
+                               ),
+
+                               # Hits
+                               "%s" % row.hits,
+                       ))
+
+               # Show a note if there have been no alerts
+               if not i:
+                       elements.append(
+                               reportlab.platypus.Paragraph(
+                                       _("No Alerts Have Been Reported"),
+                                       self.styles["Note"],
+                               ),
+                       )
+
+                       # End the page
+                       elements.append(
+                               reportlab.platypus.PageBreak(),
+                       )
+
+                       # Done
+                       return
+
+               # Create the table
+               table = reportlab.platypus.Table(rows,
+                       # Set the widths of the rows
+                       colWidths=(
+                               width * 0.02, width * 0.8, width * 0.18,
+                       ),
+
+                       # Repeat the header after a page break
+                       repeatRows=1,
+               )
+
+               # Style the table
+               table.setStyle(style)
+
+               # Append the table to the output
+               elements.append(table)
+
+               # End the page
+               elements.append(
+                       reportlab.platypus.PageBreak(),
+               )
+
        def _make_alerts(self, elements, date_start, date_end, **kwargs):
                """
                        Called to add all alerts in the date range with all their detail.