From 6f1421944508cb371f07ca2ec6f08642c1905e04 Mon Sep 17 00:00:00 2001 From: scriptos Date: Tue, 24 Mar 2026 10:50:58 +0100 Subject: [PATCH] =?UTF-8?q?Report:=20Aktivster=20Tag=20=C3=BCber=20konfigu?= =?UTF-8?q?rierbaren=20Zeitraum=20statt=20Berichtsperiode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adguard-shield.conf | 6 ++++++ docs/konfiguration.md | 1 + docs/report.md | 6 ++++-- report-generator.sh | 42 ++++++++++++++++++++++++++++++++++++------ templates/report.html | 2 +- templates/report.txt | 2 +- 6 files changed, 49 insertions(+), 10 deletions(-) diff --git a/adguard-shield.conf b/adguard-shield.conf index e52eef5..bafb553 100644 --- a/adguard-shield.conf +++ b/adguard-shield.conf @@ -128,6 +128,12 @@ REPORT_FORMAT="html" # Mail-Befehl (z.B. "msmtp", "sendmail", "mail") REPORT_MAIL_CMD="msmtp" +# Zeitraum für "Aktivster Tag" im Report (in Tagen) +# Bestimmt, über wie viele Tage zurück der aktivste Tag ermittelt wird. +# 30 = Aktivster Tag der letzten 30 Tage (empfohlen) +# 0 = Nur innerhalb des Berichtszeitraums (altes Verhalten) +REPORT_BUSIEST_DAY_RANGE=30 + # --- Externe Blocklist (optional) --- # Aktiviert den externen Blocklist-Worker EXTERNAL_BLOCKLIST_ENABLED=false diff --git a/docs/konfiguration.md b/docs/konfiguration.md index bb30466..9dc41bd 100644 --- a/docs/konfiguration.md +++ b/docs/konfiguration.md @@ -139,6 +139,7 @@ Regelmäßige Statistik-Reports per E-Mail. Voraussetzung ist ein funktionierend | `REPORT_EMAIL_FROM` | `adguard-shield@hostname` | E-Mail-Absender | | `REPORT_FORMAT` | `html` | Format: `html` oder `txt` | | `REPORT_MAIL_CMD` | `msmtp` | Mail-Befehl (`msmtp`, `sendmail`, `mail`) | +| `REPORT_BUSIEST_DAY_RANGE` | `30` | Zeitraum in Tagen für „Aktivster Tag“. `30` = letzte 30 Tage. `0` = nur Berichtszeitraum (altes Verhalten) | > Siehe [E-Mail Report Dokumentation](report.md) für Details zu Inhalten, Templates und Befehlen. diff --git a/docs/report.md b/docs/report.md index 6a65c3d..79e3cc0 100644 --- a/docs/report.md +++ b/docs/report.md @@ -42,6 +42,7 @@ sudo /opt/adguard-shield/report-generator.sh install | `REPORT_EMAIL_FROM` | `adguard-shield@hostname` | E-Mail-Absender | | `REPORT_FORMAT` | `html` | Format: `html` oder `txt` | | `REPORT_MAIL_CMD` | `msmtp` | Mail-Befehl (`msmtp`, `sendmail`, `mail`) | +| `REPORT_BUSIEST_DAY_RANGE` | `30` | Zeitraum in Tagen für „Aktivster Tag“ (0 = Berichtszeitraum) | ### Versandintervalle @@ -86,7 +87,7 @@ Die übrigen Zeiträume laufen vom Starttag 00:00 Uhr bis zum Zeitpunkt der Repo - Rate-Limit Sperren - Subdomain-Flood Sperren - Externe Blocklist Sperren -- Aktivster Tag im Berichtszeitraum +- Aktivster Tag – wird über einen konfigurierbaren Zeitraum ermittelt (Standard: letzte 30 Tage, `REPORT_BUSIEST_DAY_RANGE`). Zeigt zusätzlich die Anzahl der Sperren an diesem Tag. Bei `REPORT_BUSIEST_DAY_RANGE=0` wird nur der Berichtszeitraum betrachtet. ### Top 10 Listen - **Auffälligste IPs** — Die 10 IPs mit den meisten Sperren (mit Balkendiagramm im HTML-Format) @@ -175,7 +176,8 @@ Die Templates verwenden Platzhalter (z.B. `{{TOTAL_BANS}}`, `{{TOP10_IPS_TABLE}} | `{{RATELIMIT_BANS}}` | Rate-Limit Sperren | | `{{SUBDOMAIN_FLOOD_BANS}}` | Subdomain-Flood Sperren | | `{{EXTERNAL_BLOCKLIST_BANS}}` | Externe Blocklist Sperren | -| `{{BUSIEST_DAY}}` | Aktivster Tag | +| `{{BUSIEST_DAY}}` | Aktivster Tag (Datum + Anzahl Sperren) | +| `{{BUSIEST_DAY_LABEL}}` | Dynamisches Label für den aktivsten Tag (z.B. „Aktivster Tag (30 Tage)“) | | `{{TOP10_IPS_TABLE}}` | Top 10 IPs (HTML-Tabelle) | | `{{TOP10_IPS_TEXT}}` | Top 10 IPs (Text-Tabelle) | | `{{TOP10_DOMAINS_TABLE}}` | Top 10 Domains (HTML-Tabelle) | diff --git a/report-generator.sh b/report-generator.sh index 976d751..5fdb8e2 100644 --- a/report-generator.sh +++ b/report-generator.sh @@ -41,6 +41,7 @@ REPORT_EMAIL_TO="${REPORT_EMAIL_TO:-}" REPORT_EMAIL_FROM="${REPORT_EMAIL_FROM:-adguard-shield@$(hostname -f 2>/dev/null || hostname)}" REPORT_FORMAT="${REPORT_FORMAT:-html}" REPORT_MAIL_CMD="${REPORT_MAIL_CMD:-msmtp}" +REPORT_BUSIEST_DAY_RANGE="${REPORT_BUSIEST_DAY_RANGE:-30}" BAN_HISTORY_FILE="${BAN_HISTORY_FILE:-/var/log/adguard-shield-bans.log}" BAN_HISTORY_RETENTION_DAYS="${BAN_HISTORY_RETENTION_DAYS:-0}" STATE_DIR="${STATE_DIR:-/var/lib/adguard-shield}" @@ -325,6 +326,7 @@ calculate_stats() { SUBDOMAIN_FLOOD_BANS=0 EXTERNAL_BLOCKLIST_BANS=0 BUSIEST_DAY="–" + BUSIEST_DAY_LABEL="Aktivster Tag" TOP10_IPS="" TOP10_DOMAINS="" PROTOCOL_STATS="" @@ -333,16 +335,24 @@ calculate_stats() { fi # Einen einzigen awk-Pass über den Cache: alle Statistiken auf einmal + # Busiest-Day-Bereich berechnen (konfigurierbar, Standard: 30 Tage) + local busiest_start_epoch + if [[ "$REPORT_BUSIEST_DAY_RANGE" == "0" || -z "$REPORT_BUSIEST_DAY_RANGE" ]]; then + busiest_start_epoch="$start_epoch" + else + local today_midnight + today_midnight=$(get_today_midnight) + busiest_start_epoch=$((today_midnight - REPORT_BUSIEST_DAY_RANGE * 86400)) + fi + local awk_result - awk_result=$(echo "$HISTORY_CACHE" | awk -F'|' -v s="$start_epoch" -v e="$end_epoch" ' + awk_result=$(echo "$HISTORY_CACHE" | awk -F'|' -v s="$start_epoch" -v e="$end_epoch" -v bs="$busiest_start_epoch" ' $1 >= s && $1 <= e { action = $3 if (action == "BAN") { bans++ ip_count[$4]++ ip_seen[$4] = 1 - day = substr($2, 1, 10) - day_count[day]++ dom = $5 if (dom != "" && dom != "-") dom_count[dom]++ proto = $8 @@ -359,11 +369,16 @@ calculate_stats() { unbans++ } } + # Aktivster Tag: separater Zeitraum (konfigurierbar, z.B. letzte 30 Tage) + $1 >= bs && $1 <= e && $3 == "BAN" { + bday = substr($2, 1, 10) + bday_count[bday]++ + } END { for (ip in ip_seen) unique++ busiest = ""; max_d = 0 - for (d in day_count) { - if (day_count[d] > max_d) { max_d = day_count[d]; busiest = d } + for (d in bday_count) { + if (bday_count[d] > max_d) { max_d = bday_count[d]; busiest = d; busiest_cnt = bday_count[d] } } print "BANS=" (bans+0) print "UNBANS=" (unbans+0) @@ -373,6 +388,7 @@ calculate_stats() { print "SF=" (sf+0) print "EB=" (eb+0) print "BUSIEST=" busiest + print "BUSIEST_CNT=" (busiest_cnt+0) for (ip in ip_count) print "IP\t" ip_count[ip] "\t" ip for (d in dom_count) print "DOMAIN\t" dom_count[d] "\t" d for (p in proto_count) print "PROTO\t" proto_count[p] "\t" p @@ -395,12 +411,23 @@ calculate_stats() { local busiest_raw busiest_raw=$(echo "$awk_result" | awk -F= '$1=="BUSIEST" {print $2; exit}') + local busiest_cnt + busiest_cnt=$(echo "$awk_result" | awk -F= '$1=="BUSIEST_CNT" {print $2; exit}') if [[ -n "$busiest_raw" ]]; then - BUSIEST_DAY=$(date -d "$busiest_raw" '+%d.%m.%Y' 2>/dev/null || echo "$busiest_raw") + local busiest_formatted + busiest_formatted=$(date -d "$busiest_raw" '+%d.%m.%Y' 2>/dev/null || echo "$busiest_raw") + BUSIEST_DAY="${busiest_formatted} (${busiest_cnt})" else BUSIEST_DAY="–" fi + # Dynamisches Label für den aktivsten Tag + if [[ "$REPORT_BUSIEST_DAY_RANGE" == "0" || -z "$REPORT_BUSIEST_DAY_RANGE" ]]; then + BUSIEST_DAY_LABEL="Aktivster Tag" + else + BUSIEST_DAY_LABEL="Aktivster Tag (${REPORT_BUSIEST_DAY_RANGE} Tage)" + fi + # Top-Listen: Tab-getrennte Felder sortieren und in das erwartete Format bringen TOP10_IPS=$( echo "$awk_result" | awk -F'\t' '$1=="IP" {print $2 " " $3}' | sort -rn | head -10) TOP10_DOMAINS=$(echo "$awk_result" | awk -F'\t' '$1=="DOMAIN" {print $2 " " $3}' | sort -rn | head -10) @@ -786,6 +813,7 @@ generate_report() { report="${report//\{\{SUBDOMAIN_FLOOD_BANS\}\}/$SUBDOMAIN_FLOOD_BANS}" report="${report//\{\{EXTERNAL_BLOCKLIST_BANS\}\}/$EXTERNAL_BLOCKLIST_BANS}" report="${report//\{\{BUSIEST_DAY\}\}/$BUSIEST_DAY}" + report="${report//\{\{BUSIEST_DAY_LABEL\}\}/$BUSIEST_DAY_LABEL}" report="${report//\{\{TOP10_IPS_TABLE\}\}/$top10_ips_table}" report="${report//\{\{TOP10_DOMAINS_TABLE\}\}/$top10_domains_table}" report="${report//\{\{PROTOCOL_TABLE\}\}/$protocol_table}" @@ -832,6 +860,7 @@ generate_report() { report="${report//\{\{SUBDOMAIN_FLOOD_BANS\}\}/$SUBDOMAIN_FLOOD_BANS}" report="${report//\{\{EXTERNAL_BLOCKLIST_BANS\}\}/$EXTERNAL_BLOCKLIST_BANS}" report="${report//\{\{BUSIEST_DAY\}\}/$BUSIEST_DAY}" + report="${report//\{\{BUSIEST_DAY_LABEL\}\}/$BUSIEST_DAY_LABEL}" report="${report//\{\{TOP10_IPS_TEXT\}\}/$top10_ips_txt}" report="${report//\{\{TOP10_DOMAINS_TEXT\}\}/$top10_domains_txt}" report="${report//\{\{PROTOCOL_TEXT\}\}/$protocol_txt}" @@ -983,6 +1012,7 @@ show_cron_status() { echo " Empfänger: ${REPORT_EMAIL_TO:-nicht konfiguriert}" echo " Absender: ${REPORT_EMAIL_FROM}" echo " Mail-Befehl: ${REPORT_MAIL_CMD}" + echo " Aktivster Tag: letzte ${REPORT_BUSIEST_DAY_RANGE:-30} Tage" echo "" if command -v "$REPORT_MAIL_CMD" &>/dev/null; then diff --git a/templates/report.html b/templates/report.html index ed6d087..0142883 100644 --- a/templates/report.html +++ b/templates/report.html @@ -324,7 +324,7 @@
{{BUSIEST_DAY}}
-
Aktivster Tag
+
{{BUSIEST_DAY_LABEL}}
diff --git a/templates/report.txt b/templates/report.txt index 6bb3bfb..4b39b7e 100644 --- a/templates/report.txt +++ b/templates/report.txt @@ -30,7 +30,7 @@ Rate-Limit Sperren: {{RATELIMIT_BANS}} Subdomain-Flood Sperren: {{SUBDOMAIN_FLOOD_BANS}} Externe Blocklist: {{EXTERNAL_BLOCKLIST_BANS}} - Aktivster Tag: {{BUSIEST_DAY}} + {{BUSIEST_DAY_LABEL}}: {{BUSIEST_DAY}} ─────────────────────────────────────────────────────────────── 🏴‍☠️ TOP 10 – AUFFÄLLIGSTE IPs