#!/bin/sh # DNS-Monitor v2.0 - Optimized for Synology/Docker stability # Monitoring: Public IP vs. Cloudflare DNS (1.1.1.1) # Ensure dependencies if ! command -v dig >/dev/null 2>&1; then apk add --no-cache bind-tools fi if ! command -v curl >/dev/null 2>&1; then apk add --no-cache curl fi echo "[DNS-MONITOR] Service started. Monitoring $SUBDOMAINS via Cloudflare (1.1.1.1)" while true; do # 1. Fetch Public IP PUBLIC_IP=$(curl -s -4 -m 15 https://api.ipify.org) if [ -z "$PUBLIC_IP" ]; then PUBLIC_IP="Error: Public IP fetch failed" fi # Get the first subdomain to check FIRST_SUB=$(echo $SUBDOMAINS | cut -d',' -f1) if [ -z "$FIRST_SUB" ]; then echo "[DNS-MONITOR] No subdomain found in env var SUBDOMAINS" else FULL_DOMAIN="${FIRST_SUB}.duckdns.org" # 2. Resolve Global IP (Cloudflare 1.1.1.1) # Using +time and +tries for high reliability on shaky connections GLOBAL_IP=$(dig @1.1.1.1 +short +time=8 +tries=3 A "$FULL_DOMAIN" | head -n 1) # 3. Resolve Local IP (Internal Docker/Host DNS) # This checks if the local cache is still stuck LOCAL_IP=$(dig +short +time=8 +tries=3 A "$FULL_DOMAIN" | head -n 1) if [ -z "$GLOBAL_IP" ]; then GLOBAL_IP="Unresolved"; fi if [ -z "$LOCAL_IP" ]; then LOCAL_IP="Unresolved"; fi TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') # Status Logic if [ "$PUBLIC_IP" = "$GLOBAL_IP" ]; then STATUS="OK" elif [ "$GLOBAL_IP" = "Unresolved" ]; then STATUS="NETWORK_WAIT" # Network or DNS provider issue, not necessarily DuckDNS else STATUS="ALERT" # Public IP != Global IP (DuckDNS update missing or zombie active) fi # Log entry echo "[$TIMESTAMP] [$STATUS] Pub: $PUBLIC_IP | CF: $GLOBAL_IP | Loc: $LOCAL_IP" fi # Check every 5 minutes sleep 300 done