rpi/pihole/updatePihole.sh

348 lines
14 KiB
Bash
Executable File

#!/bin/bash
# Script: updatePihole.sh - https://github.com/Zelo72/rpi (/pihole/)
#
# Beschreibung: Das Script aktualisiert bei jedem Lauf die Pi-hole Gravity auf Basis der in Pi-hole
# konfigurierten Blocklisten. Zusaetzlich werden, wenn das Script an einem Sonntag ausgefuehrt
# wird, Raspberry Paketupdates simuliert.
# Bei Bedarf wird ein Gravity-Update Bericht als Mail versendet. Dieser beinhaltet neben einem Pi-Hole
# Gesundheitstatus auch die Statistik für das Pi-Hole und Gravity Update.
# Das Script ist mit Pi-hole 4.x und 5.x kompatibel.
#
# Aufruf: sudo ./updatePihole.sh name@domain.xy <-- mit Mailversand
# sudo ./updatePihole.sh <-- ohne Mailversand
#
# Ausgabedateien: /var/log/pihole/Ymd_updatePihole.sh.log --> taegliches Logfile
# /var/log/pihole/updatePihole.stats.log --> Pi-hole Gravity Update Bericht/Statistik
# /var/var/log/pihole/updatePihole.cron.log --> Logifile des Cron-Jobs
#
# Installation: 1. Script downloaden:
# wget -N https://raw.githubusercontent.com/Zelo72/rpi/master/pihole/updatePihole.sh
# 2. Script mittels sudo chmod +x updatePihole.sh ausführbar machen.
#
# Installation: 1. Script mittels sudo cp updatePihole.sh /root nach /root kopieren.
# (als Cron-Job) 2. Script mittels sudo chmod +x /root/updatePihole.sh ausfuehrbar machen.
# 3. Cron-Job mit sudo crontab -e erstellen
# Am Ende der Datei z.B. folgendes einfuegen um das Script taeglich um 03:00 Uhr zu starten
# und eine Mail mit dem Gravity Update Bericht an "name@domain.xy" zu schicken:
#
# 0 3 * * * /root/updatePihole.sh name@domain.xy > /var/log/pihole/updatePihole.cron.log 2>&1
#
# 4. Datei speichern und schliessen. (im nano Editor: Strg+o/Enter/Strg+x).
#
# -------
# :HINWEIS: Damit der Mailversand funktioniert, muss msmtp und mailutils installiert und konfiguriert
# ------- sein. Eine Anleitung dazu ist hier zu finden:
# https://github.com/Zelo72/rpi/blob/master/tutorials/Mailversand-RPi-einrichten.md
#
# Versionshistorie:
# Version 1.0.0 - [Zelo72] - initiale Version
# 1.0.1 - [Zelo72/AleksCee] - Umstellung von wc -l auf grep -Evc '^#|^$' um auskommentierte und leere Zeilen
# beim Zählen herauszufiltern.
# - Damit die Mail mit dem Abschlussbericht nicht vom Mailserver des Empfaengers
# als Spam eingestuft wird, wurde die Ausgabe der Top 50 hinzugefuegten und
# geloeschten Domains auskommentiert.
# - Gesundheitsstatus von JA/NEIN/UNDEFINIERT auf OK/FEHLER/NICHT DURCHGEFUEHRT
# umgestellt.
# - Von Gesamtlogfile auf taegliche Logs umgestellt
# - Delimiter in der Ausgabe entfernt
# 1.0.2 - [Zelo72/AleksCee] - n Sekunden warten bevor der DNS Check nach dem Pi-hole Update durchgefuehrt
# wird. Der Pi-Hole DNS Service braucht manchmal etwas bis er verfuegbar ist.
# - Versuch von RestartDNS wenn der DNS Service nach dem Pi-hole Update nicht
# mehr reagiert.
# - Möglicher Fehler Exitcode 127 bei Aufruf des pihole binaries aus einem Cron
# Job heraus behoben: von pihole -u/-g auf /usr/local/bin/pihole ... umgestellt.
# 1.0.3 - [Zelo72] - Beschreibung, Aufruf, Ausgabedateien und Installation beschrieben.
# 1.0.4 - [Zelo72] - Logverzeichnis bereinigen, Logs aelter als 7 Tage werden geloescht.
# 1.0.5 - [Zelo72/AleksCee] - Logbereinigung von Minuten auf Tage umgestellt und Unterscheidung zwischen
# Startpunkt und Suchmuster
# 1.0.6 - [Zelo72] - Gravity Update Bericht erweitert: Hostname, CPU Temperatur, RAM Nutzung,
# HDD Nutzung, Pi-hole Status (aktiv/offline)
# - Fehler behoben: Nach waitfordns und anschliessend fehlgeschlagenem DNS-Test
# wurde der Code im If-Zweig zum erneuten DNS-Test nicht
# ausgefuehrt.
# 1.0.7 - [Zelo72] - Kompatiblitaet fuer Pihole 5.x
# 1.0.8 - [Zelo72] - Auf Update nur simulieren nicht automatisch durchführen umgestellt.
# Betrifft Raspberry Pakete und das Pi-hole Softwareupdate.
# 1.0.9 - [Zelo72] - Lokalen Blocklisten-Cache vor Gravity-Update bereinigen.
# 1.1.0 - [Zelo72] - Internetverbindungs-/DNS-Test um Cloudflare erweitert.
#
# Prüfen ob das Script als root ausgefuehrt wird
if [ "$(id -u)" != "0" ]; then
echo "Das Script muss mit Rootrechten ausgeführt werden!"
exit 1
fi
# *** Initialisierung ***
# Logging initialisieren
logDir=/var/log/pihole
log=$logDir/$(date +'%Y%m%d')_updatePihole.sh.log
mkdir -p $logDir
# Hilfsfunktion zum loggen
writeLog() {
echo -e "[$(date +'%Y.%m.%d-%H:%M:%S')]" "$*" | tee -a "$log"
}
writeLog "[I] Start | Logfile: $log"
# Tempverzeichnis initialisieren
tmp=/tmp/pihole
writeLog "[I] Initialisiere Tempverzeichnis $tmp ..."
mkdir -p $tmp
cd $tmp || exit
# Logverzeichnis bereinigen, Logs aelter als 7 Tage werden geloescht.
writeLog "[I] Bereinige Logverzeichnis $logDir ..."
find $logDir -daystart -type f -mtime +7 -name \*updatePihole\*.log -exec rm -v {} \;
writeLog "[I] Logverzeichnis $logDir bereinigt."
# Variablen fuer Dateien
piholeDir=/etc/pihole
piholeBinDir=/usr/local/bin
gravityDB=$piholeDir/gravity.db
gravListPihole=$piholeDir/gravity.list
gravListBeforeUpdate=$tmp/gravity_before_update.list
gravListDiff=$tmp/gravity_diff.list
logStats=$logDir/updatePihole.stats.log
# Pihole 5.x?
[ -f $gravityDB ] && pihole5=1 || pihole5=0
# Variablen fuer "Gesundheitsstatus": -1: Undefiniert / 0: true / >0: false
rpiUpdateStatus=-1
piholeGravUpdateStatus=-1
dnsTestStatus=-1
inetTestStatus=-1
# *** Hilfsfunktionen ***
status() {
case "$*" in
-3)
echo "|> UPDATES VERFUEGBAR! <|"
;;
-2)
echo "KEINE UPDATES VERFUEGBAR"
;;
-1)
echo "NICHT UEBERPRUEFT"
;;
0)
echo "OK"
;;
1 | *)
echo "FEHLER #Exitcode:$*"
;;
esac
}
# Internetverbindung testen
checkinet() {
writeLog "[I] Teste Internetverbindung ..."
if ! (ping -c1 -w1 8.8.8.8 >/dev/null) && ! (ping -c1 -w1 1.1.1.1 >/dev/null); then
writeLog "[E] Keine Internetverbindung! Das Script wird beendet!"
inetTestStatus=1
exit 1
fi
writeLog "[I] Internetverbindungstest erfolgreich."
inetTestStatus=0
return 0
}
# DNS-Namensaufloesung testen
checkdns() {
writeLog "[I] Teste DNS Namensaufloesung ..."
if ! (ping -c1 -w2 google.de >/dev/null) && ! (ping -c1 -w2 cloudflare.com >/dev/null); then
writeLog "[E] Keine DNS Namensaufloesung moeglich!"
dnsTestStatus=1
return 1
fi
writeLog "[I] DNS Namensaufloesung erfolgreich."
dnsTestStatus=0
return 0
}
# Auf DNS Service warten
waitfordns() {
writeLog "[I] Warte $1 Sek. auf DNS Service ..."
sleep "$1"
}
# *** Pi-hole Update ***
# Internetverbindung / DNS testen
checkinet # besteht keine Internetverbindung wird das Script mit exitcode 1 beendet
checkdns
# Nur wenn dieses Script Sonntags am Wochentag 0 ausgeführt wird:
# das Raspberry Paket Update simulieren.
if test "$(date "+%w")" -eq 0; then # Sonntags = Wochentag 0
# Raspberry Paketequellen updaten
writeLog "[I] Raspberry Paket Update simulieren ..."
echo ""
apt-get update
echo ""
# Raspberry Paketupdate simulieren
writeLog "[I] Ermitteln ob Paketupdates vorliegen ..."
tst=$(apt-get --simulate upgrade | grep ^Inst)
[ -n "$tst" ] && rpiUpdateStatus=-3 || rpiUpdateStatus=-2
# Raspberry Pakete bereinigen
writeLog "[I] Raspberry Pakete bereinigen ..."
echo ""
apt-get -y autoremove
apt-get -y clean
echo ""
fi
# *** Pi-hole Gravity Update ***
# AKtuelle Gravity Liste vom Pi-hole zwischenspeichern und
# Pi-hole Gravity aktualisieren
# Kompatiblitaet fuer Pihole 5.x
if [ "$pihole5" -eq 1 ]; then
writeLog "[I] Exportiere Domains aus $gravityDB nach $gravListBeforeUpdate ..."
sqlite3 "$gravityDB" "select distinct domain from gravity;" >$gravListBeforeUpdate
else
writeLog "[I] Kopiere $gravListPihole nach $gravListBeforeUpdate ..."
cp $gravListPihole $gravListBeforeUpdate
fi
writeLog "[I] Bereinge lokalen Pi-hole Blocklisten-Cache ..."
echo ""
ls $piholeDir/list.*.domains
rm $piholeDir/list.*.domains
echo ""
writeLog "[I] Aktualisiere Pi-hole Gravity ..."
echo ""
$piholeBinDir/pihole -g # Pi-hole Gravity aktualisieren
piholeGravUpdateStatus=$?
echo ""
writeLog "[I] Pi-hole Gravity Update exitcode: $piholeGravUpdateStatus"
# DNS nach Gravity Update testen
[ "$pihole5" -eq 0 ] && waitfordns 30 #waitfordns nach pihole -g nur bei Pihole Versionen < 5.x notwendig
if ! checkdns; then
waitfordns 30
if ! checkdns; then
writeLog "[E] Pi-hole DNS Service reagiert nicht, versuche RestartDNS ..."
$piholeBinDir/pihole restartdns
waitfordns 90
checkdns
fi
fi
# Aktualisierte Pi-hole Gravityliste mit Gravityliste vor der Aktualisierung
# vergleichen und Aenderungen (hinzugefuegte/geloeschte Eintraege) in
# $gravListDiff Datei zur weiteren Auswertung speichern
writeLog "[I] Erstelle Aenderungs-Gravityliste $gravListDiff ..."
# Kompatiblitaet fuer Pihole 5.x
if [ "$pihole5" -eq 1 ]; then
writeLog "[I] Exportiere Domains aus $gravityDB nach $tmp/gravity.list ..."
sqlite3 "$gravityDB" "select distinct domain from gravity;" >$tmp/gravity.list
gravListPihole=$tmp/gravity.list
fi
diff $gravListPihole $gravListBeforeUpdate | grep '[><]' >$gravListDiff
writeLog "[I] Aenderungs-Gravityliste mit $(grep -Evc '^#|^$' $gravListDiff) Eintraegen erstellt."
# *** Pi-hole Gravity Update Bericht/Statistik ***
# Id für Pi-hole Gravity Update Bericht erzeugen
id=$(date +"%Y.%m.%d-%H%M%S")
# Ermittle Pi-hole Status
if [[ "$($piholeBinDir/pihole status web 2>/dev/null)" == "1" ]]; then
phStatus="AKTIV"
else
phStatus="OFFLINE!"
fi
# Kompatiblitaet fuer Pihole 5.x
if [ "$pihole5" -eq 1 ]; then
writeLog "[I] Exportiere Blacklist, RegExlisten, Whitelist und Adlists aus $gravityDB nach $tmp ..."
sqlite3 "$gravityDB" "select domain from vw_blacklist;" >$tmp/blacklist.txt
blacklist=$tmp/blacklist.txt
sqlite3 "$gravityDB" "select domain from vw_regex_blacklist;" >$tmp/regex_blacklist.txt
regexblacklist=$tmp/regex_blacklist.txt
sqlite3 "$gravityDB" "select domain from vw_regex_whitelist;" >$tmp/regex_whitelist.txt
regexwhitelist=$tmp/regex_whitelist.txt
sqlite3 "$gravityDB" "select domain from vw_whitelist;" >$tmp/whitelist.txt
whitelist=$tmp/whitelist.txt
sqlite3 "$gravityDB" "select address from vw_adlist;" >$tmp/adlists.txt
adlists=$tmp/adlists.txt
else
blacklist=$piholeDir/blacklist.txt
regexblacklist=$piholeDir/regex.list
whitelist=$piholeDir/whitelist.txt
adlists=$piholeDir/adlists.list
fi
# Gravity Update Bericht erzeugen und in die unter $logStats angegebene Datei schreiben.
writeLog "[I] Erstelle Pi-hole Gravity Update Bericht/Statistik $id ..."
echo ""
(
echo "# Raspberry Info #"
echo ""
echo "Hostname: $(hostname)"
echo "RAM Nutzung: $(awk '/^Mem/ {printf("%.2f%%", 100*($2-$4-$6)/$2);}' <(free -m))"
echo "HDD Nutzung: $(df -B1 / 2>/dev/null | awk 'END{ print $5 }')"
echo "Paket Updates?: $(status $rpiUpdateStatus)"
echo ""
echo "# Pi-hole Info #"
echo ""
echo "Pi-hole Status: $phStatus"
echo "Internet: $(status $inetTestStatus)"
echo "DNS-Test: $(status $dnsTestStatus)"
echo "Gravity Update: $(status $piholeGravUpdateStatus)"
echo ""
echo "# Pi-hole Update Status #"
echo ""
$piholeBinDir/pihole -up --check-only
echo ""
echo "# Pi-hole Statistik #"
echo ""
echo "Domains Gravitylist: $(grep -Evc '^#|^$' $gravListPihole)"
echo "Domains Blacklist: $(grep -Evc '^#|^$' $blacklist)"
echo "RegEx Blacklist: $(grep -Evc '^#|^$' $regexblacklist)"
echo "Domains Whitelist: $(grep -Evc '^#|^$' $whitelist)"
# Kompatiblitaet fuer Pihole 5.x
if [ "$pihole5" -eq 1 ]; then
echo "RegEx Whitelist: $(grep -Evc '^#|^$' $regexwhitelist)"
fi
echo "Aktive Blocklisten: $(grep -Evc '^#|^$' $adlists)"
echo ""
echo "# Pi-hole Gravity Updatestatistik #"
echo ""
echo "(+): $(grep -c '<' $gravListDiff) Domains hinzugefuegt"
echo "(-): $(grep -c '>' $gravListDiff) Domains geloescht"
echo "(S): $(grep -Evc '^#|^$' $gravListDiff) Domains geaendert"
) | tee $logStats #Ausgaben innerhalb von () in die $logStats Datei schreiben
echo ""
writeLog "[I] Pi-hole Gravity Update Bericht/Statistik $logStats erstellt."
# *** E-Mail Versand des Update Berichtes ***
# Aufrufparameter 1: sudo ./updatePihole.sh name@domain.xy
email="$1"
# Mail mit Gravity Update Bericht wird nur versendet wenn beim Aufruf des Scriptes eine
# Mailadresse mit uebergeben wurde!
if [ -n "$email" ]; then
writeLog "[I] E-Mail Pi-hole Gravity Update Bericht $id wird an $email versendet ..."
mail <$logStats -s "Pi-hole Gravity Update Bericht $id" "$email"
# Pruefen ob der E-Mailversand fehlgeschlagen ist
if [ $? -ne 0 ]; then
writeLog "[E] E-Mailversand an $email fehlgeschlagen!"
else
writeLog "[I] E-Mailversand an $email erfolgreich."
fi
fi
# Temp-Verzeihnis bereinigen
writeLog "[I] Bereinige $tmp"
rm -rf $tmp
writeLog "[I] Ende | Logfile: $log"