Fix(DuckDNS): Resolve zombie updater conflict via token rotation.
- Updated 'docker-compose.yml' with new DuckDNS token to lock out rogue updaters (FritzBox/HA). - Enhanced 'dns-monitor/monitor.sh' to detect 'IP Flapping' (Zombie Updaters) by comparing Public vs. Global vs. Local IPs. - Updated documentation 'duckdns_setup.md' with troubleshooting steps for IP flapping and zombie updaters.
This commit is contained in:
@@ -1,15 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Install curl and ping if not present (Alpine)
|
||||
# Ensure dependencies are installed
|
||||
# We check for 'dig' specifically. If missing, we try to install bind-tools.
|
||||
if ! command -v dig >/dev/null 2>&1; then
|
||||
echo "[DNS-MONITOR] 'dig' not found. Installing bind-tools..."
|
||||
if apk add --no-cache bind-tools; then
|
||||
echo "[DNS-MONITOR] bind-tools installed successfully."
|
||||
else
|
||||
echo "[DNS-MONITOR] ERROR: Failed to install bind-tools. Check internet connection or repo mirrors."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure curl is installed (though it seems to be present based on logs)
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
echo "[DNS-MONITOR] 'curl' not found. Installing curl..."
|
||||
apk add --no-cache curl
|
||||
fi
|
||||
|
||||
echo "[DNS-MONITOR] Service started. Monitoring $SUBDOMAINS every 5 minutes..."
|
||||
|
||||
while true; do
|
||||
# Fetch Public IP
|
||||
PUBLIC_IP=$(curl -s -m 10 https://api.ipify.org)
|
||||
# 1. Fetch Public IP (via external service)
|
||||
# We use -4 to force IPv4
|
||||
PUBLIC_IP=$(curl -s -4 -m 10 https://api.ipify.org)
|
||||
|
||||
if [ -z "$PUBLIC_IP" ]; then
|
||||
PUBLIC_IP="Error: Could not fetch IP"
|
||||
@@ -23,20 +36,32 @@ while true; do
|
||||
else
|
||||
FULL_DOMAIN="${FIRST_SUB}.duckdns.org"
|
||||
|
||||
# Resolve IP using ping
|
||||
DOMAIN_IP=$(ping -c 1 -W 5 "$FULL_DOMAIN" 2>/dev/null | head -n 1 | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n 1)
|
||||
|
||||
if [ -z "$DOMAIN_IP" ]; then
|
||||
DOMAIN_IP="Error: Could not resolve"
|
||||
# 2. Resolve Global IP (Google DNS @8.8.8.8) to check propagation
|
||||
# We look for the A record (IPv4)
|
||||
if command -v dig >/dev/null 2>&1; then
|
||||
GLOBAL_IP=$(dig @8.8.8.8 +short A "$FULL_DOMAIN" | head -n 1)
|
||||
LOCAL_IP=$(dig +short A "$FULL_DOMAIN" | head -n 1)
|
||||
else
|
||||
GLOBAL_IP="Error: dig missing"
|
||||
LOCAL_IP="Error: dig missing"
|
||||
fi
|
||||
|
||||
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')
|
||||
|
||||
if [ "$PUBLIC_IP" == "$DOMAIN_IP" ]; then
|
||||
echo "[$TIMESTAMP] [DNS-MONITOR] OK | Domain: $FULL_DOMAIN ($DOMAIN_IP) == Public: $PUBLIC_IP"
|
||||
else
|
||||
echo "[$TIMESTAMP] [DNS-MONITOR] ALERT | Domain: $FULL_DOMAIN ($DOMAIN_IP) != Public: $PUBLIC_IP"
|
||||
# Logic to determine status
|
||||
STATUS="OK"
|
||||
if [ "$PUBLIC_IP" != "$GLOBAL_IP" ]; then
|
||||
STATUS="ALERT"
|
||||
elif [ "$PUBLIC_IP" != "$LOCAL_IP" ]; then
|
||||
# If Global is correct but Local is wrong, it's a local caching issue, still an alert but specific
|
||||
STATUS="CACHE_ALERT"
|
||||
fi
|
||||
|
||||
# Log format: Time | Status | Public vs Global vs Local
|
||||
echo "[$TIMESTAMP] [DNS-MONITOR] $STATUS | Public: $PUBLIC_IP | Global(8.8.8.8): $GLOBAL_IP | Local: $LOCAL_IP"
|
||||
fi
|
||||
|
||||
# Check every 5 minutes
|
||||
|
||||
Reference in New Issue
Block a user