DDNS Updater DDNS Updater 2: Wünsche und Verbesserungsvorschläge - Requests and suggestions

Mitglied seit
04. Jan 2016
Beiträge
4
Punkte für Reaktionen
1
Punkte
1
Es klappt jetzt: sowohl IPv4 als auch IPv6 werden aktualisiert, wenn sie sich geändert haben, oder wenn ein Monat vergangen ist.

Das basiert auf dem kostenlosen DDNS-Service von nsupdate.info - ich nutze den schon seit 8 Jahren für die Fritzbox und er war immer stabil. Ich weiß gar nicht mehr, wie ich den damals gefunden habe. Jetzt habe ich noch einen zweiten Host hinzugefügt.

Das war mein erstes größeres Bash-Script. Habe doch sehr viel im oben verlinkten Code geändert; er hatte auch noch einige Bugs. Außerdem habe ich noch einige Sicherungen eingefügt. Leider habe ich auch als Root keinen Zugang zu /var/log auf der DS, weshalb das Script im Nutzerverzeichnis läuft und dort auch seine Logs und Dateien ablegt. Falls Ihr Fehler seht, lasst es mich wissen.

Wer es auch nutzen möchte: einfach ganz am Anfang die eigenen Daten bei DOMAIN und TOKEN eintragen. Datei im Adminverzeichnis speichern als "nsupdate.sh". Dann per SSH auf DS einloggen. Datei ausführbar machen mit "chmod +x nsupdate.sh". Und dann per "./nsupdate.sh" ausführen. Oder für Debug-Output als "bash -x nsupdate.sh" ausführen.

Das ganze muss natürlich noch mit crontab regelmäßig laufen; das sollte aber einfach sein (habe es aber noch nicht gemacht).

Nächste Baustelle: Let's Encrypt...

Bash:
#!/usr/bin/env sh

# Based on script from comment in https://gist.github.com/raphiz/837453f189dca966a69c
# Original Author, 2015-06-05: raphiz
# Additional Author in comment, IPv6 adaptation, 2016-09-23: rosch100
# Updated and improved script below, 2023-01-31: Hausanschlussraum


#Add your domain and token from nsupdate.info
DOMAIN="MYDOMAIN.nsupdate.info"
TOKEN="MYSECRET"
#If IP address did not change, only update after the following number of seconds (should be one month to avoid ban)
TIMEBETWEENFORCEDUPDATES="2628000"

#Files to be used - add path if required
LOGFILE='nsupdate.log'
ERRORLOGFILE='nsupdateerror.log'
TEMPFILE='nsupdate.temp'
LASTCONTACTFILE='lastcontactv4.upd'
LASTCONTACTFILEv6='lastcontactv6.upd'

# Functions to check whether returned variables are roughly valid IP addresses to catch empty or error responses

is_ipv4_address() {
  [[ $1 =~ [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} ]]
}

is_ipv6_address() {
  [[ $1 =~ ^([0-9a-fA-F]{0,4}:){0,7}[0-9a-fA-F]{1,4}$ ]]
}

# initialise Force Update variable
FORCEUPDATE="FALSE"
FORCEUPDATEv6="FALSE"

# Store current time
CURRENTDATE=$(date --utc +%FT%T.%3N%Z)
CURRENTTIME=$(date +%s)
CURRENTTIMEv6=$(date +%s)

