Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16b2c5950e | ||
|
|
b93689bbaf | ||
| e555db8092 | |||
| b04b8bf87d | |||
| 6b6a77a98c | |||
| ac21922178 | |||
| edd8cd4806 | |||
| 44936e9f20 | |||
| 440694925e | |||
| c97e327f0d | |||
| 12745c3fef | |||
| c2d6f872f5 | |||
| ccdc555246 | |||
| 633331748f | |||
| 2559ed89ea | |||
| df8b18ae08 | |||
| 6f9f7eba8e | |||
| a132b2a0f1 | |||
| 70818698d1 | |||
| 0264e1e896 | |||
| df15a587ee | |||
| 3d60771a1b | |||
| 4d7e053ce7 | |||
| 23deae7d81 | |||
| 0602fbb596 | |||
| a27c093d83 | |||
| cfd6fa9b70 |
229
README.md
229
README.md
@@ -1,153 +1,168 @@
|
||||
```
|
||||
▄▄▄ ▓█████▄ ▄████ █ ██ ▄▄▄ ██▀███ ▓█████▄ ██████ ██░ ██ ██▓▓█████ ██▓ ▓█████▄
|
||||
▒████▄ ▒██▀ ██▌ ██▒ ▀█▒ ██ ▓██▒▒████▄ ▓██ ▒ ██▒▒██▀ ██▌ ▒██ ▒ ▓██░ ██▒▓██▒▓█ ▀ ▓██▒ ▒██▀ ██▌
|
||||
▒██ ▀█▄ ░██ █▌▒██░▄▄▄░▓██ ▒██░▒██ ▀█▄ ▓██ ░▄█ ▒░██ █▌ ░ ▓██▄ ▒██▀▀██░▒██▒▒███ ▒██░ ░██ █▌
|
||||
░██▄▄▄▄██ ░▓█▄ ▌░▓█ ██▓▓▓█ ░██░░██▄▄▄▄██ ▒██▀▀█▄ ░▓█▄ ▌ ▒ ██▒░▓█ ░██ ░██░▒▓█ ▄ ▒██░ ░▓█▄ ▌
|
||||
▓█ ▓██▒░▒████▓ ░▒▓███▀▒▒▒█████▓ ▓█ ▓██▒░██▓ ▒██▒░▒████▓ ▒██████▒▒░▓█▒░██▓░██░░▒████▒░██████▒░▒████▓
|
||||
▒▒ ▓▒█░ ▒▒▓ ▒ ░▒ ▒ ░▒▓▒ ▒ ▒ ▒▒ ▓▒█░░ ▒▓ ░▒▓░ ▒▒▓ ▒ ▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒░▓ ░░ ▒░ ░░ ▒░▓ ░ ▒▒▓ ▒
|
||||
▒ ▒▒ ░ ░ ▒ ▒ ░ ░ ░░▒░ ░ ░ ▒ ▒▒ ░ ░▒ ░ ▒░ ░ ▒ ▒ ░ ░▒ ░ ░ ▒ ░▒░ ░ ▒ ░ ░ ░ ░░ ░ ▒ ░ ░ ▒ ▒
|
||||
░ ▒ ░ ░ ░ ░ ░ ░ ░░░ ░ ░ ░ ▒ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░ ░ ░ ░ ░
|
||||
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
|
||||
░ ░ ░
|
||||
```
|
||||
<p align="center">
|
||||
<a href="https://techniverse.net">
|
||||
<img src="https://assets.techniverse.net/f1/git/graphics/repo-techniverse-logo.png" alt="Techniverse Community" height="70" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
# AdGuard Shield
|
||||
<h1 align="center">AdGuard Shield</h1>
|
||||
|
||||
Automatischer Schutz für deinen AdGuard Home DNS-Server gegen übermäßige Anfragen einzelner Clients. Überwacht die AdGuard Home API, erkennt Rate-Limit-Verstöße und sperrt missbrauchende Clients per iptables — für alle DNS-Protokolle (DNS, DoH, DoT, DoQ).
|
||||
<h4 align="center">
|
||||
Automatischer Schutz für AdGuard Home: erkennt auffällige DNS-Clients, sperrt sie per Firewall und hebt temporäre Sperren selbstständig wieder auf.
|
||||
</h4>
|
||||
|
||||
## Was macht das Tool?
|
||||
<h6 align="center">
|
||||
<a href="https://www.cleveradmin.de">🏰 Website</a>
|
||||
·
|
||||
<a href="https://techniverse.net">📰 Community</a>
|
||||
·
|
||||
<a href="https://social.techniverse.net/@donnerwolke">🐘 Mastodon</a>
|
||||
·
|
||||
<a href="https://matrix.to/#/#support:techniverse.net">💬 Support</a>
|
||||
</h6>
|
||||
<br><br>
|
||||
|
||||
Wenn ein Client eine bestimmte Domain zu oft anfragt (z.B. >30x pro Minute), wird er automatisch auf Firewall-Ebene für alle DNS-Ports gesperrt. Nach einer konfigurierbaren Zeitspanne wird die Sperre automatisch aufgehoben.
|
||||
|
||||
## Features
|
||||
## ✨ Was ist AdGuard Shield?
|
||||
|
||||
- Automatische Erkennung und Sperre bei Rate-Limit-Verstößen
|
||||
- **Subdomain-Flood-Erkennung** — erkennt Random-Subdomain-Attacken (z.B. `abc123.microsoft.com`, `xyz456.microsoft.com`, ...)
|
||||
- **Progressive Sperren (Recidive)** — Wiederholungstäter werden stufenweise länger gesperrt (wie bei fail2ban), mit automatischem Cleanup abgelaufener Zähler
|
||||
- Unterstützt **alle DNS-Protokolle**: DNS (53), DoH (443), DoT (853), DoQ (784/853/8853)
|
||||
- **IPv4 + IPv6**
|
||||
- Eigene iptables Chain — greift nicht in bestehende Regeln ein
|
||||
- Automatisches Entsperren nach konfigurierbarer Dauer
|
||||
- **Externe Blocklisten** — IP-Adressen von externen Textdateien (URLs) laden und automatisch sperren
|
||||
- **Externe Whitelisten** — Domains/IPs aus externen Listen laden und automatisch whitelisten (ideal für DynDNS)
|
||||
- **GeoIP-Länderfilter** — Länder sperren oder erlauben (Blocklist/Allowlist), mit automatischem MaxMind-DB-Download
|
||||
- **AbuseIPDB Reporting** — permanent gesperrte IPs automatisch an AbuseIPDB melden
|
||||
- **E-Mail Reports** — periodische Statistik-Reports als HTML oder TXT (täglich, wöchentlich, zweiwöchentlich, monatlich)
|
||||
- **Ban-History** — lückenlose Protokollierung aller Sperren/Entsperrungen mit Zeitstempel
|
||||
- Whitelist für vertrauenswürdige IPs
|
||||
- Dry-Run Modus zum gefahrlosen Testen
|
||||
- Benachrichtigungen (Discord, Slack, Gotify, Ntfy)
|
||||
- **Watchdog** — automatischer Health Check alle 5 Minuten mit Recovery und Benachrichtigung bei Service-Ausfall
|
||||
- systemd Service für dauerhaften Betrieb
|
||||
AdGuard Shield überwacht das Query Log deiner AdGuard-Home-Instanz und erkennt Clients, die eine Domain oder viele zufällige Subdomains in kurzer Zeit übermäßig oft anfragen. Auffällige Clients werden über eine eigene `iptables`/`ip6tables`-Chain auf DNS-relevanten Ports blockiert.
|
||||
|
||||
## Voraussetzungen
|
||||
Das schützt klassische DNS-Anfragen genauso wie DoH, DoT und DoQ, ohne deine bestehenden Firewall-Regeln unnötig anzufassen.
|
||||
|
||||
- Linux Server mit AdGuard Home (bare metal)
|
||||
- Root-Zugriff (`sudo`)
|
||||
- AdGuard Home Web-API erreichbar (Standard: Port 3000)
|
||||
- Pakete: `curl`, `jq`, `iptables`, `gawk`, `systemd` — werden bei der Installation **automatisch** installiert
|
||||
## 🚀 Highlights
|
||||
|
||||
## Schnellstart
|
||||
- Automatische Sperren bei Rate-Limit-Verstößen
|
||||
- Erkennung von Random-Subdomain-Floods, z.B. `abc123.example.com`
|
||||
- DNS-Flood-Watchlist: sofortiger permanenter Ban + AbuseIPDB-Meldung für definierte Domains
|
||||
- Progressive Sperren für Wiederholungstäter, ähnlich wie bei fail2ban
|
||||
- Unterstützung für DNS, DoH, DoT, DoQ und DNSCrypt
|
||||
- IPv4 und IPv6
|
||||
- Eigene Firewall-Chain für sauberes Debugging und einfache Entfernung
|
||||
- Externe Blocklisten und dynamische externe Whitelists
|
||||
- GeoIP-Länderfilter mit Blocklist- oder Allowlist-Modus
|
||||
- AbuseIPDB-Reporting für permanent gesperrte IPs
|
||||
- Benachrichtigungen über Ntfy, Discord, Slack, Gotify oder Generic Webhook
|
||||
- E-Mail-Reports als HTML oder Text
|
||||
- Watchdog mit automatischem Health Check und Recovery
|
||||
|
||||
## ✅ Voraussetzungen
|
||||
|
||||
- Linux-Server mit AdGuard Home
|
||||
- Root-Zugriff per `sudo`
|
||||
- Erreichbare AdGuard Home Web-API, standardmäßig `http://127.0.0.1:3000`
|
||||
- `curl`, `jq`, `iptables`, `gawk` und `systemd`
|
||||
|
||||
Die benötigten Pakete werden vom Installer automatisch installiert.
|
||||
|
||||
## ⚡ Schnellstart
|
||||
|
||||
```bash
|
||||
# 1. Repository klonen
|
||||
git clone https://git.techniverse.net/scriptos/adguard-shield.git /tmp/adguard-shield
|
||||
cd /tmp/adguard-shield
|
||||
|
||||
# 2. Installer aufrufen (interaktives Menü)
|
||||
# Interaktives Installationsmenü
|
||||
sudo bash install.sh
|
||||
|
||||
# Oder direkt installieren:
|
||||
sudo bash install.sh install
|
||||
|
||||
# 3. Erst im Dry-Run testen (loggt nur, sperrt nichts)
|
||||
# Vor dem produktiven Start testen: loggt nur, sperrt nichts
|
||||
sudo /opt/adguard-shield/adguard-shield.sh dry-run
|
||||
|
||||
# 4. Wenn alles passt — Service starten
|
||||
# Service starten und prüfen
|
||||
sudo systemctl start adguard-shield
|
||||
sudo systemctl status adguard-shield
|
||||
```
|
||||
|
||||
> **Hinweis:** Bei der Installation werden alle benötigten Abhängigkeiten automatisch installiert und der Service wird für den Autostart beim Booten registriert.
|
||||
> Beim Installieren wird der systemd-Service für den Autostart registriert. Der Watchdog-Timer wird ebenfalls eingerichtet und prüft den Service regelmäßig.
|
||||
|
||||
[](https://asciinema.techniverse.net/a/77)
|
||||
|
||||
## Wichtigste Befehle
|
||||
## 🔧 Wichtigste Befehle
|
||||
|
||||
### Installation & Updates
|
||||
|
||||
```bash
|
||||
# Installer-Menü
|
||||
sudo bash install.sh # Interaktives Menü (Install/Update/Uninstall/Status)
|
||||
sudo bash install.sh --help # Hilfe anzeigen
|
||||
sudo bash install.sh update # Update mit automatischer Konfigurations-Migration
|
||||
sudo bash install.sh status # Installationsstatus prüfen
|
||||
|
||||
# Deinstallation (kein install.sh benötigt)
|
||||
sudo bash /opt/adguard-shield/uninstall.sh # Direkt aus dem Installationsverzeichnis
|
||||
|
||||
# Monitor
|
||||
sudo /opt/adguard-shield/adguard-shield.sh status # Aktive Sperren anzeigen
|
||||
sudo /opt/adguard-shield/adguard-shield.sh history # Ban-History anzeigen
|
||||
sudo /opt/adguard-shield/adguard-shield.sh unban IP # Einzelne IP entsperren
|
||||
sudo /opt/adguard-shield/adguard-shield.sh flush # Alle Sperren aufheben
|
||||
sudo /opt/adguard-shield/adguard-shield.sh reset-offenses # Offense-Zähler zurücksetzen
|
||||
sudo /opt/adguard-shield/adguard-shield.sh test # API-Verbindung testen
|
||||
sudo /opt/adguard-shield/adguard-shield.sh blocklist-status # Externe Blocklisten Status
|
||||
sudo /opt/adguard-shield/adguard-shield.sh blocklist-sync # Blocklisten manuell synchronisieren
|
||||
sudo /opt/adguard-shield/adguard-shield.sh whitelist-status # Externe Whitelisten Status
|
||||
sudo /opt/adguard-shield/adguard-shield.sh whitelist-sync # Whitelisten manuell synchronisieren
|
||||
sudo /opt/adguard-shield/adguard-shield.sh geoip-status # GeoIP-Status anzeigen
|
||||
sudo /opt/adguard-shield/adguard-shield.sh geoip-sync # GeoIP einmalig prüfen
|
||||
sudo /opt/adguard-shield/adguard-shield.sh geoip-lookup IP # GeoIP-Lookup einer IP
|
||||
sudo /opt/adguard-shield/report-generator.sh send # Report jetzt senden
|
||||
sudo /opt/adguard-shield/report-generator.sh status # Report-Status anzeigen
|
||||
sudo /opt/adguard-shield/report-generator.sh install # Cron-Job einrichten
|
||||
sudo journalctl -u adguard-shield -f # Logs live verfolgen
|
||||
|
||||
# Watchdog (automatischer Health Check)
|
||||
sudo systemctl status adguard-shield-watchdog.timer # Watchdog-Status
|
||||
sudo systemctl list-timers adguard-shield-watchdog.timer # Nächste Ausführung
|
||||
sudo bash install.sh # Interaktives Menü
|
||||
sudo bash install.sh install # Direkt installieren
|
||||
sudo bash install.sh update # Update inkl. Konfigurations-Migration
|
||||
sudo bash install.sh status # Installationsstatus prüfen
|
||||
sudo bash /opt/adguard-shield/uninstall.sh
|
||||
```
|
||||
|
||||
## Dokumentation
|
||||
### Betrieb & Diagnose
|
||||
|
||||
| Dokument | Inhalt |
|
||||
|----------|--------|
|
||||
| [Architektur](docs/architektur.md) | Wie das Tool funktioniert, iptables-Strategie, Konfig-Migration |
|
||||
| [Konfiguration](docs/konfiguration.md) | Alle Parameter, Ports, Whitelist-Pflege, automatische Migration |
|
||||
| [Befehle](docs/befehle.md) | Vollständige Befehlsreferenz für Installer, Monitor, iptables-Helper und systemd |
|
||||
| [Benachrichtigungen](docs/benachrichtigungen.md) | Setup für Discord, Slack, Gotify, Ntfy |
|
||||
| [E-Mail Report](docs/report.md) | Periodische Statistik-Reports per E-Mail (HTML/TXT) |
|
||||
| [Tipps & Troubleshooting](docs/tipps-und-troubleshooting.md) | Best Practices, häufige Probleme, Watchdog, Deinstallation |
|
||||
```bash
|
||||
sudo systemctl status adguard-shield
|
||||
sudo systemctl restart adguard-shield
|
||||
sudo journalctl -u adguard-shield -f
|
||||
|
||||
## Lizenz
|
||||
sudo /opt/adguard-shield/adguard-shield.sh status
|
||||
sudo /opt/adguard-shield/adguard-shield.sh history
|
||||
sudo /opt/adguard-shield/adguard-shield.sh test
|
||||
sudo /opt/adguard-shield/adguard-shield.sh unban 192.0.2.10
|
||||
sudo /opt/adguard-shield/adguard-shield.sh flush
|
||||
```
|
||||
|
||||
[MIT](LICENSE)
|
||||
### Optionale Module
|
||||
|
||||
---
|
||||
```bash
|
||||
sudo /opt/adguard-shield/adguard-shield.sh blocklist-status
|
||||
sudo /opt/adguard-shield/adguard-shield.sh whitelist-status
|
||||
sudo /opt/adguard-shield/adguard-shield.sh geoip-status
|
||||
|
||||
## 👥 Techniverse Community
|
||||
sudo /opt/adguard-shield/report-generator.sh status
|
||||
sudo /opt/adguard-shield/report-generator.sh send
|
||||
sudo /opt/adguard-shield/report-generator.sh install
|
||||
```
|
||||
|
||||
Lust auf Austausch rund um Matrix, Selfhosting und andere smarte IT-Lösungen?
|
||||
In der **Techniverse Community** triffst du Gleichgesinnte, kannst Fragen stellen oder einfach nerdigen Talk genießen. 🚀
|
||||
Die vollständige Befehlsreferenz steht in [docs/befehle.md](docs/befehle.md).
|
||||
|
||||
👉 **[Jetzt der Gruppe auf Matrix beitreten](https://matrix.to/#/#community:techniverse.net)**
|
||||
~ Direkte Raumadresse: `#community:techniverse.net`
|
||||
## ⚙️ Konfiguration
|
||||
|
||||
👉 **[Für lockere Gespräche abseits der Kernthemen komm in den Talkraum](https://matrix.to/#/#talk:techniverse.net)**
|
||||
~ Direkte Raumadresse: `#talk:techniverse.net`
|
||||
Die zentrale Konfiguration liegt nach der Installation hier:
|
||||
|
||||
Wir freuen uns, wenn du dabei bist!
|
||||
```text
|
||||
/opt/adguard-shield/adguard-shield.conf
|
||||
```
|
||||
|
||||
---
|
||||
Wichtige Startpunkte:
|
||||
|
||||
📝 **Blog:** [www.cleveradmin.de](https://www.cleveradmin.de)
|
||||
🌐 **Webseite:** [www.patrick-asmus.de](https://www.patrick-asmus.de)
|
||||
📧 **E-Mail:** [support@techniverse.net](mailto:support@techniverse.net)
|
||||
- `ADGUARD_URL`, `ADGUARD_USER`, `ADGUARD_PASS` für die AdGuard-Home-API
|
||||
- `RATE_LIMIT_MAX_REQUESTS`, `RATE_LIMIT_WINDOW` und `CHECK_INTERVAL` für die Erkennung
|
||||
- `BAN_DURATION` und `PROGRESSIVE_BAN_*` für temporäre und progressive Sperren
|
||||
- `WHITELIST` für vertrauenswürdige Clients wie Router, Management-IPs oder lokale Resolver
|
||||
- `DNS_FLOOD_WATCHLIST_*` für sofortigen Permanent-Ban bei bekannten Flood-Domains
|
||||
- `NOTIFY_*`, `REPORT_*`, `GEOIP_*`, `EXTERNAL_BLOCKLIST_*` und `EXTERNAL_WHITELIST_*` für optionale Funktionen
|
||||
|
||||
Bei Updates migriert der Installer die bestehende Konfiguration automatisch: vorhandene Werte bleiben erhalten, neue Parameter werden ergänzt und die alte Datei wird als `adguard-shield.conf.old` gesichert.
|
||||
|
||||
Mehr Details findest du in [docs/konfiguration.md](docs/konfiguration.md).
|
||||
|
||||
## 🧭 Dokumentation
|
||||
|
||||
| Thema | Link |
|
||||
|---|---|
|
||||
| Architektur & Funktionsweise | [docs/architektur.md](docs/architektur.md) |
|
||||
| Befehle & Nutzung | [docs/befehle.md](docs/befehle.md) |
|
||||
| Konfiguration | [docs/konfiguration.md](docs/konfiguration.md) |
|
||||
| Benachrichtigungen | [docs/benachrichtigungen.md](docs/benachrichtigungen.md) |
|
||||
| E-Mail Report | [docs/report.md](docs/report.md) |
|
||||
| Updates | [docs/update.md](docs/update.md) |
|
||||
| Tipps & Troubleshooting | [docs/tipps-und-troubleshooting.md](docs/tipps-und-troubleshooting.md) |
|
||||
|
||||
## 🧩 Wie es arbeitet
|
||||
|
||||
1. AdGuard Shield liest regelmäßig das AdGuard-Home-Query-Log über die API.
|
||||
2. Anfragen werden pro Client, Domain und Protokoll ausgewertet.
|
||||
3. Überschreitet ein Client die konfigurierten Limits, wird er gegen Whitelist und Sonderregeln geprüft.
|
||||
4. Die Sperre landet in der eigenen Firewall-Chain `ADGUARD_SHIELD`.
|
||||
5. Ban-History, Logs und optionale Benachrichtigungen dokumentieren das Ereignis.
|
||||
6. Temporäre Sperren werden automatisch entfernt, permanente Sperren bleiben bis zur manuellen Freigabe aktiv.
|
||||
|
||||
<br><br>
|
||||
<p align="center">
|
||||
<img src="https://assets.techniverse.net/f1/git/graphics/gray0-catonline.svg" alt="">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://assets.techniverse.net/f1/logos/small/license.png" alt="License" width="15" height="15"> <a href="./LICENSE">License</a> | <img src="https://assets.techniverse.net/f1/logos/small/matrix2.svg" alt="Matrix" width="15" height="15"> <a href="https://matrix.to/#/#community:techniverse.net">Matrix</a> | <img src="https://assets.techniverse.net/f1/logos/small/mastodon2.svg" alt="Mastodon" width="15" height="15"> <a href="https://social.techniverse.net/@donnerwolke">Mastodon</a>
|
||||
</p>
|
||||
<sub>
|
||||
Patrick Asmus · Techniverse Network · <a href="./LICENSE">Lizenz</a>
|
||||
</sub>
|
||||
</p>
|
||||
@@ -18,6 +18,10 @@ SUBDOMAIN_FLOOD_ENABLED=true
|
||||
SUBDOMAIN_FLOOD_MAX_UNIQUE=50 # Max. eindeutige Subdomains pro Basisdomain/Client
|
||||
SUBDOMAIN_FLOOD_WINDOW=60 # Zeitfenster in Sekunden
|
||||
|
||||
# --- DNS-Flood-Watchlist ---
|
||||
DNS_FLOOD_WATCHLIST_ENABLED=false
|
||||
DNS_FLOOD_WATCHLIST="" # Kommagetrennt, z.B. "example.com,evil.org"
|
||||
|
||||
# --- Sperr-Einstellungen ---
|
||||
BAN_DURATION=3600 # Basis-Sperrdauer in Sekunden
|
||||
IPTABLES_CHAIN="ADGUARD_SHIELD"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# Lizenz: MIT
|
||||
###############################################################################
|
||||
|
||||
VERSION="v0.8.0"
|
||||
VERSION="v0.9.0"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -369,6 +369,32 @@ is_whitelisted() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# ─── DNS-Flood-Watchlist Prüfung ────────────────────────────────────────────
|
||||
is_dns_flood_watchlist_match() {
|
||||
local domain="$1"
|
||||
|
||||
if [[ "${DNS_FLOOD_WATCHLIST_ENABLED:-false}" != "true" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -z "${DNS_FLOOD_WATCHLIST:-}" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local entry
|
||||
IFS=',' read -ra watchlist_entries <<< "$DNS_FLOOD_WATCHLIST"
|
||||
for entry in "${watchlist_entries[@]}"; do
|
||||
entry=$(echo "$entry" | xargs)
|
||||
[[ -z "$entry" ]] && continue
|
||||
|
||||
if [[ "$domain" == "$entry" || "$domain" == *".$entry" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# ─── iptables Chain Setup ────────────────────────────────────────────────────
|
||||
setup_iptables_chain() {
|
||||
# IPv4 Chain erstellen falls nicht vorhanden
|
||||
@@ -425,6 +451,13 @@ ban_client() {
|
||||
fi
|
||||
fi
|
||||
|
||||
# DNS-Flood-Watchlist: Sofort permanent sperren
|
||||
if [[ "$reason" == "dns-flood-watchlist" ]]; then
|
||||
is_permanent=true
|
||||
effective_duration=0
|
||||
log "WARN" "DNS-Flood-Watchlist: Erzwinge permanente Sperre für $client_ip ($domain)"
|
||||
fi
|
||||
|
||||
local ban_until
|
||||
local ban_until_display
|
||||
if [[ "$is_permanent" == "true" ]]; then
|
||||
@@ -439,16 +472,16 @@ ban_client() {
|
||||
duration_display=$(format_duration "$effective_duration")
|
||||
|
||||
if [[ "$DRY_RUN" == "true" ]]; then
|
||||
if [[ "${PROGRESSIVE_BAN_ENABLED:-false}" == "true" ]]; then
|
||||
if [[ "${PROGRESSIVE_BAN_ENABLED:-false}" == "true" && "$reason" != "dns-flood-watchlist" ]]; then
|
||||
log "WARN" "[DRY-RUN] WÜRDE sperren: $client_ip (${count}x $domain in ${window}s via $protocol) für ${duration_display} [Stufe $offense_level] [${reason}]"
|
||||
else
|
||||
log "WARN" "[DRY-RUN] WÜRDE sperren: $client_ip (${count}x $domain in ${window}s via $protocol) [${reason}]"
|
||||
log "WARN" "[DRY-RUN] WÜRDE sperren: $client_ip (${count}x $domain in ${window}s via $protocol) für ${duration_display} [${reason}]"
|
||||
fi
|
||||
log_ban_history "DRY" "$client_ip" "$domain" "$count" "dry-run (${reason})" "${duration_display}" "$protocol"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "${PROGRESSIVE_BAN_ENABLED:-false}" == "true" ]]; then
|
||||
if [[ "${PROGRESSIVE_BAN_ENABLED:-false}" == "true" && "$reason" != "dns-flood-watchlist" ]]; then
|
||||
log "WARN" "SPERRE Client: $client_ip (${count}x $domain in ${window}s via $protocol) für ${duration_display} [Stufe ${offense_level}/${PROGRESSIVE_BAN_MAX_LEVEL:-0}] [${reason}]"
|
||||
else
|
||||
log "WARN" "SPERRE Client: $client_ip (${count}x $domain in ${window}s via $protocol) für ${duration_display} [${reason}]"
|
||||
@@ -480,7 +513,7 @@ EOF
|
||||
|
||||
# Ban-History Eintrag
|
||||
local history_duration="${duration_display}"
|
||||
[[ "${PROGRESSIVE_BAN_ENABLED:-false}" == "true" ]] && history_duration="${duration_display} (Stufe ${offense_level})"
|
||||
[[ "${PROGRESSIVE_BAN_ENABLED:-false}" == "true" && "$reason" != "dns-flood-watchlist" ]] && history_duration="${duration_display} (Stufe ${offense_level})"
|
||||
log_ban_history "BAN" "$client_ip" "$domain" "$count" "$reason" "$history_duration" "$protocol"
|
||||
|
||||
# Benachrichtigung senden
|
||||
@@ -574,6 +607,7 @@ send_notification() {
|
||||
|
||||
local reason_label="Rate-Limit"
|
||||
[[ "$reason" == "subdomain-flood" ]] && reason_label="Subdomain-Flood"
|
||||
[[ "$reason" == "dns-flood-watchlist" ]] && reason_label="DNS-Flood-Watchlist"
|
||||
|
||||
local title
|
||||
local message
|
||||
@@ -591,12 +625,12 @@ send_notification() {
|
||||
abuseipdb_hint=$'\n⚠️ IP wurde an AbuseIPDB gemeldet'
|
||||
fi
|
||||
|
||||
# Dauer-Anzeige mit Stufe
|
||||
# Dauer-Anzeige mit Stufe (nicht bei Watchlist – dort ist es immer permanent)
|
||||
local dur_line
|
||||
if [[ "${PROGRESSIVE_BAN_ENABLED:-false}" == "true" && -n "$offense_level" ]]; then
|
||||
if [[ "${PROGRESSIVE_BAN_ENABLED:-false}" == "true" && -n "$offense_level" && "$reason" != "dns-flood-watchlist" ]]; then
|
||||
dur_line="**${duration_display}** [Stufe ${offense_level}/${PROGRESSIVE_BAN_MAX_LEVEL:-0}]"
|
||||
else
|
||||
dur_line=$(format_duration "${BAN_DURATION}")
|
||||
dur_line="**${duration_display}**"
|
||||
fi
|
||||
|
||||
message="🚫 AdGuard Shield Ban auf ${my_hostname}${abuseipdb_hint}
|
||||
@@ -839,7 +873,13 @@ analyze_queries() {
|
||||
continue
|
||||
fi
|
||||
|
||||
ban_client "$client" "$domain" "$count" "rate-limit" "$RATE_LIMIT_WINDOW" "$proto_display"
|
||||
local ban_reason="rate-limit"
|
||||
if is_dns_flood_watchlist_match "$domain"; then
|
||||
ban_reason="dns-flood-watchlist"
|
||||
log "WARN" "DNS-Flood-Watchlist Treffer: $client → $domain (${count}x in ${RATE_LIMIT_WINDOW}s) → permanenter Ban + AbuseIPDB"
|
||||
fi
|
||||
|
||||
ban_client "$client" "$domain" "$count" "$ban_reason" "$RATE_LIMIT_WINDOW" "$proto_display"
|
||||
fi
|
||||
done <<< "$violations"
|
||||
}
|
||||
@@ -961,7 +1001,13 @@ analyze_subdomain_flood() {
|
||||
continue
|
||||
fi
|
||||
|
||||
ban_client "$client" "*.${base_domain}" "$unique_count" "subdomain-flood" "$window" "$proto_display"
|
||||
local ban_reason="subdomain-flood"
|
||||
if is_dns_flood_watchlist_match "$base_domain"; then
|
||||
ban_reason="dns-flood-watchlist"
|
||||
log "WARN" "DNS-Flood-Watchlist Treffer (Subdomain-Flood): $client → *.${base_domain} → permanenter Ban + AbuseIPDB"
|
||||
fi
|
||||
|
||||
ban_client "$client" "*.${base_domain}" "$unique_count" "$ban_reason" "$window" "$proto_display"
|
||||
done <<< "$violations"
|
||||
}
|
||||
|
||||
@@ -989,6 +1035,14 @@ show_status() {
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# DNS-Flood-Watchlist Info
|
||||
if [[ "${DNS_FLOOD_WATCHLIST_ENABLED:-false}" == "true" ]]; then
|
||||
echo " 🎯 DNS-Flood-Watchlist: AKTIV"
|
||||
echo " Domains: ${DNS_FLOOD_WATCHLIST:-<keine>}"
|
||||
echo " Aktion: Sofort permanenter Ban + AbuseIPDB-Meldung"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# GeoIP-Filter Info
|
||||
if [[ "${GEOIP_ENABLED:-false}" == "true" ]]; then
|
||||
local geoip_mode_label
|
||||
@@ -1021,6 +1075,7 @@ show_status() {
|
||||
|
||||
local reason_tag=""
|
||||
[[ "$s_reason" == "subdomain-flood" ]] && reason_tag=" (Subdomain-Flood)"
|
||||
[[ "$s_reason" == "dns-flood-watchlist" ]] && reason_tag=" (DNS-Flood-Watchlist)"
|
||||
|
||||
local count_info=""
|
||||
if [[ -n "$s_count" && "$s_count" != "-" ]]; then
|
||||
@@ -1033,7 +1088,9 @@ show_status() {
|
||||
|
||||
local proto_tag=" via ${s_proto}"
|
||||
|
||||
if [[ "$s_perm" == "true" ]]; then
|
||||
if [[ "$s_perm" == "true" && "$s_reason" == "dns-flood-watchlist" ]]; then
|
||||
echo " 🚫 Gesperrt: $s_ip → $s_domain [PERMANENT${count_info}${proto_tag}]${reason_tag}"
|
||||
elif [[ "$s_perm" == "true" ]]; then
|
||||
echo " 🚫 Gesperrt: $s_ip → $s_domain [PERMANENT, Stufe ${s_level:-?}${count_info}${proto_tag}]${reason_tag}"
|
||||
elif [[ -n "$s_level" && "$s_level" -gt 0 ]]; then
|
||||
echo " 🚫 Gesperrt: $s_ip → $s_domain [Stufe ${s_level}, $(format_duration "${s_dur:-$BAN_DURATION}"), bis $s_until${count_info}${proto_tag}]${reason_tag}"
|
||||
@@ -1271,8 +1328,8 @@ start_offense_cleanup_worker() {
|
||||
return
|
||||
fi
|
||||
|
||||
log "INFO" "Starte Offense-Cleanup-Worker im Hintergrund..."
|
||||
bash "$worker_script" start &
|
||||
log "INFO" "Starte Offense-Cleanup-Worker im Hintergrund (nice 19, idle I/O)..."
|
||||
nice -n 19 ionice -c 3 bash "$worker_script" start &
|
||||
OFFENSE_CLEANUP_WORKER_PID=$!
|
||||
log "INFO" "Offense-Cleanup-Worker gestartet (PID: $OFFENSE_CLEANUP_WORKER_PID)"
|
||||
}
|
||||
@@ -1312,6 +1369,11 @@ main_loop() {
|
||||
else
|
||||
log "INFO" " Subdomain-Flood-Schutz: deaktiviert"
|
||||
fi
|
||||
if [[ "${DNS_FLOOD_WATCHLIST_ENABLED:-false}" == "true" ]]; then
|
||||
log "INFO" " DNS-Flood-Watchlist: AKTIV (Domains: ${DNS_FLOOD_WATCHLIST:-<keine>})"
|
||||
else
|
||||
log "INFO" " DNS-Flood-Watchlist: deaktiviert"
|
||||
fi
|
||||
if [[ "${ABUSEIPDB_ENABLED:-false}" == "true" ]]; then
|
||||
log "INFO" " AbuseIPDB Reporting: AKTIV (Kategorien: ${ABUSEIPDB_CATEGORIES:-4})"
|
||||
else
|
||||
|
||||
@@ -56,6 +56,17 @@
|
||||
|
||||
> **Hinweis:** Die Subdomain-Flood-Erkennung hat ein eigenes Zeitfenster (`SUBDOMAIN_FLOOD_WINDOW`) und einen eigenen Schwellwert (`SUBDOMAIN_FLOOD_MAX_UNIQUE`), unabhängig von den Rate-Limit-Einstellungen.
|
||||
|
||||
### DNS-Flood-Watchlist-Sperre
|
||||
|
||||
1. Client `10.0.0.42` fragt `microsoft.com` 35x in 60 Sekunden an
|
||||
2. Monitor erkennt: 35 > 30 (Limit überschritten)
|
||||
3. Domain `microsoft.com` steht auf der DNS-Flood-Watchlist → **sofortige permanente Sperre**
|
||||
4. Progressive-Ban-Stufe wird ignoriert — kein stufenweises Hochstufen
|
||||
5. IP wird an AbuseIPDB gemeldet (falls aktiviert)
|
||||
6. Permanente Sperre bleibt bis zur manuellen Freigabe aktiv
|
||||
|
||||
> **Hinweis:** Die Watchlist greift sowohl bei normalen Rate-Limit-Verstößen als auch bei Subdomain-Flood-Erkennungen. Subdomains werden automatisch erkannt: `foo.microsoft.com` matcht den Watchlist-Eintrag `microsoft.com`.
|
||||
|
||||
## iptables Strategie
|
||||
|
||||
Das Tool erstellt eine eigene Chain `ADGUARD_SHIELD`:
|
||||
@@ -137,7 +148,7 @@ Das ermöglicht:
|
||||
├── external-blocklist-worker.sh # Externer Blocklist-Worker
|
||||
├── external-whitelist-worker.sh # Externer Whitelist-Worker (DNS-Auflösung)
|
||||
├── geoip-worker.sh # GeoIP-Länderfilter-Worker
|
||||
├── offense-cleanup-worker.sh # Automatisches Aufräumen abgelaufener Offense-Zähler
|
||||
├── offense-cleanup-worker.sh # Aufräumen abgelaufener Offense-Zähler (nice 19, idle I/O)
|
||||
├── unban-expired.sh # Cron-basiertes Entsperren
|
||||
└── geoip/ # Auto-Download MaxMind GeoLite2 DB (optional)
|
||||
|
||||
@@ -210,8 +221,10 @@ ZEITSTEMPEL | AKTION | CLIENT-IP | DOMAIN
|
||||
|-------|----------|
|
||||
| `rate-limit` | Automatische Sperre wegen Limit-Überschreitung |
|
||||
| `subdomain-flood` | Sperre wegen zu vieler eindeutiger Subdomains einer Basisdomain |
|
||||
| `dns-flood-watchlist` | Sofortige permanente Sperre + AbuseIPDB-Meldung (Domain auf der Watchlist) |
|
||||
| `dry-run` | Im Dry-Run erkannt (nicht wirklich gesperrt) |
|
||||
| `dry-run (subdomain-flood)` | Subdomain-Flood im Dry-Run erkannt |
|
||||
| `dry-run (dns-flood-watchlist)` | Watchlist-Treffer im Dry-Run erkannt |
|
||||
| `expired` | Automatisch entsperrt nach Ablauf der Sperrdauer |
|
||||
| `expired-cron` | Entsperrt durch den Cron-Job (`unban-expired.sh`) |
|
||||
| `manual` | Manuell entsperrt per `unban`-Befehl |
|
||||
|
||||
@@ -284,7 +284,7 @@ sudo /opt/adguard-shield/geoip-worker.sh flush-cache
|
||||
|
||||
## Offense-Cleanup-Worker
|
||||
|
||||
Der Offense-Cleanup-Worker räumt abgelaufene Offense-Zähler (progressive Sperren) automatisch auf. Er startet automatisch mit dem Hauptservice, wenn progressive Sperren aktiviert sind, und prüft stündlich ob Zähler aufgeräumt werden können.
|
||||
Der Offense-Cleanup-Worker räumt abgelaufene Offense-Zähler (progressive Sperren) automatisch auf. Er startet automatisch mit dem Hauptservice, wenn progressive Sperren aktiviert sind, und prüft stündlich ob Zähler aufgeräumt werden können. Der Worker läuft mit niedrigster CPU- und I/O-Priorität (`nice 19`, `ionice idle`), um den DNS-Dienst nicht zu beeinträchtigen.
|
||||
|
||||
Der Worker kann auch standalone gesteuert werden:
|
||||
|
||||
|
||||
@@ -116,12 +116,12 @@ Bei Sperren aus der **externen Blocklist** werden Benachrichtigungen separat üb
|
||||
### Service gestartet
|
||||
**Überschrift:** ✅ AdGuard Shield
|
||||
|
||||
> 🟢 AdGuard Shield v0.8.0 wurde auf dns1 gestartet.
|
||||
> 🟢 AdGuard Shield v0.9.0 wurde auf dns1 gestartet.
|
||||
|
||||
### Service gestoppt
|
||||
**Überschrift:** 🚨 🛡️ AdGuard Shield
|
||||
|
||||
> 🔴 AdGuard Shield v0.8.0 wurde auf dns1 gestoppt.
|
||||
> 🔴 AdGuard Shield v0.9.0 wurde auf dns1 gestoppt.
|
||||
|
||||
### Watchdog — Service wiederhergestellt
|
||||
**Überschrift:** 🔄 AdGuard Shield Watchdog
|
||||
@@ -167,6 +167,19 @@ Bei permanenter Sperre mit aktiviertem AbuseIPDB-Reporting erscheint zusätzlich
|
||||
> Whois: https://www.whois.com/whois/95.71.42.116
|
||||
> AbuseIPDB: https://www.abuseipdb.com/check/95.71.42.116
|
||||
|
||||
Bei DNS-Flood-Watchlist-Treffer (sofort permanent, ohne Stufe):
|
||||
|
||||
> 🚫 AdGuard Shield Ban auf dns1
|
||||
> ⚠️ IP wurde an AbuseIPDB gemeldet
|
||||
> ---
|
||||
> IP: 95.71.42.116
|
||||
> Hostname: example-host.provider.net
|
||||
> Grund: 45x microsoft.com in 60s via DNS, DNS-Flood-Watchlist
|
||||
> Dauer: PERMANENT
|
||||
>
|
||||
> Whois: https://www.whois.com/whois/95.71.42.116
|
||||
> AbuseIPDB: https://www.abuseipdb.com/check/95.71.42.116
|
||||
|
||||
### Entsperrung (Unban)
|
||||
**Überschrift:** ✅ AdGuard Shield
|
||||
|
||||
|
||||
@@ -70,6 +70,34 @@ xk9z3a.microsoft.com
|
||||
|
||||
> **Tipp:** Der Schwellwert `SUBDOMAIN_FLOOD_MAX_UNIQUE` sollte hoch genug sein, um legitime Clients nicht zu stören (z.B. CDNs nutzen oft viele Subdomains). Ein Wert von 50–100 ist in den meisten Fällen sinnvoll.
|
||||
|
||||
### DNS-Flood-Watchlist
|
||||
|
||||
Domains bei denen eine Rate-Limit-Überschreitung **sofort** zu einer **permanenten Sperre** und einer **AbuseIPDB-Meldung** führt — ohne progressive Eskalation. Ideal für bekannte Angriffsziele, die regelmäßig geflutet werden (z.B. `microsoft.com`, `google.com`).
|
||||
|
||||
| Parameter | Standard | Beschreibung |
|
||||
|-----------|----------|--------------|
|
||||
| `DNS_FLOOD_WATCHLIST_ENABLED` | `false` | DNS-Flood-Watchlist aktivieren |
|
||||
| `DNS_FLOOD_WATCHLIST` | *(leer)* | Überwachte Domains, kommagetrennt (z.B. `"microsoft.com,google.com"`) |
|
||||
|
||||
#### Wie funktioniert die Watchlist?
|
||||
|
||||
1. Die reguläre Rate-Limit-Prüfung erkennt, dass ein Client mehr als `RATE_LIMIT_MAX_REQUESTS` Anfragen für eine Domain gestellt hat
|
||||
2. Zusätzlich wird geprüft, ob die angefragte Domain in der Watchlist steht (inkl. Subdomains: `foo.microsoft.com` matcht `microsoft.com`)
|
||||
3. Trifft beides zu → **sofortige permanente Sperre** + **AbuseIPDB-Meldung** (falls aktiviert)
|
||||
|
||||
Die Watchlist greift sowohl bei normalen Rate-Limit-Verstößen als auch bei Subdomain-Flood-Erkennungen.
|
||||
|
||||
#### Beispiel
|
||||
|
||||
```bash
|
||||
DNS_FLOOD_WATCHLIST_ENABLED=true
|
||||
DNS_FLOOD_WATCHLIST="microsoft.com,google.com,apple.com"
|
||||
```
|
||||
|
||||
→ Ein Client der `35x foo.microsoft.com` in 60s abfragt (bei `RATE_LIMIT_MAX_REQUESTS=30`) wird **sofort permanent** gesperrt und an AbuseIPDB gemeldet.
|
||||
|
||||
> **Hinweis:** Damit die AbuseIPDB-Meldung funktioniert, muss `ABUSEIPDB_ENABLED=true` und ein gültiger `ABUSEIPDB_API_KEY` konfiguriert sein. Ohne AbuseIPDB-Konfiguration wird nur permanent gesperrt.
|
||||
|
||||
### Sperr-Einstellungen
|
||||
|
||||
| Parameter | Standard | Beschreibung |
|
||||
@@ -100,7 +128,7 @@ Wiederholungstäter werden wie bei fail2ban stufenweise länger gesperrt. Wird e
|
||||
| 4. Mal | 4 | 8 Stunden | 3600 × 8 |
|
||||
| 5. Mal | 5 | **PERMANENT** | Max-Stufe erreicht |
|
||||
|
||||
> **Hinweis:** Abgelaufene Offense-Zähler werden automatisch vom **Offense-Cleanup-Worker** aufgeräumt, der stündlich prüft, ob das letzte Vergehen einer IP länger als `PROGRESSIVE_BAN_RESET_AFTER` zurückliegt. Der Worker startet automatisch zusammen mit dem Hauptservice, wenn progressive Sperren aktiviert sind. Manuelles Zurücksetzen ist jederzeit mit `reset-offenses` möglich. Permanente Sperren werden **nicht** automatisch aufgehoben – sie müssen manuell mit `unban` oder `flush` entfernt werden.
|
||||
> **Hinweis:** Abgelaufene Offense-Zähler werden automatisch vom **Offense-Cleanup-Worker** aufgeräumt, der stündlich prüft, ob das letzte Vergehen einer IP länger als `PROGRESSIVE_BAN_RESET_AFTER` zurückliegt. Der Worker startet automatisch zusammen mit dem Hauptservice, wenn progressive Sperren aktiviert sind. Er läuft mit niedrigster CPU- und I/O-Priorität (`nice 19`, `ionice idle`), sodass andere Dienste nicht beeinträchtigt werden. Manuelles Zurücksetzen ist jederzeit mit `reset-offenses` möglich. Permanente Sperren werden **nicht** automatisch aufgehoben – sie müssen manuell mit `unban` oder `flush` entfernt werden.
|
||||
|
||||
### Logging
|
||||
|
||||
@@ -251,7 +279,7 @@ sudo systemctl restart adguard-shield
|
||||
|
||||
Der Report an AbuseIPDB enthält (auf Englisch):
|
||||
|
||||
- **Bei Rate-Limit:** `DNS flooding on our DNS server: 100x microsoft.com in 60s. Banned by Adguard Shield 🔗 https://tnvs.de/as`
|
||||
- **Bei Rate-Limit / DNS-Flood-Watchlist:** `DNS flooding on our DNS server: 100x microsoft.com in 60s. Banned by Adguard Shield 🔗 https://tnvs.de/as`
|
||||
- **Bei Subdomain-Flood:** `DNS flooding on our DNS server: 85x *.microsoft.com in 60s (random subdomain attack). Banned by Adguard Shield 🔗 https://tnvs.de/as`
|
||||
|
||||
Die Kategorie `4` (DDoS Attack) wird standardmäßig verwendet. Weitere Kategorien können kommagetrennt angegeben werden (z.B. `"4,15"`).
|
||||
|
||||
@@ -501,8 +501,8 @@ parse_blocklist_ips() {
|
||||
log "WARN" "Eintrag übersprungen (ungültige IPv6-Adresse oder IP:Port): $line"
|
||||
fi
|
||||
|
||||
elif [[ "$line" =~ ^[0-9] ]]; then
|
||||
# ── IPv4 ──────────────────────────────────────────────────────────
|
||||
elif [[ "$line" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/[0-9]+)?$ ]]; then
|
||||
# ── IPv4 (nur Ziffern, Punkte und optionaler CIDR-Suffix) ────────
|
||||
[[ "$line" == "0.0.0.0"* ]] && continue
|
||||
if _is_valid_ipv4 "$line"; then
|
||||
echo "$line"
|
||||
|
||||
@@ -218,8 +218,8 @@ parse_whitelist_entries() {
|
||||
log "WARN" "Whitelist-Eintrag übersprungen (ungültige IPv6): $line"
|
||||
fi
|
||||
|
||||
elif [[ "$line" =~ ^[0-9] ]]; then
|
||||
# IPv4
|
||||
elif [[ "$line" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/[0-9]+)?$ ]]; then
|
||||
# IPv4 (nur Ziffern, Punkte und optionaler CIDR-Suffix)
|
||||
[[ "$line" == "0.0.0.0"* ]] && continue
|
||||
if _is_valid_ipv4 "$line"; then
|
||||
echo "$line"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# Lizenz: MIT
|
||||
###############################################################################
|
||||
|
||||
VERSION="v0.8.0"
|
||||
VERSION="v0.9.0"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
# Autor: Patrick Asmus
|
||||
# E-Mail: support@techniverse.net
|
||||
# Datum: 2026-04-14
|
||||
# Datum: 2026-04-16
|
||||
# Lizenz: MIT
|
||||
###############################################################################
|
||||
|
||||
@@ -25,6 +25,12 @@ fi
|
||||
# shellcheck source=adguard-shield.conf
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
# ─── Niedrigste Priorität setzen (CPU + I/O) ─────────────────────────────────
|
||||
# Stellt sicher, dass der Worker auch bei manuellem Start nie andere Dienste
|
||||
# verdrängt. nice 19 = niedrigste CPU-Priorität, ionice idle = nur bei freier I/O.
|
||||
renice -n 19 $$ >/dev/null 2>&1 || true
|
||||
ionice -c 3 -p $$ >/dev/null 2>&1 || true
|
||||
|
||||
# ─── Worker PID-File ──────────────────────────────────────────────────────────
|
||||
WORKER_PID_FILE="/var/run/adguard-offense-cleanup-worker.pid"
|
||||
|
||||
@@ -80,6 +86,7 @@ cleanup_expired_offenses() {
|
||||
now=$(date '+%s')
|
||||
local cleaned=0
|
||||
|
||||
local batch_count=0
|
||||
for offense_file in "${STATE_DIR}"/*.offenses; do
|
||||
[[ -f "$offense_file" ]] || continue
|
||||
|
||||
@@ -101,6 +108,12 @@ cleanup_expired_offenses() {
|
||||
rm -f "$offense_file"
|
||||
cleaned=$((cleaned + 1))
|
||||
fi
|
||||
|
||||
# Alle 10 Dateien kurz pausieren, um I/O-Bursts zu vermeiden
|
||||
batch_count=$((batch_count + 1))
|
||||
if (( batch_count % 10 == 0 )); then
|
||||
sleep 0.1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $cleaned -gt 0 ]]; then
|
||||
|
||||
Reference in New Issue
Block a user