233 lines
12 KiB
Markdown
233 lines
12 KiB
Markdown
# Architektur & Funktionsweise
|
|
|
|
## Überblick
|
|
|
|
```
|
|
┌─────────────────────┐
|
|
│ Client Anfragen │
|
|
│ (DNS/DoH/DoT/DoQ) │
|
|
└──────────┬──────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────┐ ┌──────────────────────┐
|
|
│ AdGuard Home │────▶ │ Query Log (API) │
|
|
│ DNS Server │ └──────────┬───────────┘
|
|
└─────────────────────┘ │
|
|
▼
|
|
┌──────────────────────┐
|
|
│ adguard-shield.sh │
|
|
│ (Monitor Script) │
|
|
└──────────┬───────────┘
|
|
│
|
|
┌──────────────┼──────────────┐
|
|
▼ ▼ ▼
|
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
│ iptables │ │ Log │ │ Webhook │
|
|
│ DROP │ │ Datei │ │ Notify │
|
|
└──────────┘ └──────────┘ └──────────┘
|
|
```
|
|
|
|
## Ablauf einer Sperre
|
|
|
|
### Rate-Limit-Sperre
|
|
|
|
1. Client `192.168.1.50` fragt `microsoft.com` 45x in 60 Sekunden an
|
|
2. Monitor fragt die AdGuard Home API alle 10 Sekunden ab (`/control/querylog`)
|
|
3. Die Anfragen werden pro Client+Domain-Kombination gezählt
|
|
4. Monitor erkennt: 45 > 30 (Limit überschritten)
|
|
5. Prüfung: Ist der Client auf der Whitelist? → Nein
|
|
6. **Progressive Sperren:** Offense-Level wird geprüft/erhöht, Sperrdauer berechnet
|
|
7. iptables-Regel wird erstellt: `DROP` für `192.168.1.50` auf allen DNS-Ports
|
|
8. State-Datei wird angelegt: `/var/lib/adguard-shield/192.168.1.50.ban`
|
|
9. Offense-Datei wird aktualisiert: `/var/lib/adguard-shield/192.168.1.50.offenses`
|
|
10. Ban-History Eintrag wird in `/var/log/adguard-shield-bans.log` geschrieben
|
|
11. Log-Eintrag + optionale Webhook-Benachrichtigung
|
|
12. Nach Ablauf der (progressiven) Sperrdauer: automatische Entsperrung + History-Eintrag
|
|
|
|
### Subdomain-Flood-Sperre (Random Subdomain Attack)
|
|
|
|
1. Client `10.0.0.99` fragt `abc123.microsoft.com`, `xyz456.microsoft.com`, ... ab
|
|
2. Monitor extrahiert die **Basisdomain** (`microsoft.com`) aus jeder Anfrage
|
|
3. Pro Client wird gezählt, wie viele **eindeutige Subdomains** einer Basisdomain im Zeitfenster abgefragt wurden
|
|
4. Monitor erkennt: 63 eindeutige Subdomains > 50 (Schwellwert überschritten)
|
|
5. Prüfung: Ist der Client auf der Whitelist? → Nein
|
|
6. Sperre wird ausgeführt mit Domain `*.microsoft.com` und Grund `subdomain-flood`
|
|
7. Progressive Sperren greifen auch hier — Wiederholungstäter werden stufenweise länger gesperrt
|
|
|
|
> **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`:
|
|
|
|
```
|
|
INPUT Chain
|
|
├── ... (bestehende Regeln bleiben unberührt)
|
|
├── -p tcp --dport 53 → ADGUARD_SHIELD
|
|
├── -p udp --dport 53 → ADGUARD_SHIELD
|
|
├── -p tcp --dport 443 → ADGUARD_SHIELD
|
|
├── -p udp --dport 443 → ADGUARD_SHIELD
|
|
├── -p tcp --dport 853 → ADGUARD_SHIELD
|
|
├── -p udp --dport 853 → ADGUARD_SHIELD
|
|
└── ...
|
|
|
|
ADGUARD_SHIELD Chain
|
|
├── -s 192.168.1.50 → DROP (gesperrter Client)
|
|
├── -s 10.0.0.25 → DROP (gesperrter Client)
|
|
└── RETURN (alle anderen passieren)
|
|
```
|
|
|
|
**Vorteile der eigenen Chain:**
|
|
- Greift nicht in bestehende Firewall-Regeln ein
|
|
- Kann komplett geflusht werden ohne andere Regeln zu beeinflussen
|
|
- Einfaches Debugging per `iptables -L ADGUARD_SHIELD`
|
|
|
|
## State-Management (SQLite)
|
|
|
|
Alle Laufzeitdaten werden in einer zentralen SQLite-Datenbank gespeichert:
|
|
|
|
```
|
|
/var/lib/adguard-shield/adguard-shield.db
|
|
```
|
|
|
|
Die Datenbank enthält folgende Tabellen:
|
|
|
|
| Tabelle | Beschreibung |
|
|
|---------|--------------|
|
|
| `active_bans` | Aktive Sperren (IP, Domain, Sperrdauer, Offense-Level, Grund, Quelle, GeoIP) |
|
|
| `offense_tracking` | Offense-Zähler für progressive Sperren (Level, letztes/erstes Vergehen) |
|
|
| `ban_history` | Vollständige Ban-History (alle Sperren und Entsperrungen) |
|
|
| `whitelist_cache` | Cache der aufgelösten externen Whitelist-IPs |
|
|
| `schema_version` | Datenbank-Schema-Version für zukünftige Migrationen |
|
|
|
|
**Vorteile gegenüber Flat-Files:**
|
|
- Schnellere Abfragen, besonders bei vielen aktiven Sperren
|
|
- Atomare Transaktionen — kein Datenverlust bei Stromausfall
|
|
- WAL-Modus für parallelen Lese-/Schreibzugriff
|
|
- Indexierte Suche nach IP, Zeitstempel, Quelle und Aktion
|
|
- Kompakte Speicherung statt tausender Einzeldateien
|
|
|
|
Die zentrale Datenbankbibliothek (`db.sh`) wird von allen Scripts per `source db.sh` eingebunden und stellt typisierte Funktionen für alle Tabellen bereit (z.B. `db_ban_insert`, `db_offense_get_level`, `db_history_add`).
|
|
|
|
### Migration von Flat-Files
|
|
|
|
Beim Update auf die SQLite-Version werden bestehende Flat-File-Daten (`.ban`, `.offenses`, Ban-History-Log, Whitelist-Cache) automatisch in die Datenbank migriert. Die alten Dateien werden als Backup nach `/var/lib/adguard-shield/.backup_pre_sqlite/` verschoben. Die Migration läuft einmalig beim Update und zeigt den Fortschritt im Terminal an.
|
|
|
|
## Dateistruktur nach Installation
|
|
|
|
```
|
|
/opt/adguard-shield/
|
|
├── adguard-shield.sh # Haupt-Monitor-Script
|
|
├── adguard-shield.conf # Konfiguration (chmod 600)
|
|
├── adguard-shield.conf.old # Backup der Konfig nach Update
|
|
├── adguard-shield-watchdog.sh # Watchdog Health-Check-Script
|
|
├── iptables-helper.sh # iptables Verwaltung
|
|
├── 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 # Aufräumen abgelaufener Offense-Zähler (nice 19, idle I/O)
|
|
├── db.sh # SQLite Datenbank-Bibliothek (wird von allen Scripts eingebunden)
|
|
├── unban-expired.sh # Cron-basiertes Entsperren
|
|
└── geoip/ # Auto-Download MaxMind GeoLite2 DB (optional)
|
|
|
|
/etc/systemd/system/
|
|
├── adguard-shield.service # systemd Service (Autostart aktiv)
|
|
├── adguard-shield-watchdog.service # systemd Watchdog-Unit (oneshot)
|
|
└── adguard-shield-watchdog.timer # systemd Timer (alle 5 Min.)
|
|
|
|
/var/lib/adguard-shield/
|
|
├── adguard-shield.db # SQLite-Datenbank (Bans, Offenses, History, Whitelist-Cache)
|
|
├── .migration_v1_complete # Marker: Flat-File-Migration abgeschlossen
|
|
├── .backup_pre_sqlite/ # Backup der alten Flat-Files nach Migration
|
|
├── external-blocklist/ # Cache für externe Blocklisten
|
|
├── external-whitelist/ # Cache für externe Whitelisten
|
|
└── geoip-cache/ # Cache für GeoIP-Lookups (24h)
|
|
|
|
/var/log/
|
|
├── adguard-shield.log # Laufzeit-Log
|
|
└── adguard-shield-bans.log # Ban-History (Legacy, wird nach Migration nicht mehr geschrieben)
|
|
```
|
|
|
|
## Installer-Architektur
|
|
|
|
Der Installer (`install.sh`) bietet ein interaktives Menü und folgende Funktionen:
|
|
|
|
| Befehl | Beschreibung |
|
|
|--------|--------------|
|
|
| `install` | Vollständige Neuinstallation (Abhängigkeiten, Dateien, Konfiguration, Service, Watchdog) |
|
|
| `update` | Update mit automatischer Konfigurations-Migration, Datenbank-Migration, Watchdog-Aktivierung und Service-Neustart |
|
|
| `uninstall` | Deinstallation mit optionalem Behalten der Konfiguration |
|
|
| `status` | Installationsstatus, Version und Service-Status anzeigen |
|
|
| `--help` | Hilfe und Befehlsübersicht |
|
|
|
|
### Konfigurations-Migration beim Update
|
|
|
|
```
|
|
┌─────────────────────────┐ ┌─────────────────────────┐
|
|
│ Bestehende Konfig │ │ Neue Konfig (Repo) │
|
|
│ (Benutzer-Settings) │ │ (mit neuen Parametern) │
|
|
└───────────┬─────────────┘ └───────────┬─────────────┘
|
|
│ │
|
|
▼ ▼
|
|
┌──────────────────────────────────────────┐
|
|
│ Konfigurations-Migration │
|
|
│ 1. Backup als .conf.old erstellen │
|
|
│ 2. Alle Schlüssel vergleichen │
|
|
│ 3. Neue Schlüssel zur Konfig ergänzen │
|
|
│ 4. Bestehende Werte NICHT ändern │
|
|
└──────────────────────┬───────────────────┘
|
|
▼
|
|
┌──────────────────────────┐
|
|
│ Aktualisierte Konfig │
|
|
│ (alte Werte + neue Keys) │
|
|
└──────────────────────────┘
|
|
```
|
|
|
|
## Ban-History
|
|
|
|
Jede Sperre und Entsperrung wird dauerhaft in der SQLite-Datenbank protokolliert (Tabelle `ban_history`). Das ermöglicht eine lückenlose Nachvollziehbarkeit mit indexierter Suche nach IP, Zeitstempel und Aktion.
|
|
|
|
**Gespeicherte Felder pro Eintrag:**
|
|
| Feld | Beschreibung |
|
|
|------|--------------|
|
|
| `timestamp_epoch` | Unix-Zeitstempel |
|
|
| `timestamp_text` | Lesbarer Zeitstempel |
|
|
| `action` | `BAN` oder `UNBAN` |
|
|
| `client_ip` | Betroffene IP-Adresse |
|
|
| `domain` | Angefragte Domain |
|
|
| `count` | Anzahl der Anfragen |
|
|
| `duration` | Sperrdauer |
|
|
| `protocol` | Verwendetes DNS-Protokoll |
|
|
| `reason` | Sperrgrund |
|
|
|
|
**Mögliche Gründe (GRUND-Spalte):**
|
|
| Grund | Bedeutung |
|
|
|-------|----------|
|
|
| `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 |
|
|
| `manual-flush` | Entsperrt durch `flush`-Befehl (alle Sperren aufgehoben) |
|
|
|
|
**History anzeigen:**
|
|
```bash
|
|
sudo /opt/adguard-shield/adguard-shield.sh history # letzte 50
|
|
sudo /opt/adguard-shield/adguard-shield.sh history 200 # letzte 200
|
|
```
|