#!/bin/sh # /usr/lib/dynamic_dns/dynamic_dns_updater.sh # # Written by Eric Paul Bishop, Janary 2008 # Distributed under the terms of the GNU General Public License (GPL) version 2.0 # # This script is (loosely) based on the one posted by exobyte in the forums here: # http://forum.openwrt.org/viewtopic.php?id=14040 # . /usr/lib/ddns/dynamic_dns_functions.sh service_id=$1 if [ -z "$service_id" ] then echo "ERRROR: You must specify a service id (the section name in the /etc/config/ddns file) to initialize dynamic DNS." return 1 fi #default mode is verbose_mode, but easily turned off with second parameter verbose_mode="1" if [ -n "$2" ] then verbose_mode="$2" fi ############################################################### # Leave this comment here, to clearly document variable names # that are expected/possible # # Now use load_all_config_options to load config # options, which is a much more flexible solution. # # #config_load "ddns" # #config_get enabled $service_id enabled #config_get service_name $service_id service_name #config_get update_url $service_id update_url # # #config_get username $service_id username #config_get password $service_id password #config_get domain $service_id domain # # #config_get use_https $service_id use_https #config_get use_syslog $service_id use_syslog #config_get cacert $service_id cacert # #config_get ip_source $service_id ip_source #config_get ip_interface $service_id ip_interface #config_get ip_network $service_id ip_network #config_get ip_url $service_id ip_url # #config_get force_interval $service_id force_interval #config_get force_unit $service_id force_unit # #config_get check_interval $service_id check_interval #config_get check_unit $service_id check_unit ######################################################### load_all_config_options "ddns" "$service_id" #some defaults if [ -z "$check_interval" ] then check_interval=600 fi if [ -z "$retry_interval" ] then retry_interval=60 fi if [ -z "$check_unit" ] then check_unit="seconds" fi if [ -z "$force_interval" ] then force_interval=72 fi if [ -z "$force_unit" ] then force_unit="hours" fi if [ -z $use_syslog ] then use_syslog=0 fi if [ -z "$use_https" ] then use_https=0 fi #some constants retrieve_prog="/usr/bin/wget -O - "; if [ "x$use_https" = "x1" ] then /usr/bin/wget --version 2>&1 |grep -q "\+ssl" if [ $? -eq 0 ] then if [ -f "$cacert" ] then retrieve_prog="${retrieve_prog}--ca-certificate=${cacert} " elif [ -d "$cacert" ] then retrieve_prog="${retrieve_prog}--ca-directory=${cacert} " fi else retrieve_prog="/usr/bin/curl " if [ -f "$cacert" ] then retrieve_prog="${retrieve_prog}--cacert $cacert " elif [ -d "$cacert" ] then retrieve_prog="${retrieve_prog}--capath $cacert " fi fi fi service_file="/usr/lib/ddns/services" ip_regex="[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" NEWLINE_IFS=' ' #determine what update url we're using if the service_name is supplied if [ -n "$service_name" ] then #remove any lines not containing data, and then make sure fields are enclosed in double quotes quoted_services=$(cat $service_file | grep "^[\t ]*[^#]" | awk ' gsub("\x27", "\"") { if ($1~/^[^\"]*$/) $1="\""$1"\"" }; { if ( $NF~/^[^\"]*$/) $NF="\""$NF"\"" }; { print $0 }' ) #echo "quoted_services = $quoted_services" OLD_IFS=$IFS IFS=$NEWLINE_IFS for service_line in $quoted_services do #grep out proper parts of data and use echo to remove quotes next_name=$(echo $service_line | grep -o "^[\t ]*\"[^\"]*\"" | xargs -r -n1 echo) next_url=$(echo $service_line | grep -o "\"[^\"]*\"[\t ]*$" | xargs -r -n1 echo) if [ "$next_name" = "$service_name" ] then update_url=$next_url fi done IFS=$OLD_IFS fi if [ "x$use_https" = x1 ] then update_url=$(echo $update_url | sed -e 's/^http:/https:/') fi verbose_echo "update_url=$update_url" #if this service isn't enabled then quit if [ "$enabled" != "1" ] then return 0 fi #compute update interval in seconds case "$force_unit" in "days" ) force_interval_seconds=$(($force_interval*60*60*24)) ;; "hours" ) force_interval_seconds=$(($force_interval*60*60)) ;; "minutes" ) force_interval_seconds=$(($force_interval*60)) ;; "seconds" ) force_interval_seconds=$force_interval ;; * ) #default is hours force_interval_seconds=$(($force_interval*60*60)) ;; esac #compute check interval in seconds case "$check_unit" in "days" ) check_interval_seconds=$(($check_interval*60*60*24)) ;; "hours" ) check_interval_seconds=$(($check_interval*60*60)) ;; "minutes" ) check_interval_seconds=$(($check_interval*60)) ;; "seconds" ) check_interval_seconds=$check_interval ;; * ) #default is seconds check_interval_seconds=$check_interval ;; esac #compute retry interval in seconds case "$retry_unit" in "days" ) retry_interval_seconds=$(($retry_interval*60*60*24)) ;; "hours" ) retry_interval_seconds=$(($retry_interval*60*60)) ;; "minutes" ) retry_interval_seconds=$(($retry_interval*60)) ;; "seconds" ) retry_interval_seconds=$retry_interval ;; * ) #default is seconds retry_interval_seconds=$retry_interval ;; esac verbose_echo "force seconds = $force_interval_seconds" verbose_echo "check seconds = $check_interval_seconds" #kill old process if it exists & set new pid file if [ -d /var/run/dynamic_dns ] then #if process is already running, stop it if [ -e "/var/run/dynamic_dns/$service_id.pid" ] then old_pid=$(cat /var/run/dynamic_dns/$service_id.pid) test_match=$(ps | grep "^[\t ]*$old_pid") verbose_echo "old process id (if it exists) = \"$test_match\"" if [ -n "$test_match" ] then kill $old_pid fi fi else #make dir since it doesn't exist mkdir /var/run/dynamic_dns fi echo $$ > /var/run/dynamic_dns/$service_id.pid #determine when the last update was current_time=$(monotonic_time) last_update=$(( $current_time - (2*$force_interval_seconds) )) if [ -e "/var/run/dynamic_dns/$service_id.update" ] then last_update=$(cat /var/run/dynamic_dns/$service_id.update) fi time_since_update=$(($current_time - $last_update)) human_time_since_update=$(( $time_since_update / ( 60 * 60 ) )) verbose_echo "time_since_update = $human_time_since_update hours" #do update and then loop endlessly, checking ip every check_interval and forcing an updating once every force_interval while [ true ] do registered_ip=$(echo $(nslookup "$domain" 2>/dev/null) | grep -o "Name:.*" | grep -o "$ip_regex") current_ip=$(get_current_ip) current_time=$(monotonic_time) time_since_update=$(($current_time - $last_update)) syslog_echo "Running IP check ..." verbose_echo "Running IP check..." verbose_echo "current system ip = $current_ip" verbose_echo "registered domain ip = $registered_ip" if [ "$current_ip" != "$registered_ip" ] || [ $force_interval_seconds -lt $time_since_update ] then verbose_echo "update necessary, performing update ..." #do replacement final_url=$update_url for option_var in $ALL_OPTION_VARIABLES do if [ "$option_var" != "update_url" ] then replace_name=$(echo "\[$option_var\]" | tr 'a-z' 'A-Z') replace_value=$(eval echo "\$$option_var") replace_value=$(echo $replace_value | sed -f /usr/lib/ddns/url_escape.sed) final_url=$(echo $final_url | sed s^"$replace_name"^"$replace_value"^g ) fi done final_url=$(echo $final_url | sed s^"\[HTTPAUTH\]"^"${username//^/\\^}${password:+:${password//^/\\^}}"^g ) final_url=$(echo $final_url | sed s/"\[IP\]"/"$current_ip"/g ) verbose_echo "updating with url=\"$final_url\"" #here we actually connect, and perform the update update_output=$( $retrieve_prog "$final_url" ) if [ $? -gt 0 ] then syslog_echo "update failed, retrying in $retry_interval_seconds seconds" verbose_echo "update failed" sleep $retry_interval_seconds continue fi syslog_echo "Update successful" verbose_echo "Update Output:" verbose_echo "$update_output" verbose_echo "" #save the time of the update current_time=$(monotonic_time) last_update=$current_time time_since_update='0' registered_ip=$current_ip human_time=$(date) verbose_echo "update complete, time is: $human_time" echo "$last_update" > "/var/run/dynamic_dns/$service_id.update" else human_time=$(date) human_time_since_update=$(( $time_since_update / ( 60 * 60 ) )) verbose_echo "update unnecessary" verbose_echo "time since last update = $human_time_since_update hours" verbose_echo "the time is now $human_time" fi #sleep for 10 minutes, then re-check ip && time since last update sleep $check_interval_seconds done #should never get here since we're a daemon, but I'll throw it in anyway return 0