[packages] ddns-scripts: Introduce retry_interval option to periodically retry DDNS...
[openwrt/svn-archive/archive.git] / net / ddns-scripts / files / usr / lib / ddns / dynamic_dns_updater.sh
1 #!/bin/sh
2 # /usr/lib/dynamic_dns/dynamic_dns_updater.sh
3 #
4 # Written by Eric Paul Bishop, Janary 2008
5 # Distributed under the terms of the GNU General Public License (GPL) version 2.0
6 #
7 # This script is (loosely) based on the one posted by exobyte in the forums here:
8 # http://forum.openwrt.org/viewtopic.php?id=14040
9 #
10
11 . /usr/lib/ddns/dynamic_dns_functions.sh
12
13
14 service_id=$1
15 if [ -z "$service_id" ]
16 then
17 echo "ERRROR: You must specify a service id (the section name in the /etc/config/ddns file) to initialize dynamic DNS."
18 return 1
19 fi
20
21 #default mode is verbose_mode, but easily turned off with second parameter
22 verbose_mode="1"
23 if [ -n "$2" ]
24 then
25 verbose_mode="$2"
26 fi
27
28 ###############################################################
29 # Leave this comment here, to clearly document variable names
30 # that are expected/possible
31 #
32 # Now use load_all_config_options to load config
33 # options, which is a much more flexible solution.
34 #
35 #
36 #config_load "ddns"
37 #
38 #config_get enabled $service_id enabled
39 #config_get service_name $service_id service_name
40 #config_get update_url $service_id update_url
41 #
42 #
43 #config_get username $service_id username
44 #config_get password $service_id password
45 #config_get domain $service_id domain
46 #
47 #
48 #config_get use_https $service_id use_https
49 #config_get cacert $service_id cacert
50 #
51 #config_get ip_source $service_id ip_source
52 #config_get ip_interface $service_id ip_interface
53 #config_get ip_network $service_id ip_network
54 #config_get ip_url $service_id ip_url
55 #
56 #config_get force_interval $service_id force_interval
57 #config_get force_unit $service_id force_unit
58 #
59 #config_get check_interval $service_id check_interval
60 #config_get check_unit $service_id check_unit
61 #########################################################
62 load_all_config_options "ddns" "$service_id"
63
64
65 #some defaults
66 if [ -z "$check_interval" ]
67 then
68 check_interval=600
69 fi
70
71 if [ -z "$retry_interval" ]
72 then
73 retry_interval=60
74 fi
75
76 if [ -z "$check_unit" ]
77 then
78 check_unit="seconds"
79 fi
80
81
82 if [ -z "$force_interval" ]
83 then
84 force_interval=72
85 fi
86
87 if [ -z "$force_unit" ]
88 then
89 force_unit="hours"
90 fi
91
92 if [ -z "$use_https" ]
93 then
94 use_https=0
95 fi
96
97
98
99 #some constants
100
101 if [ "x$use_https" = "x1" ]
102 then
103 retrieve_prog="/usr/bin/curl "
104 if [ -f "$cacert" ]
105 then
106 retrieve_prog="${retrieve_prog}--cacert $cacert "
107 elif [ -d "$cacert" ]
108 then
109 retrieve_prog="${retrieve_prog}--capath $cacert "
110 fi
111 else
112 retrieve_prog="/usr/bin/wget -O - ";
113 fi
114
115 service_file="/usr/lib/ddns/services"
116
117 ip_regex="[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"
118
119 NEWLINE_IFS='
120 '
121
122
123 #determine what update url we're using if the service_name is supplied
124 if [ -n "$service_name" ]
125 then
126 #remove any lines not containing data, and then make sure fields are enclosed in double quotes
127 quoted_services=$(cat $service_file | grep "^[\t ]*[^#]" | awk ' gsub("\x27", "\"") { if ($1~/^[^\"]*$/) $1="\""$1"\"" }; { if ( $NF~/^[^\"]*$/) $NF="\""$NF"\"" }; { print $0 }' )
128
129
130 #echo "quoted_services = $quoted_services"
131 OLD_IFS=$IFS
132 IFS=$NEWLINE_IFS
133 for service_line in $quoted_services
134 do
135 #grep out proper parts of data and use echo to remove quotes
136 next_name=$(echo $service_line | grep -o "^[\t ]*\"[^\"]*\"" | xargs -r -n1 echo)
137 next_url=$(echo $service_line | grep -o "\"[^\"]*\"[\t ]*$" | xargs -r -n1 echo)
138
139 if [ "$next_name" = "$service_name" ]
140 then
141 update_url=$next_url
142 fi
143 done
144 IFS=$OLD_IFS
145 fi
146
147 if [ "x$use_https" = x1 ]
148 then
149 update_url=$(echo $update_url | sed -e 's/^http:/https:/')
150 fi
151
152
153 verbose_echo "update_url=$update_url"
154
155
156
157 #if this service isn't enabled then quit
158 if [ "$enabled" != "1" ]
159 then
160 return 0
161 fi
162
163
164
165
166
167 #compute update interval in seconds
168 case "$force_unit" in
169 "days" )
170 force_interval_seconds=$(($force_interval*60*60*24))
171 ;;
172 "hours" )
173 force_interval_seconds=$(($force_interval*60*60))
174 ;;
175 "minutes" )
176 force_interval_seconds=$(($force_interval*60))
177 ;;
178 "seconds" )
179 force_interval_seconds=$force_interval
180 ;;
181 * )
182 #default is hours
183 force_interval_seconds=$(($force_interval*60*60))
184 ;;
185 esac
186
187
188
189 #compute check interval in seconds
190 case "$check_unit" in
191 "days" )
192 check_interval_seconds=$(($check_interval*60*60*24))
193 ;;
194 "hours" )
195 check_interval_seconds=$(($check_interval*60*60))
196 ;;
197 "minutes" )
198 check_interval_seconds=$(($check_interval*60))
199 ;;
200 "seconds" )
201 check_interval_seconds=$check_interval
202 ;;
203 * )
204 #default is seconds
205 check_interval_seconds=$check_interval
206 ;;
207 esac
208
209
210
211 #compute retry interval in seconds
212 case "$retry_unit" in
213 "days" )
214 retry_interval_seconds=$(($retry_interval*60*60*24))
215 ;;
216 "hours" )
217 retry_interval_seconds=$(($retry_interval*60*60))
218 ;;
219 "minutes" )
220 retry_interval_seconds=$(($retry_interval*60))
221 ;;
222 "seconds" )
223 retry_interval_seconds=$retry_interval
224 ;;
225 * )
226 #default is seconds
227 retry_interval_seconds=$retry_interval
228 ;;
229 esac
230
231
232
233 verbose_echo "force seconds = $force_interval_seconds"
234 verbose_echo "check seconds = $check_interval_seconds"
235
236 #kill old process if it exists & set new pid file
237 if [ -d /var/run/dynamic_dns ]
238 then
239 #if process is already running, stop it
240 if [ -e "/var/run/dynamic_dns/$service_id.pid" ]
241 then
242 old_pid=$(cat /var/run/dynamic_dns/$service_id.pid)
243 test_match=$(ps | grep "^[\t ]*$old_pid")
244 verbose_echo "old process id (if it exists) = \"$test_match\""
245 if [ -n "$test_match" ]
246 then
247 kill $old_pid
248 fi
249 fi
250
251 else
252 #make dir since it doesn't exist
253 mkdir /var/run/dynamic_dns
254 fi
255 echo $$ > /var/run/dynamic_dns/$service_id.pid
256
257
258
259
260 #determine when the last update was
261 current_time=$(monotonic_time)
262 last_update=$(( $current_time - (2*$force_interval_seconds) ))
263 if [ -e "/var/run/dynamic_dns/$service_id.update" ]
264 then
265 last_update=$(cat /var/run/dynamic_dns/$service_id.update)
266 fi
267 time_since_update=$(($current_time - $last_update))
268
269
270 human_time_since_update=$(( $time_since_update / ( 60 * 60 ) ))
271 verbose_echo "time_since_update = $human_time_since_update hours"
272
273
274
275
276 registered_ip=$(echo $(nslookup "$domain" 2>/dev/null) | grep -o "Name:.*" | grep -o "$ip_regex")
277
278
279 #do update and then loop endlessly, checking ip every check_interval and forcing an updating once every force_interval
280
281 while [ true ]
282 do
283 current_ip=$(get_current_ip)
284
285
286 current_time=$(monotonic_time)
287 time_since_update=$(($current_time - $last_update))
288
289
290 verbose_echo "Running IP check..."
291 verbose_echo "current system ip = $current_ip"
292 verbose_echo "registered domain ip = $registered_ip"
293
294
295 if [ "$current_ip" != "$registered_ip" ] || [ $force_interval_seconds -lt $time_since_update ]
296 then
297 verbose_echo "update necessary, performing update ..."
298
299 #do replacement
300 final_url=$update_url
301 for option_var in $ALL_OPTION_VARIABLES
302 do
303 if [ "$option_var" != "update_url" ]
304 then
305 replace_name=$(echo "\[$option_var\]" | tr 'a-z' 'A-Z')
306 replace_value=$(eval echo "\$$option_var")
307 replace_value=$(echo $replace_value | sed -f /usr/lib/ddns/url_escape.sed)
308 final_url=$(echo $final_url | sed s^"$replace_name"^"$replace_value"^g )
309 fi
310 done
311 final_url=$(echo $final_url | sed s/"\[HTTPAUTH\]"/"$username${password:+:$password}"/g )
312 final_url=$(echo $final_url | sed s/"\[IP\]"/"$current_ip"/g )
313
314
315 verbose_echo "updating with url=\"$final_url\""
316
317 #here we actually connect, and perform the update
318 update_output=$( $retrieve_prog "$final_url" )
319 if [ $? -gt 0 ]
320 then
321 verbose_echo "update failed"
322 sleep $retry_interval_seconds
323 continue
324 fi
325
326 verbose_echo "Update Output:"
327 verbose_echo "$update_output"
328 verbose_echo ""
329
330 #save the time of the update
331 current_time=$(monotonic_time)
332 last_update=$current_time
333 time_since_update='0'
334 registered_ip=$current_ip
335
336 human_time=$(date)
337 verbose_echo "update complete, time is: $human_time"
338
339 echo "$last_update" > "/var/run/dynamic_dns/$service_id.update"
340 else
341 human_time=$(date)
342 human_time_since_update=$(( $time_since_update / ( 60 * 60 ) ))
343 verbose_echo "update unnecessary"
344 verbose_echo "time since last update = $human_time_since_update hours"
345 verbose_echo "the time is now $human_time"
346 fi
347
348 #sleep for 10 minutes, then re-check ip && time since last update
349 sleep $check_interval_seconds
350 done
351
352 #should never get here since we're a daemon, but I'll throw it in anyway
353 return 0
354
355
356
357