In the meantime I have used a large number of Raspberry Pis for measuring and monitoring purposes. Since these usually hang behind Internet connections with dynamic IP, I have been using no-ip. com as a DynDNS service for some time now. However, the Dynamic DNS Update Client (DUC) offered by NO-IP never really worked reliably for me and so I had no access to the Raspberry Pis on a regular basis. I therefore wrote myself a small bash-script for a reliable and fast update of the IP-address. The script is certainly not perfect, but it has been working reliably for months now.
The functionality is quickly explained:
- the script uses Cronjob to regularly determine the current IP
- the current IP is compared with the cached IP
- If the IP has changed, NO-IP is notified by curl
- the newly determined IP is cached for future comparisons
- all IP updates and occurred errors are logged
Difficulty level:
As described above, the script uses curl to access NO-IP. Curl must therefore be installed first:
$ sudo apt-get install curl
The script is then stored under /usr/local/bin/noip_updater. sh and the permissions are adjusted:
$ sudo nano /usr/local/bin/noip_updater.sh $ sudo chmod 700 /usr/local/bin/noip_updater.sh
Script
The following content must be copied to the noip_updater. sh file and the USERNAME, PASSWORD and HOST variables must be customized:
#!/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
To execute the bash script at regular intervals, a cronjob must be created. For this purpose we work on crontab:
$ sudo nano /etc/crontab
At the bottom, the following entry is simply added and the change is saved on the crontab:
# NO-IP update */5 * * * * root /usr/local/bin/noip_updater.sh
Then restart the Cron service.
$ sudo service cron restart
Note: There is a rating embedded within this post, please visit this post to rate it.