Bash: Update-Script für NO-IP.com (DynDNS)
Mittlerweile habe ich für Mess- und Monitoringzwecke eine Vielzahl an Raspberry Pis im Einsatz. Da diese in der Regel hinter Internetanschlüssen mit dynamischer IP hängen, setze ich dafür seit einiger Zeit no-ip.com als DynDNS-Dienst ein. Jedoch hat der von NO-IP angebotene Dynamic DNS Update Client (DUC) bei mir nie wirklich zuverlässig funktioniert und somit hatte ich regelmäßig keinen Zugriff mehr auf die Raspberry Pis. Ich habe mir deshalb kurzerhand ein kleines Bash-Script zur zuverlässigen und schnellen Aktualisierung der IP-Adresse geschrieben. Das Script ist mit Sicherheit nicht perfekt, verrichtet jedoch schon seit Monaten zuverlässig seinen Dienst.
Die Funktionsweise ist schnell erklärt:
- das Script ermittelt mittels Cronjob regelmäßig die aktuelle IP
- die aktuelle IP wird mit der zwischengespeicherten IP verglichen
- hat sich die IP geändert, wird dies NO-IP per curl mitgeteilt
- die neu ermittelte IP wird für zukünftige Vergleiche zwischengespeichert
- sämtliche IP-Updates und aufgetretene Fehler werden protokolliert
Schwierigkeitsgrad:
Wie oben bereits beschrieben, verwendet das Script curl für den Zugriff auf NO-IP. Curl muss daher zuerst installiert werden:
$ sudo apt-get install curl
Anschließend wird das Script unter /usr/local/bin/noip_updater.sh abgelegt und die Rechte angepasst:
$ sudo nano /usr/local/bin/noip_updater.sh $ sudo chmod 700 /usr/local/bin/noip_updater.sh
Das Script
In die Datei noip_updater.sh muss folgender Inhalt kopiert und die Variablen USERNAME, PASSWORD und HOST angepasst werden:
#!/bin/bash # ------------------------------------------------------- # CONFIG # ------------------------------------------------------- USERNAME="dein-noip-benutzername" PASSWORD="dein-noip-passwort" HOST="dein-noip-host.ddns.net" LOGFILE=/var/log/noip.log IPFILE=/tmp/current_ip USERAGENT="Datenreise NOIP Updater/0.4" if [ ! -e $IPFILE ]; then touch $IPFILE if [ $? -ne 0 ]; then LOGTEXT="IP file could not be created." LOGDATE="[$(date +'%d.%m.%Y %H:%M:%S')]" echo "$LOGDATE $LOGTEXT" >> $LOGFILE exit 1 fi elif [ ! -w $IPFILE ]; then LOGTEXT="IP file is not writable." LOGDATE="[$(date +'%d.%m.%Y %H:%M:%S')]" echo "$LOGDATE $LOGTEXT" >> $LOGFILE exit 1 fi # IP Validator # http://www.linuxjournal.com/content/validating-ip-address-bash-script function validate_ip() { local ip=$1 local stat=1 if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then OIFS=$IFS IFS='.' ip=($ip) IFS=$OIFS [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] stat=$? fi return $stat } GET_IP_URLS=( "http://icanhazip.com" "https://api.ipify.org" "http://wtfismyip.com/text" "http://nst.sourceforge.net/nst/tools/ip.php" ) for key in ${!GET_IP_URLS[@]}; do NEWIP=$(curl -s ${GET_IP_URLS[$key]} | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}') if validate_ip $NEWIP; then break elif [ $key -eq $((${#GET_IP_URLS[@]} - 1)) ]; then LOGTEXT="Could not find current IP. Offline?" LOGDATE="[$(date +'%d.%m.%Y %H:%M:%S')]" echo "$LOGDATE $LOGTEXT" >> $LOGFILE exit 1 else LOGTEXT="Got a non-valid IP from ${GET_IP_URLS[$key]}." LOGDATE="[$(date +'%d.%m.%Y %H:%M:%S')]" echo "$LOGDATE $LOGTEXT" >> $LOGFILE fi done STOREDIP=$(cat $IPFILE) if [ "$NEWIP" != "$STOREDIP" ]; then RESPONSE=$(curl -s -k -u $USERNAME:$PASSWORD --user-agent "$USERAGENT" "https://dynupdate.no-ip.com/nic/update?hostname=$HOST&myip=$NEWIP") RESPONSE=$(echo $RESPONSE | tr -cd "[:print:]") RESPONSE_A=$(echo $RESPONSE | awk '{ print $1 }') case $RESPONSE_A in "good") RESPONSE_B=$(echo $RESPONSE | awk '{ print $2 }') LOGTEXT="(good) DNS hostname(s) successfully updated to $RESPONSE_B." ;; "nochg") RESPONSE_B=$(echo $RESPONSE | awk '{ print $2 }') LOGTEXT="(nochg) IP address is current: $RESPONSE_B; no update performed." ;; "nohost") LOGTEXT="(nohost) Hostname supplied does not exist under specified account. Revise config file." ;; "badauth") LOGTEXT="(badauth) Invalid username password combination." ;; "badagent") LOGTEXT="(badagent) Client disabled - No-IP is no longer allowing requests from this update script." ;; "!donator") LOGTEXT="(!donator) An update request was sent including a feature that is not available." ;; "abuse") LOGTEXT="(abuse) Username is blocked due to abuse." ;; "911") LOGTEXT="(911) A fatal error on our side such as a database outage. Retry the update in no sooner than 30 minutes." ;; *) LOGTEXT="(error) Could not understand the response from No-IP. The DNS update server may be down." ;; esac echo $NEWIP > $IPFILE LOGDATE="[$(date +'%d.%m.%Y %H:%M:%S')]" echo "$LOGDATE $LOGTEXT" >> $LOGFILE fi exit 0
Cronjob
Damit das Bash-Script in regelmäßigen Intervallen ausgefüht wird, muss noch ein Cronjob angelegt werden. Dazu bearbeiten wir die crontab:
$ sudo nano /etc/crontab
Ganz unten wird einfach folgender Eintrag hinzugefügt und die Änderung an der Crontab gespeichert:
# NO-IP update */5 * * * * root /usr/local/bin/noip_updater.sh
Anschließend den Cron-Service neustarten – fertig!
$ sudo service cron restart
Man muss sich bei No-IP einmal im Monat anmelden damit der Zugang gültig bleibt.
Ja, beim kostenlosen Angebot (Free Dynamic DNS) muss man den Zugang alle 30 Tage bestätigen. Da ich NO-IP jedoch für eine Vielzahl an DSL-Anschlüssen im Einsatz habe, habe ich mir die kleinste Bezahlvariante (Enhanced Dynamic DNS) für 24$/Jahr gegönnt. Das sind gerade einmal 2$/Monat und ich kann damit bis zu 25 Host anlegen – ein wirklich faires Angebot und ein sehr zuverlässiger Service.
Würde sich der Einsatz dieser BASH auch für einen VPN mit DynDNS empfehlen?
Klar, dafür ist es u.a. gedacht.
Einfach bei noip.com registrieren und anschließend einen Hostname anlegen. Für diesen kann die IP dann mit dem Bash-Skript aktualisiert werden.
Kann man auch andere DynDNS Provider angeben, wenn man die Daten und den Update-Server richtig eingibt?
Kann man auch mehr als ein Host im Account updaten lassen?
Klar, das ist möglich. Mir erschließt sich zwar nicht ganz der Einsatzzweck, warum es mehrere Host-Adressen braucht, die alle auf die gleiche IP verweisen, aber mit kleinen Anpassungen im Skript ist das einfach realisierbar:
Folgende Zeile muss geändert werden:
ändern zu:
Dann im Hauptskript folgendes ändern bzw. ergänzen (fette Markierungen beachten):
(Die beschriebenen Änderungen habe ich nicht getestet, sondern sind rein frei Kopf ;-) )
Verstehe ich das Richtig, die Anmeldung alle 30 Tage erspare ich mir mit diesem Skript nicht?
Danke, LG.
Sorry, meinte um es korrekt zu formulieren bei einem Free Dynamic DNS Account von NO-IP.
Nein, die Reaktivierung des kostenlosen Accounts ersparst du dir damit nicht. Das Script dient rein zur IP-Aktualisierung.
Anstatt mein eigenes Bashscript von null an zu schreiben habe ich dieses gefunden, vielen Dank dafür. Habe es für meine Bedürfnisse und eigenen DynDNS Dienst angepasst. Ausserdem hat es den Vorteil das es im Gegensatz zu ddclient nachvollziehbar ist was das Ding macht :-)
Genau dafür war es gedacht :)
Freut mich, dass ich dir damit weiterhelfen konnte.
Morgen.
Wie schreibe ich Dein Sript in die fritz.box ein?
Danke
Mfg
Danke, für das nette Skript.
Hi,
klappt super, vielen Dank!
Gibt´s ne Möglichkeit das Passwort nicht im Klartext im Script stehen zu haben?
Habe es bereits probiert mit:
echo -n passwort|base64 -> in die sh
aber das klappt anscheinend nicht :(
Grüße Dave
Danke fürs Teilen