diff --git a/README.md b/README.md
index ffe6696..bb1ef93 100644
--- a/README.md
+++ b/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
+ ```
@@ -11,5 +35,5 @@ Wichtig: Link für Lizenz anpassen.
-
License |
Matrix |
Mastodon
+
License |
Matrix |
Mastodon
\ No newline at end of file
diff --git a/dns-watch.v1.sh b/dns-watch.v1.sh
new file mode 100644
index 0000000..39fc0a3
--- /dev/null
+++ b/dns-watch.v1.sh
@@ -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
+ 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 <