24 Commits

Author SHA1 Message Date
Patrick Asmus
16b2c5950e Release: Version v0.9.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-28 23:34:29 +02:00
Patrick Asmus
b93689bbaf feat: DNS-Flood-Watchlist – sofortiger permanenter Ban für definierte Domains 2026-04-28 23:31:58 +02:00
e555db8092 README.md aktualisiert 2026-04-21 13:45:21 +00:00
b04b8bf87d update Readme.md 2026-04-21 12:03:54 +02:00
6b6a77a98c Merge pull request 'fix: IPv4-Erkennung korrigiert – Hostnamen mit führender Ziffer werden nicht mehr fehlklassifiziert' (#17) from v0.8.2 into main
Reviewed-on: #17
2026-04-19 14:18:40 +00:00
ac21922178 Release: Version v0.8.2 2026-04-19 16:17:56 +02:00
edd8cd4806 fix: IPv4-Erkennung korrigiert – Hostnamen mit führender Ziffer werden nicht mehr fehlklassifiziert 2026-04-19 16:15:10 +02:00
44936e9f20 Merge branch 'main' of https://git.techniverse.net/scriptos/adguard-shield 2026-04-17 13:40:46 +02:00
440694925e Merge pull request 'fix: Offense-Cleanup-Worker mit niedrigster CPU/IO-Priorität ausführen' (#16) from v0.8.1 into main
Reviewed-on: #16
2026-04-16 20:23:48 +00:00
c97e327f0d Merge pull request 'fix: Offense-Cleanup-Worker mit niedrigster CPU/IO-Priorität ausführen' (#16) from v0.8.1 into main
Reviewed-on: #16
2026-04-16 20:23:48 +00:00
12745c3fef Release: Version v0.8.1 2026-04-16 22:22:13 +02:00
ccdc555246 fix: Offense-Cleanup-Worker mit niedrigster CPU/IO-Priorität ausführen 2026-04-16 21:33:47 +02:00
2559ed89ea Merge pull request 'v0.8.0' (#15) from v0.8.0 into main
Reviewed-on: #15
2026-04-14 19:30:31 +00:00
6f9f7eba8e Merge tag 'v0.8.0' of https://git.techniverse.net/scriptos/adguard-shield into v0.8.0 2026-04-14 21:24:44 +02:00
a132b2a0f1 Merge pull request 'v0.8.0' (#14) from v0.8.0 into main
Reviewed-on: #14
2026-04-14 19:17:15 +00:00
70818698d1 Release: Version v0.8.0 2026-04-14 21:06:52 +02:00
0264e1e896 feat: Offense-Cleanup-Worker für automatisches Aufräumen abgelaufener Offense-Zähler 2026-04-14 21:01:51 +02:00
df15a587ee update: Konfigurationsdatei aufräumen – Kommentare gekürzt, Verweis auf Doku ergänzt, fehlende Variable EXTERNAL_WHITELIST_CACHE_DIR hinzugefügt 2026-04-14 20:44:06 +02:00
3d60771a1b feat: GeoIP-Länderfilter mit MaxMind Auto-Download 2026-04-14 20:30:37 +02:00
4d7e053ce7 Merge pull request 'v0.7.1' (#13) from v0.7.1 into main
Reviewed-on: #13
2026-04-12 12:37:09 +00:00
23deae7d81 Release: Version v0.7.1 2026-04-12 14:35:47 +02:00
0602fbb596 docs: README für docs-Verzeichnis hinzugefügt 2026-04-12 14:28:37 +02:00
a27c093d83 docs: Projektstruktur entfernt 2026-04-12 14:19:08 +02:00
cfd6fa9b70 feat: Watchdog-Service für automatischen Health-Check und Recovery bei Service-Ausfall 2026-04-12 14:17:59 +02:00
9 changed files with 261 additions and 126 deletions

229
README.md
View File

@@ -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.
[![asciicast](https://asciinema.techniverse.net/a/77.svg)](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>

View File

@@ -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"

View File

@@ -8,7 +8,7 @@
# Lizenz: MIT
###############################################################################
VERSION="v0.8.1"
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}"
@@ -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

View File

@@ -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`:
@@ -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 |

View File

@@ -116,12 +116,12 @@ Bei Sperren aus der **externen Blocklist** werden Benachrichtigungen separat üb
### Service gestartet
**Überschrift:** ✅ AdGuard Shield
> 🟢 AdGuard Shield v0.8.1 wurde auf dns1 gestartet.
> 🟢 AdGuard Shield v0.9.0 wurde auf dns1 gestartet.
### Service gestoppt
**Überschrift:** 🚨 🛡️ AdGuard Shield
> 🔴 AdGuard Shield v0.8.1 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

View File

@@ -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 50100 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 |
@@ -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"`).

View File

@@ -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"

View File

@@ -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"

View File

@@ -6,7 +6,7 @@
# Lizenz: MIT
###############################################################################
VERSION="v0.8.1"
VERSION="v0.9.0"
set -euo pipefail