# Evaluate the current remote IPs and the one that is currently registerd
CURRENT=$(curl -s https://ipv4.nsupdate.info/myip)
CURRENTv6=$(curl -s https://ipv6.nsupdate.info/myip)
SAVED=$(python2 -c "import socket; print socket.gethostbyname('$DOMAIN')")

#Fritzbox DNS appears to filter local IPv6 address for some reason in responses; hence, nslookup specifying Google DNS is used instead
#getaddrinfo would be preferred if it works
#SAVEDv6=$(python2 -c "import socket; print socket.getaddrinfo('$DOMAIN', None, socket.AF_INET6)[0][4][0]")
SAVEDv6=$(nslookup -type=AAAA "$DOMAIN" 8.8.8.8 | awk 'NR==6 {print $2}')

# Write the current date, ip and registered ip into the log file

{
    echo '----------------------------'
    echo "$CURRENTDATE"
    echo "The current external IPv4 is: $CURRENT"
    echo "The current external IPv6 is: $CURRENTv6"
    echo "The following IPv4 is registered: $SAVED"
    echo "The following IPv6 is registered: $SAVEDv6"
} >> "$LOGFILE"

# Read in time of last contact (create and fill file with sensible value if missing or empty)
if [ ! -f "$LASTCONTACTFILE" ]; then
    touch "$LASTCONTACTFILE"
fi
if [ ! -s "$LASTCONTACTFILE" ]; then
    echo -n "1675124740" > "$LASTCONTACTFILE"
fi
LASTCONTACT=$(< "$LASTCONTACTFILE")

# Same for v6
if [ ! -f "$LASTCONTACTFILEv6" ]; then
    touch "$LASTCONTACTFILEv6"
fi
if [ ! -s "$LASTCONTACTFILEv6" ]; then
    echo -n "1675124740" > "$LASTCONTACTFILEv6"
fi
LASTCONTACTv6=$(< "$LASTCONTACTFILEv6")

# Correct current time to be at least last contact time plus 5 seconds in case of current time problem
if [ $(("$LASTCONTACT")) -gt $(($"CURRENTTIME")) ]; then
    $"CURRENTTIME"=$(("$LASTCONTACT"+5))
    echo "$CURRENTDATE Warning: current time or time of last IPv4 contact potentially wrong" >> "$ERRORLOGFILE"
fi

# Same for v6
if [ $(("$LASTCONTACTv6")) -gt $(($"CURRENTTIMEv6")) ]; then
    $"CURRENTTIMEv6"=$(("$LASTCONTACTv6"+5))
    echo "$CURRENTDATE Warning: current time or time of last IPv6 contact potentially wrong" >> "$ERRORLOGFILE"
fi

# If last contact more than the number of seconds defined above ago, set Force Update variable to TRUE
if [ $(("$LASTCONTACT"+"$TIMEBETWEENFORCEDUPDATES")) -lt $(($"CURRENTTIME")) ]; then
    FORCEUPDATE="TRUE"
fi

# Same for v6
if [ $(("$LASTCONTACTv6"+"$TIMEBETWEENFORCEDUPDATES")) -lt $(($"CURRENTTIMEv6")) ]; then
    FORCEUPDATEv6="TRUE"
fi

# Check if an update is required - if so, update and verify the response
# If more than required time has passed, update anyway

if ! is_ipv4_address "$CURRENT"; then
    echo "Warning: The current external IPv4 adress is not valid. Skipping IPv4 update." >> "$LOGFILE"
    echo "$CURRENTDATE Warning: The current external IPv4 adress is not valid. Skipping IPv4 update." >> "$ERRORLOGFILE"
elif ! is_ipv4_address "$SAVED"; then
    echo "Warning: The saved IPv4 adress is not valid. Skipping IPv4 update." >> "$LOGFILE"
    echo "$CURRENTDATE Warning: The saved IPv4 adress is not valid. Skipping IPv4 update." >> "$ERRORLOGFILE"
elif [ "$CURRENT" != "$SAVED" ] || [ "$FORCEUPDATE" = "TRUE" ]; then
    echo "updating IPv4..." >> "$LOGFILE"
    RESPONSE=$(curl --user "$DOMAIN":"$TOKEN" https://ipv4.nsupdate.info/nic/update)
    START=$(python2 -c "print '$RESPONSE'[:5]")
    if [ "$START" = "good " ]; then
        echo "Update IPv4 succesful!" >> "$LOGFILE"
        echo -n "$CURRENTTIME" > "$LASTCONTACTFILE"     
    elif [ "$START" = "nochg" ]; then
        echo "WARNING: IPv4 has not changed but was updated - watch out for client ban" >> "$LOGFILE"
        echo "$CURRENTDATE WARNING: IPv4 has not changed but was updated - watch out for client ban" >> "$ERRORLOGFILE"
        echo -n "$CURRENTTIME" > "$LASTCONTACTFILE"
    else
        echo "ERROR: DDNS Server for IPv4 did not respond or response not as expected"  >> "$LOGFILE"
        echo "$CURRENTDATE ERROR: DDNS Server for IPv4 did not respond or response not as expected"  >> "$ERRORLOGFILE"
    fi
else
    echo 'no IPv4 update required' >> "$LOGFILE"
fi

# Same for IPv6

if ! is_ipv6_address "$CURRENTv6"; then
    echo "Warning: The current external IPv6 adress is not valid. Skipping IPv6 update." >> "$LOGFILE"
    echo "$CURRENTDATE Warning: The current external IPv6 adress is not valid. Skipping IPv6 update." >> "$ERRORLOGFILE"
elif ! is_ipv6_address "$SAVEDv6"; then
    echo "Warning: The saved IPv6 adress is not valid. Skipping IPv6 update." >> "$LOGFILE"
    echo "$CURRENTDATE Warning: The saved IPv6 adress is not valid. Skipping IPv6 update." >> "$ERRORLOGFILE"
elif [ "$CURRENTv6" != "$SAVEDv6" ] || [ "$FORCEUPDATEv6" = "TRUE" ]; then
    echo "updating IPv6..." >> "$LOGFILE"
    RESPONSE=$(curl --user "$DOMAIN":"$TOKEN" https://ipv6.nsupdate.info/nic/update)
    START=$(python2 -c "print '$RESPONSE'[:5]")
    if [ "$START" = "good " ]; then
        echo "Update IPv6 succesful!" >> "$LOGFILE"
        echo -n "$CURRENTTIMEv6" > "$LASTCONTACTFILEv6"     
    elif [ "$START" = "nochg" ]; then
        echo "WARNING: IPv6 has not changed but was updated - watch out for client ban" >> "$LOGFILE"
        echo "$CURRENTDATE WARNING: IPv6 has not changed but was updated - watch out for client ban" >> "$ERRORLOGFILE"
        echo -n "$CURRENTTIMEv6" > "$LASTCONTACTFILEv6"
    else
        echo "ERROR: DDNS Server for IPv6 did not respond or response not as expected"  >> "$LOGFILE"
        echo "$CURRENTDATE ERROR: DDNS Server for IPv6 did not respond or response not as expected"  >> "$ERRORLOGFILE"
    fi
else
    echo 'no IPv6 update required' >> "$LOGFILE"
fi

# Keep the log down to 100,000 lines
cp -R "$LOGFILE" "$TEMPFILE"
tail -n 100000 "$TEMPFILE" > "$LOGFILE"
rm "$TEMPFILE"
[/ICODE]
 
  • Like
Reaktionen: compy
Mitglied seit
04. Jan 2016
Beiträge
4
Punkte für Reaktionen
1
Punkte
1
Crontab gibt es nicht, daher das Script per Task Scheduler im Control Centre regelmäßig laufen lassen.

Ich habe jetzt auch das Fritzbox DNS-Problem verstanden - es geht darum, dass niemand extern einen Domain Name so nutzt, dass dieser auf eine lokale Ressource zeigt. Aber man kann für seine eigene Domain in der Fritzbox einfach eine Ausnahme hinzufügen unter Heimnetz->Netzwerk->Netzwerkeinstellungen->DNS-Rebind-Schutz. Dann kann man im obigen Code die Zeile mit 'nslookup' auskommentieren und stattdessen die Kommentarzeile mit getaddrinfo wieder aktivieren.

Let's Encrypt ging dann ganz einfach mit der in der Synology eingebauten Routine. Man muss allerdings Port 80 weiterleiten (bzw. öffnen für IPv6) auf der Fritzbox. Dann noch als Standard wählen und schon hat man auch im LAN HTTPS und keine Fehlermeldungen mehr.
 

Radon

Benutzer
Mitglied seit
09. Mai 2012
Beiträge
13
Punkte für Reaktionen
0
Punkte
1
Mann kann dort zwar auch für ddnss.de einen benutzerdefinierten Anbieter hinzufügen, allerdings funktioniert dies (bei mir) nicht, da die Synology offenbar mit der Response nicht klar kommt und diese immer als Fehler bewertet.
Hallo zusammen
Da hier schon sehr viel zu dem Thema steht, wollte ich keinen neuen Beitrag eröffnen und beim durchlesen habe ich mein Problem "wiedergefunden". Aber leider keine Lösung dazu.

Ich wechsle gerade auf ein neues NAS und will eigentlich nicht mehr auf DSM 6 bleiben:
Nun muss ich feststellen die einfachste und wichtigste Aufgabe geht nicht mehr wie ich das erwarte.
DDNS (IPv4) nutzen für ZoneEdit.com und Two-DNS.de

Beide sind nicht mehr als Serviceanbieter gelistet in DSM 7. Ich habe sie beide manuell hinzugefügt und habe einiges getestet, aber habe immer das Problem, dass "Fehlgeschlagen" gemeldet wird, die Aufgabe wird aber korrekt ausgeführt.

Wieso kommt trotzdem die Fehlermeldung, bzw. wie kriege ich diese Weg?

Details falls es relevant ist:
Folgende Query URL habe ich versucht (alle mit und ohne https://):
https://api.cp.zoneedit.com/dyn/gen...ASSWORD__&hostname=__HOSTNAME__&myip=__MYIP__
https://__USERNAME__:__PASSWORD__@a...neric.php?hostname=__HOSTNAME__&myip=__MYIP__
https://api.cp.zoneedit.com/dyn/generic.php?hostname=__HOSTNAME__&myip=__MYIP__

https://update.twodns.de/update.php?hostname=__HOSTNAME__&myip=__MYIP__

Gemäss GUI ist der Verbindungstest "Normal" jedoch dann die Aufgabe immer auf "Fehlgeschlagen"
Und im Protokoll wird hinterlegt:
"System successfully registered [1.2.3.4] to [my.domain] in DDNS server [USER_Zoneedit.com]."

Bei ZoneEdit habe ich es auch überprüft, es wird tatsächlich die IP aktualisiert, aber wieso kommt trotzdem die Fehlermeldung?
 

Andy+

Benutzer
Sehr erfahren
Mitglied seit
25. Jan 2016
Beiträge
5.363
Punkte für Reaktionen
485
Punkte
189


 

Kaffeautomat

Wenn du das Forum hilfreich findest oder uns unterstützen möchtest, dann gib uns doch einfach einen Kaffee aus.

Als Dankeschön schalten wir deinen Account werbefrei.

:coffee:

Hier gehts zum Kaffeeautomat