initial
This commit is contained in:
parent
438ad74707
commit
368f182ae5
30
README.md
30
README.md
@ -1,9 +1,33 @@
|
||||
# template_repository
|
||||
# DNS-Watch
|
||||
|
||||
Ein Bash-Skript zur Überwachung von DNS-Einträgen (A/AAAA-Records) für definierte Hosts.
|
||||
Bei Änderungen werden Benachrichtigungen per **E-Mail** und/oder **ntfy** ausgelöst.
|
||||
|
||||
## Features
|
||||
|
||||
Wichtig: Link für Lizenz anpassen.
|
||||
- Überwachung beliebiger Hosts und Subdomains
|
||||
- Unterstützung für **A**- und **AAAA**-Records
|
||||
- Speicherung des letzten Zustands zur Erkennung von Änderungen
|
||||
- Benachrichtigung:
|
||||
- **Mail** (konfigurierbar)
|
||||
- **ntfy** mit **Bearer Token Auth**
|
||||
- Logging & Lockfile (verhindert parallele Läufe)
|
||||
- Konfigurierbar über Variablen im Skript
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- `bash` (>= 4.0)
|
||||
- `dig` (meist im Paket `dnsutils` oder `bind9-dnsutils`)
|
||||
- `curl` (für ntfy)
|
||||
- `mail`-Binary (z. B. via `mailutils` oder `msmtp-mta`) – nur falls Mail genutzt wird
|
||||
|
||||
## Installation
|
||||
|
||||
1. Skript ins System legen:
|
||||
```bash
|
||||
sudo cp dns-watch.sh /usr/local/bin/dns-watch.sh
|
||||
sudo chmod +x /usr/local/bin/dns-watch.sh
|
||||
```
|
||||
|
||||
|
||||
<p align="center">
|
||||
@ -11,5 +35,5 @@ Wichtig: Link für Lizenz anpassen.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://assets.techniverse.net/f1/logos/small/license.png" alt="License" width="15" height="15"> <a href="./template_repository/src/branch/main/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="Matrix" width="15" height="15"> <a href="https://social.techniverse.net/@donnerwolke">Mastodon</a>
|
||||
<img src="https://assets.techniverse.net/f1/logos/small/license.png" alt="License" width="15" height="15"> <a href="./dns-watch/src/branch/main/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="Matrix" width="15" height="15"> <a href="https://social.techniverse.net/@donnerwolke">Mastodon</a>
|
||||
</p>
|
277
dns-watch.v1.sh
Normal file
277
dns-watch.v1.sh
Normal file
@ -0,0 +1,277 @@
|
||||
#!/usr/bin/env bash
|
||||
# Script Name: dns-watch.v1.sh
|
||||
# Beschreibung: Überwacht A/AAAA DNS-Records für definierte Hosts und meldet Änderungen per Mail und/oder ntfy.
|
||||
# Autor: Patrick Asmus
|
||||
# Web: https://www.cleveradmin.de
|
||||
# Git-Reposit.: https://git.techniverse.net/scriptos/dns-watch
|
||||
# Version: 1.0
|
||||
# Datum: 18.08.2025
|
||||
# Modifikation: Initial
|
||||
#####################################################
|
||||
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
#####################################
|
||||
# KONFIG #
|
||||
#####################################
|
||||
|
||||
# Liste der zu überwachenden Hosts
|
||||
HOSTS=(
|
||||
"domain.com"
|
||||
"sub.domain.com"
|
||||
)
|
||||
|
||||
# Welche Record-Typen prüfen?
|
||||
RECORD_TYPES=("A" "AAAA")
|
||||
|
||||
# Optional: Eigener DNS-Resolver (leer = System-Resolver)
|
||||
# Beispielformat: "1.1.1.1" oder "9.9.9.9"
|
||||
DNS_RESOLVER="1.1.1.1"
|
||||
|
||||
# Zustandsablage (wird automatisch erstellt)
|
||||
STATE_DIR="./states"
|
||||
# Logdatei (optional; leer lassen, wenn nur stdout)
|
||||
LOG_FILE="/var/log/dns-watch.log"
|
||||
|
||||
# --- Benachrichtigungen ---
|
||||
# Mail
|
||||
MAIL_ENABLED=false
|
||||
MAIL_TO=""
|
||||
MAIL_FROM=""
|
||||
MAIL_SUBJECT_PREFIX="[DNS-Watch]"
|
||||
MAIL_BIN="${MAIL_BIN:-/usr/bin/mail}" # /usr/bin/mail (bsd-mailx / mailutils / msmtp-mta)
|
||||
|
||||
# ntfy
|
||||
NTFY_ENABLED=true
|
||||
NTFY_SERVER="https://ntfy.sh"
|
||||
NTFY_TOPIC="dns-watch"
|
||||
NTFY_TOKEN=""
|
||||
NTFY_TITLE_PREFIX="[DNS-Watch]"
|
||||
NTFY_PRIORITY="default" # options: min|low|default|high|max
|
||||
NTFY_TAGS="satellite" # Komma-getrennt, z. B. "satellite,dns,warning"
|
||||
|
||||
# Lockfile gegen Parallelstarts
|
||||
LOCK_FILE="/tmp/dns-watch.lock"
|
||||
|
||||
#####################################
|
||||
# HILFSFUNKTIONEN #
|
||||
#####################################
|
||||
|
||||
log() {
|
||||
local ts
|
||||
ts="$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
local line="[$ts] $*"
|
||||
if [[ -n "${LOG_FILE}" ]]; then
|
||||
echo "${line}" >> "${LOG_FILE}"
|
||||
else
|
||||
echo "${line}"
|
||||
fi
|
||||
}
|
||||
|
||||
with_lock() {
|
||||
exec 9>"${LOCK_FILE}"
|
||||
if ! flock -n 9; then
|
||||
log "Bereits laufende Instanz erkannt. Beende."
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_dirs() {
|
||||
mkdir -p "${STATE_DIR}"
|
||||
if [[ -n "${LOG_FILE}" ]]; then
|
||||
mkdir -p "$(dirname "${LOG_FILE}")"
|
||||
touch "${LOG_FILE}"
|
||||
fi
|
||||
}
|
||||
|
||||
# DNS-Abfrage für Host/Typ, gibt sortierte, eindeutige Liste (zeilenweise) zurück.
|
||||
resolve_records() {
|
||||
local host="$1"
|
||||
local rtype="$2"
|
||||
|
||||
local dig_args=("+short" "${host}" "${rtype}")
|
||||
if [[ -n "${DNS_RESOLVER}" ]]; then
|
||||
dig_args=("@${DNS_RESOLVER}" "${host}" "${rtype}" "+short")
|
||||
fi
|
||||
|
||||
# Ausführen, IPv4/IPv6-Adressen filtern, sortieren, eindeutige Einträge
|
||||
local out
|
||||
if ! out="$(dig "${dig_args[@]}" 2>/dev/null | sed 's/\s\+$//' | grep -E '^[0-9a-fA-F:\.]+$' || true)"; then
|
||||
out=""
|
||||
fi
|
||||
|
||||
if [[ -z "${out}" ]]; then
|
||||
# Als Platzhalter "EMPTY" speichern, damit Änderungen erkennbar sind
|
||||
echo "EMPTY"
|
||||
else
|
||||
# Sortierte, eindeutige Liste
|
||||
echo "${out}" | sort -u
|
||||
fi
|
||||
}
|
||||
|
||||
# Zustandspfad für Host/Typ
|
||||
state_file_path() {
|
||||
local host="$1"
|
||||
local rtype="$2"
|
||||
local safe_host
|
||||
safe_host="$(echo -n "${host}" | tr '/:@' '___')"
|
||||
echo "${STATE_DIR}/${safe_host}__${rtype}.state"
|
||||
}
|
||||
|
||||
# Vergleicht Alt/Neu; gibt 0 zurück, wenn identisch
|
||||
compare_sets() {
|
||||
local old_file="$1"
|
||||
local tmp_new="$2"
|
||||
|
||||
# Falls kein Altzustand existiert, als Unterschied werten
|
||||
if [[ ! -s "${old_file}" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# diff -q gibt 0 zurück, wenn gleich; sonst != 0
|
||||
if diff -q "${old_file}" "${tmp_new}" >/dev/null 2>&1; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#####################################
|
||||
# BENACHRICHTIGUNGEN #
|
||||
#####################################
|
||||
|
||||
notify_mail() {
|
||||
# usage: notify_mail "Betreff" "Nachrichtentext"
|
||||
local subject="$1"
|
||||
local body="$2"
|
||||
|
||||
if [[ "${MAIL_ENABLED}" != "true" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ ! -x "${MAIL_BIN}" ]]; then
|
||||
log "WARN: ${MAIL_BIN} nicht gefunden/ausführbar, Mailbenachrichtigung übersprungen."
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Versuch über -a "From:" Header (bei mailutils/bsd-mailx/msmtp-mta häufig verfügbar)
|
||||
{
|
||||
echo -e "${body}"
|
||||
} | "${MAIL_BIN}" -a "From: ${MAIL_FROM}" -s "${MAIL_SUBJECT_PREFIX} ${subject}" "${MAIL_TO}" || {
|
||||
log "WARN: Mailversand fehlgeschlagen."
|
||||
}
|
||||
}
|
||||
|
||||
notify_ntfy() {
|
||||
# usage: notify_ntfy "Titel" "Body" "priority" "tags"
|
||||
local title="$1"
|
||||
local body="$2"
|
||||
local prio="${3:-${NTFY_PRIORITY}}"
|
||||
local tags="${4:-${NTFY_TAGS}}"
|
||||
|
||||
if [[ "${NTFY_ENABLED}" != "true" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -z "${NTFY_SERVER}" || -z "${NTFY_TOPIC}" ]]; then
|
||||
log "WARN: ntfy SERVER/TOPIC nicht gesetzt, ntfy-Notify übersprungen."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local url="${NTFY_SERVER%/}/${NTFY_TOPIC}"
|
||||
|
||||
# Headers:
|
||||
# Title: Betreffzeile
|
||||
# Priority: min|low|default|high|max
|
||||
# Tags: emoji/labels (kommagetrennt)
|
||||
# Authorization: Bearer <token>
|
||||
local auth_header=()
|
||||
if [[ -n "${NTFY_TOKEN}" && "${NTFY_TOKEN}" != "PLACE_YOUR_NTFY_API_TOKEN_HERE" ]]; then
|
||||
auth_header=(-H "Authorization: Bearer ${NTFY_TOKEN}")
|
||||
fi
|
||||
|
||||
curl -sS -X POST \
|
||||
-H "Title: ${NTFY_TITLE_PREFIX} ${title}" \
|
||||
-H "Priority: ${prio}" \
|
||||
-H "Tags: ${tags}" \
|
||||
"${auth_header[@]}" \
|
||||
--data-binary "${body}" \
|
||||
"${url}" >/dev/null || {
|
||||
log "WARN: ntfy-POST fehlgeschlagen."
|
||||
}
|
||||
}
|
||||
|
||||
#####################################
|
||||
# LOGIK #
|
||||
#####################################
|
||||
|
||||
process_host_type() {
|
||||
local host="$1"
|
||||
local rtype="$2"
|
||||
|
||||
local new_records
|
||||
new_records="$(resolve_records "${host}" "${rtype}")"
|
||||
|
||||
# Temporäre Datei für neuen Zustand
|
||||
local tmp_new
|
||||
tmp_new="$(mktemp)"
|
||||
printf "%s\n" "${new_records}" > "${tmp_new}"
|
||||
|
||||
local state_file
|
||||
state_file="$(state_file_path "${host}" "${rtype}")"
|
||||
|
||||
if compare_sets "${state_file}" "${tmp_new}"; then
|
||||
# Keine Änderung
|
||||
rm -f "${tmp_new}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Änderung erkannt
|
||||
local old="(kein vorheriger Zustand)"
|
||||
if [[ -s "${state_file}" ]]; then
|
||||
old="$(cat "${state_file}")"
|
||||
fi
|
||||
local now
|
||||
now="$(cat "${tmp_new}")"
|
||||
|
||||
# State aktualisieren
|
||||
mv -f "${tmp_new}" "${state_file}"
|
||||
|
||||
# Meldung bauen
|
||||
local subject="Änderung: ${host} ${rtype}"
|
||||
local body
|
||||
body=$(cat <<EOF
|
||||
DNS-Änderung erkannt
|
||||
|
||||
Host: ${host}
|
||||
Typ: ${rtype}
|
||||
Zeit: $(date -Iseconds)
|
||||
|
||||
Alt:
|
||||
${old}
|
||||
|
||||
Neu:
|
||||
${now}
|
||||
|
||||
Resolver: ${DNS_RESOLVER:-system-default}
|
||||
EOF
|
||||
)
|
||||
|
||||
log "Änderung erkannt für ${host} ${rtype}. Sende Benachrichtigungen."
|
||||
notify_mail "${subject}" "${body}"
|
||||
notify_ntfy "${subject}" "${body}" "${NTFY_PRIORITY}" "${NTFY_TAGS}"
|
||||
}
|
||||
|
||||
main() {
|
||||
with_lock
|
||||
ensure_dirs
|
||||
|
||||
for host in "${HOSTS[@]}"; do
|
||||
for rt in "${RECORD_TYPES[@]}"; do
|
||||
process_host_type "${host}" "${rt}"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
main "$@"
|
Loading…
x
Reference in New Issue
Block a user