diff --git a/FETCH_HEAD b/FETCH_HEAD new file mode 100644 index 0000000..e69de29 diff --git a/README.de.md b/README.de.md index a550bf4..c426c2b 100644 --- a/README.de.md +++ b/README.de.md @@ -22,12 +22,12 @@ ## ✨ Features -✅ **Ein-Klick-Installation** - Setup mit einem Befehl -✅ **DNS-Sicherheit** - Pi-hole + Unbound mit DNSSEC -✅ **Netzwerk-Monitoring** - NetAlertX Geräte-Tracking -✅ **API-Monitoring** - Python FastAPI + SQLite -✅ **Produktionsbereit** - Systemd-Hardening & Auto-Restart -✅ **Idempotent** - Sicher mehrfach ausführbar +✅ **Ein-Klick-Installation** – Setup mit einem Befehl +✅ **DNS-Sicherheit** – Pi-hole + Unbound mit DNSSEC +✅ **Netzwerk-Monitoring** – NetAlertX Geräte-Tracking +✅ **API-Monitoring** – Python FastAPI + SQLite +✅ **Produktionsbereit** – Systemd-Hardening & Auto-Restart +✅ **Idempotent** – Sicher mehrfach ausführbar --- @@ -38,7 +38,7 @@ git clone https://github.com/TimInTech/Pi-hole-Unbound-PiAlert-Setup.git cd Pi-hole-Unbound-PiAlert-Setup chmod +x install.sh sudo ./install.sh -``` +```` **Fertig!** 🎉 Ihr kompletter DNS-Sicherheits-Stack läuft jetzt. @@ -46,12 +46,12 @@ sudo ./install.sh ## 🧰 Was installiert wird -| Komponente | Zweck | Zugriff | -|------------|-------|---------| -| **🕳️ Pi-hole** | DNS-Werbeblocker & Web-UI | `http://[ihre-ip]/admin` | -| **🔐 Unbound** | Rekursiver DNS + DNSSEC | `127.0.0.1:5335` | -| **📡 NetAlertX** | Netzwerkgeräte-Monitoring | `http://[ihre-ip]:20211` | -| **🐍 Python API** | Monitoring & Statistik-API | `http://127.0.0.1:8090` | +| Komponente | Zweck | Zugriff | +| ----------------- | --------------------------------- | ------------------------ | +| **🕳️ Pi-hole** | DNS-Werbeblocker & Web-Oberfläche | `http://[ihre-ip]/admin` | +| **🔐 Unbound** | Rekursiver DNS + DNSSEC | `127.0.0.1:5335` | +| **📡 NetAlertX** | Netzwerkgeräte-Monitoring | `http://[ihre-ip]:20211` | +| **🐍 Python API** | Monitoring- & Statistik-API | `http://127.0.0.1:8090` | --- @@ -77,6 +77,7 @@ sudo ./install.sh ``` **Datenfluss:** + 1. **Clients** → Pi-hole (DNS-Filterung) 2. **Pi-hole** → Unbound (rekursive Auflösung) 3. **Unbound** → Root-Server (DNSSEC-Validierung) @@ -87,15 +88,32 @@ sudo ./install.sh ## 🔌 API-Referenz +#### `GET /leases` + +```json +[ + { + "ip": "192.168.1.101", + "mac": "aa:bb:cc:dd:ee:ff", + "hostname": "drucker", + "lease_start": "2024-12-21 10:00:00", + "lease_end": "2024-12-21 12:00:00" + } +] +``` + ### Authentifizierung -Alle Endpunkte benötigen `X-API-Key`-Header: + +Alle Endpunkte benötigen den `X-API-Key`-Header: + ```bash -curl -H "X-API-Key: ihr-api-key" http://127.0.0.1:8090/endpoint +curl -H "X-API-Key: $SUITE_API_KEY" http://127.0.0.1:8090/endpoint ``` ### Endpunkte #### `GET /health` + ```json { "ok": true, @@ -105,6 +123,7 @@ curl -H "X-API-Key: ihr-api-key" http://127.0.0.1:8090/endpoint ``` #### `GET /dns?limit=50` + ```json [ { @@ -117,6 +136,7 @@ curl -H "X-API-Key: ihr-api-key" http://127.0.0.1:8090/endpoint ``` #### `GET /devices` + ```json [ { @@ -130,6 +150,7 @@ curl -H "X-API-Key: ihr-api-key" http://127.0.0.1:8090/endpoint ``` #### `GET /stats` + ```json { "total_dns_logs": 1250, @@ -143,21 +164,24 @@ curl -H "X-API-Key: ihr-api-key" http://127.0.0.1:8090/endpoint ## 🛠️ Manuelle Schritte (Optional) ### Pi-hole-Konfiguration -1. Admin-Interface aufrufen: `http://[ihre-ip]/admin` + +1. Admin-Oberfläche aufrufen: `http://[ihre-ip]/admin` 2. **Einstellungen → DNS** navigieren -3. **Custom upstream** prüfen: `127.0.0.1#5335` -4. Geräte konfigurieren, um Pi-hole als DNS-Server zu verwenden +3. **Custom Upstream** setzen: `127.0.0.1#5335` +4. Geräte im Netzwerk konfigurieren, um Pi-hole als DNS-Server zu nutzen ### NetAlertX-Setup -- Dashboard aufrufen: `http://[ihre-ip]:20211` -- Scan-Zeitpläne und Benachrichtigungen konfigurieren -- Netzwerk-Topologie und Geräteliste überprüfen + +* Dashboard aufrufen: `http://[ihre-ip]:20211` +* Scan-Zeitpläne und Benachrichtigungen konfigurieren +* Netzwerk-Topologie und Geräteliste prüfen --- ## 🧪 Gesundheitschecks & Problembehandlung ### Schneller Gesundheitscheck + ```bash # Unbound testen dig @127.0.0.1 -p 5335 example.com @@ -173,6 +197,7 @@ curl -H "X-API-Key: $SUITE_API_KEY" http://127.0.0.1:8090/health ``` ### Service-Verwaltung + ```bash # Services prüfen systemctl status pihole-suite unbound pihole-FTL @@ -190,32 +215,35 @@ docker restart netalertx ### Häufige Probleme -| Problem | Lösung | -|---------|--------| -| **Port 53 belegt** | `sudo systemctl stop systemd-resolved` | -| **API-Key fehlt** | `.env`-Datei prüfen oder mit Installer neu generieren | -| **Datenbankfehler** | `python scripts/bootstrap.py` ausführen | -| **Unbound startet nicht** | `/etc/unbound/unbound.conf.d/pi-hole.conf` prüfen | +| Problem | Lösung | +| ------------------------- | -------------------------------------------------------------------------------------------- | +| **Port 53 belegt** | `sudo systemctl stop systemd-resolved` *(ggf. dauerhaft: disable + /etc/resolv.conf prüfen)* | +| **API-Key fehlt** | `.env`-Datei prüfen oder mit Installer neu generieren | +| **Datenbankfehler** | `python scripts/bootstrap.py` ausführen | +| **Unbound startet nicht** | `/etc/unbound/unbound.conf.d/pi-hole.conf` prüfen | --- ## 🧯 Sicherheitshinweise ### 🔐 API-Sicherheit -- **API-Keys** werden automatisch generiert (16-Byte Hex) -- **CORS** nur für localhost aktiviert -- **Authentifizierung** für alle Endpunkte erforderlich + +* **API-Keys** werden automatisch generiert (16-Byte Hex) +* **CORS** nur für localhost aktiviert +* **Authentifizierung** für alle Endpunkte erforderlich ### 🛡️ Systemd-Hardening -- **NoNewPrivileges** verhindert Rechte-Eskalation -- **ProtectSystem=strict** Schreibschutz für Dateisystem -- **PrivateTmp** isolierte temporäre Verzeichnisse -- **Memory-Limits** verhindern Ressourcen-Erschöpfung + +* `NoNewPrivileges` verhindert Rechte-Eskalation +* `ProtectSystem=strict` schützt das Dateisystem +* `PrivateTmp` isoliert temporäre Verzeichnisse +* Speicherlimits verhindern Ressourcenüberlastung ### 🔒 Netzwerk-Sicherheit -- **Unbound** nur auf localhost (nicht exponiert) -- **DNS über TLS** zu Upstream-Resolvern -- **DNSSEC**-Validierung aktiviert + +* **Unbound** lauscht nur auf `localhost` +* DNS über TLS zu Upstream-Resolvern +* DNSSEC-Validierung ist aktiviert --- @@ -231,19 +259,19 @@ docker restart netalertx ## 📜 Lizenz -Dieses Projekt ist unter der **MIT-Lizenz** lizenziert - siehe [LICENSE](LICENSE)-Datei. +Dieses Projekt ist unter der **MIT-Lizenz** lizenziert – siehe [LICENSE](LICENSE)-Datei. --- ## 📈 Changelog -Siehe [CHANGELOG.md](CHANGELOG.md) für Versionshistorie und Updates. +Siehe [CHANGELOG.md](CHANGELOG.md) für Versionsverlauf und Updates. ---
-**Mit ❤️ für die Pi-hole-Community erstellt** +**Mit ❤️ für die Pi-hole-Community entwickelt** [🐛 Bug melden](https://github.com/TimInTech/Pi-hole-Unbound-PiAlert-Setup/issues) • [✨ Feature anfordern](https://github.com/TimInTech/Pi-hole-Unbound-PiAlert-Setup/issues) • diff --git a/install.sh b/install.sh index 7efdb6e..ed78208 100755 --- a/install.sh +++ b/install.sh @@ -9,10 +9,6 @@ set -euo pipefail readonly UNBOUND_PORT=5335 readonly NETALERTX_PORT=20211 readonly PYTHON_SUITE_PORT=8090 -readonly NETALERTX_IMAGE="techxartisan/netalertx:latest" -readonly SUITE_API_KEY=${SUITE_API_KEY:-$(openssl rand -hex 16)} -readonly INSTALL_USER=${SUDO_USER:-$(whoami)} -readonly INSTALL_HOME=$(getent passwd "$INSTALL_USER" | cut -d: -f6) readonly PROJECT_DIR="$(pwd)" # 🎨 Colors @@ -38,7 +34,6 @@ check_system() { success "System checks passed" } -# 🔌 Port conflicts check_ports() { step "Checking ports" local ports=($UNBOUND_PORT $NETALERTX_PORT $PYTHON_SUITE_PORT 53) @@ -53,7 +48,6 @@ check_ports() { install_packages() { step "Installing system packages" apt-get update -qq - apt-get install -y unbound unbound-anchor ca-certificates curl dnsutils \ python3 python3-venv python3-pip git docker.io openssl systemd sqlite3 success "System packages installed" } @@ -87,6 +81,7 @@ forward-zone: forward-tls-upstream: yes forward-addr: 9.9.9.9@853#dns.quad9.net forward-addr: 149.112.112.112@853#dns.quad9.net +# NOTE: This is DoT forwarding to Quad9 (not full recursion to the root); intended. EOF unbound-anchor -a /var/lib/unbound/root.key || true @@ -174,7 +169,6 @@ ENV run_health_checks() { step "Running health checks" dig +short @127.0.0.1 -p $UNBOUND_PORT example.com | grep -q "." && success "Unbound OK" || error "Unbound FAIL" - pihole status | grep -q "blocking is enabled" && success "Pi-hole OK" || warn "Pi-hole status unclear" docker ps | grep -q netalertx && success "NetAlertX OK" || warn "NetAlertX missing" systemctl is-active --quiet pihole-suite && success "Python suite OK" || warn "Python suite not active" } @@ -195,6 +189,7 @@ main() { check_ports install_packages configure_unbound + handle_systemd_resolved install_pihole install_netalertx setup_python_suite diff --git a/pyalloc/allocator.py b/pyalloc/allocator.py index 02ce2ab..bbcfa32 100644 --- a/pyalloc/allocator.py +++ b/pyalloc/allocator.py @@ -4,10 +4,6 @@ import logging import threading from typing import Set -"""Simple IP pool allocator.""" -import ipaddress -import logging -import threading logger = logging.getLogger(__name__) @@ -31,16 +27,10 @@ def allocate(self) -> str: Returns: String IP address - + Raises: RuntimeError: If no IPs available """ - def __init__(self, network: str): - self.network = ipaddress.ip_network(network) - self.lock = threading.Lock() - self.allocated = set() - - def allocate(self) -> str: with self.lock: for ip in self.network.hosts(): ip_str = str(ip) @@ -95,12 +85,3 @@ def get_stats(self) -> dict: "available": total_hosts - allocated_count, "utilization_percent": (allocated_count / total_hosts) * 100 if total_hosts > 0 else 0 } - logger.info("Allocated IP %s", ip_str) - return ip_str - raise RuntimeError("No free IP addresses") - - def release(self, ip: str) -> None: - with self.lock: - if ip in self.allocated: - self.allocated.remove(ip) - logger.info("Released IP %s", ip) diff --git a/pyalloc/main.py b/pyalloc/main.py index 7cf1aea..a9b9c00 100644 --- a/pyalloc/main.py +++ b/pyalloc/main.py @@ -3,11 +3,8 @@ import logging import sqlite3 import threading -from typing import Optional -"""Placeholder IP allocator worker.""" -import logging -import threading import time +from typing import Optional from .allocator import IPPool @@ -101,25 +98,3 @@ def stop() -> None: def get_pool() -> Optional[IPPool]: """Get the current IP pool instance (for demo/testing).""" return _pool -_pool = None -_stop_event = threading.Event() - - -def start(conn, network: str = "192.168.0.0/24"): - del conn # not used yet - global _pool - _pool = IPPool(network) - logger.info("Starting IP allocator for %s", network) - _stop_event.clear() - thread = threading.Thread(target=_run, daemon=True) - thread.start() - return thread - - -def _run() -> None: - while not _stop_event.is_set(): - time.sleep(60) - - -def stop() -> None: - _stop_event.set() diff --git a/shared/shared_config.py b/shared/shared_config.py index 83a9a1e..809b413 100644 --- a/shared/shared_config.py +++ b/shared/shared_config.py @@ -1,6 +1,4 @@ """Shared configuration for the Pi-hole suite.""" - -""" import logging import os from pathlib import Path