ddns-scripts: rename variable: s/retry_count/retry_max_count/
[feed/packages.git] / net / ddns-scripts / files / usr / lib / ddns / dynamic_dns_updater.sh
old mode 100755 (executable)
new mode 100644 (file)
index 107d0eb..47b2abf
 #!/bin/sh
 # /usr/lib/ddns/dynamic_dns_updater.sh
 #
+#.Distributed under the terms of the GNU General Public License (GPL) version 2.0
 # Original written by Eric Paul Bishop, January 2008
-# Distributed under the terms of the GNU General Public License (GPL) version 2.0
 # (Loosely) based on the script on the one posted by exobyte in the forums here:
 # http://forum.openwrt.org/viewtopic.php?id=14040
-#
-# extended and partial rewritten in August 2014 
-# by Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
-# to support:
-# - IPv6 DDNS services
-# - DNS Server to retrieve registered IP including TCP transport (Ticket 7820)
-# - Proxy Server to send out updates
-# - force_interval=0 to run once (Luci Ticket 538)
-# - the usage of BIND's host command instead of BusyBox's nslookup if installed
-# - extended Verbose Mode and log file support for better error detection 
-# - wait for interface to fully come up, before the first update is done
+# extended and partial rewritten
+#.2014-2018 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
 #
 # variables in small chars are read from /etc/config/ddns
 # variables in big chars are defined inside these scripts as global vars
 # variables in big chars beginning with "__" are local defined inside functions only
-#set -vx       #script debugger
-
-[ $# -lt 1 -o -n "${2//[0-3]/}" -o ${#2} -gt 1 ] && {
-       echo -e "\n  USAGE:"
-       echo -e "  $0 [SECTION] [VERBOSE_MODE]\n"
-       echo    "  [SECTION]      - service section as defined in /etc/config/ddns"
-       echo    "  [VERBOSE_MODE] - '0' NO output to console"
-       echo    "                   '1' output to console"
-       echo    "                   '2' output to console AND logfile"
-       echo    "                       + run once WITHOUT retry on error"
-       echo    "                   '3' output to console AND logfile"
-       echo    "                       + run once WITHOUT retry on error"
-       echo -e "                       + NOT sending update to DDNS service\n"
+# set -vx      #script debugger
+
+. $(dirname $0)/dynamic_dns_functions.sh       # global vars are also defined here
+
+usage() {
+       cat << EOF
+
+Usage:
+ $MYPROG [options] -- command
+
+Commands:
+start                Start SECTION or NETWORK or all
+stop                 Stop NETWORK or all
+
+Parameters:
+ -n NETWORK          Start/Stop sections in background monitoring NETWORK, force VERBOSE=0
+ -S SECTION          SECTION to start
+                     use either -N NETWORK or -S SECTION
+
+ -h                  show this help and exit
+ -V                  show version and exit
+ -v LEVEL            VERBOSE=LEVEL (default 1)
+                        '0' NO output to console
+                        '1' output to console
+                        '2' output to console AND logfile
+                            + run once WITHOUT retry on error
+                        '3' output to console AND logfile
+                            + run once WITHOUT retry on error
+                            + NOT sending update to DDNS service
+
+EOF
+}
+
+usage_err() {
+       printf %s\\n "$MYPROG: $@" >&2
+       usage >&2
        exit 1
 }
 
-. /usr/lib/ddns/dynamic_dns_functions.sh       # global vars are also defined here
+while getopts ":hv:n:S:V" OPT; do
+       case "$OPT" in
+               h)      usage; exit 0;;
+               v)      VERBOSE=$OPTARG;;
+               n)      NETWORK=$OPTARG;;
+               S)      SECTION_ID=$OPTARG;;
+               V)      printf %s\\n "ddns-scripts $VERSION"; exit 0;;
+               :)      usage_err "option -$OPTARG missing argument";;
+               \?)     usage_err "invalid option -$OPTARG";;
+               *)      usage_err "unhandled option -$OPT $OPTARG";;
+       esac
+done
+shift $((OPTIND - 1 )) # OPTIND is 1 based
 
-SECTION_ID="$1"
-VERBOSE_MODE=${2:-1}   # default mode is log to console
+[ -n "$NETWORK" -a -n "$SECTION_ID" ] && usage_err "use either option '-N' or '-S' not both"
+[ $# -eq 0 ] && usage_err "missing command"
+[ $# -gt 1 ] && usage_err "to much commands"
 
-# set file names
-PIDFILE="$RUNDIR/$SECTION_ID.pid"      # Process ID file
-UPDFILE="$RUNDIR/$SECTION_ID.update"   # last update successful send (system uptime)
-LOGFILE="$LOGDIR/$SECTION_ID.log"      # log file
+case "$1" in
+       start)
+               if [ -n "$NETWORK" ]; then
+                       start_daemon_for_all_ddns_sections "$NETWORK"
+                       exit 0
+               fi
+               if [ -z "$SECTION_ID" ]; then
+                       start_daemon_for_all_ddns_sections
+                       exit 0
+               fi
+               ;;
+       stop)
+               if [ -n "$INTERFACE" ]; then
+                       stop_daemon_for_all_ddns_sections "$NETWORK"
+                       exit 0
+               else
+                       stop_daemon_for_all_ddns_sections
+                       exit 0
+               fi
+               exit 1
+               ;;
+       reload)
+               killall -1 dynamic_dns_updater.sh 2>/dev/null
+               exit $?
+               ;;
+       *)      usage_err "unknown command - $1";;
+esac
 
-# VERBOSE_MODE > 1 delete logfile if exist to create an empty one
+# set file names
+PIDFILE="$ddns_rundir/$SECTION_ID.pid" # Process ID file
+UPDFILE="$ddns_rundir/$SECTION_ID.update"      # last update successful send (system uptime)
+DATFILE="$ddns_rundir/$SECTION_ID.dat" # save stdout data of WGet and other extern programs called
+ERRFILE="$ddns_rundir/$SECTION_ID.err" # save stderr output of WGet and other extern programs called
+IPFILE="$ddns_rundir/$SECTION_ID.ip"   #
+LOGFILE="$ddns_logdir/$SECTION_ID.log" # log file
+
+# VERBOSE > 1 delete logfile if exist to create an empty one
 # only with this data of this run for easier diagnostic
 # new one created by write_log function
-[ $VERBOSE_MODE -gt 1 -a -f $LOGFILE ] && rm -f $LOGFILE
+[ $VERBOSE -gt 1 -a -f $LOGFILE ] && rm -f $LOGFILE
 
 # TRAP handler
 trap "trap_handler 0 \$?" 0    # handle script exit with exit status
 trap "trap_handler 1"  1       # SIGHUP        Hangup / reload config
 trap "trap_handler 2"  2       # SIGINT        Terminal interrupt
 trap "trap_handler 3"  3       # SIGQUIT       Terminal quit
-#trap "trap_handler 9"  9      # SIGKILL       no chance to trap
+# trap "trap_handler 9"  9     # SIGKILL       no chance to trap
 trap "trap_handler 15" 15      # SIGTERM       Termination
 
 ################################################################################
@@ -67,17 +125,20 @@ trap "trap_handler 15" 15  # SIGTERM       Termination
 # config_get <variable> $SECTION_ID <option>
 #
 # defined options (also used as variable):
-# 
-# enable       self-explanatory
+#
+# enabled      self-explanatory
 # interface    network interface used by hotplug.d i.e. 'wan' or 'wan6'
 #
 # service_name Which DDNS service do you use or "custom"
 # update_url   URL to use to update your "custom" DDNS service
 # update_script SCRIPT to use to update your "custom" DDNS service
 #
-# domain       Your DNS name / replace [DOMAIN] in update_url
-# username     Username of your DDNS service account / replace [USERNAME] in update_url
-# password     Password of your DDNS service account / replace [PASSWORD] in update_url
+# lookup_host  FQDN of ONE of your at DDNS service defined host / required to validate if IP update happen/necessary
+# domain       Nomally your DDNS hostname / replace [DOMAIN] in update_url
+# username     Username of your DDNS service account / urlenceded and replace [USERNAME] in update_url
+# password     Password of your DDNS service account / urlencoded and replace [PASSWORD] in update_url
+# param_enc    Optional parameter for (later) usage  / urlencoded and replace [PARAMENC] in update_url
+# param_opt    Optional parameter for (later) usage  / replace [PARAMOPT] in update_url
 #
 # use_https    use HTTPS to update DDNS service
 # cacert       file or directory where HTTPS can find certificates to verify server; 'IGNORE' ignore check of server certificate
@@ -88,9 +149,9 @@ trap "trap_handler 15" 15    # SIGTERM       Termination
 # ip_network   local defined network to read IP from i.e. 'wan' or 'wan6'
 # ip_url       URL to read local address from i.e. http://checkip.dyndns.com/ or http://checkipv6.dyndns.com/
 # ip_script    full path and name of your script to detect local IP
-# ip_interface physical interface to use for detecting 
+# ip_interface physical interface to use for detecting
 #
-# check_interval       check for changes every  !!! checks below 10 minutes make no sense because the Internet 
+# check_interval       check for changes every  !!! checks below 10 minutes make no sense because the Internet
 # check_unit           'days' 'hours' 'minutes' !!! needs about 5-10 minutes to sync an IP-change for an DNS entry
 #
 # force_interval       force to send an update to your service if no change was detected
@@ -98,71 +159,129 @@ trap "trap_handler 15" 15 # SIGTERM       Termination
 #
 # retry_interval       if error was detected retry in
 # retry_unit           'days' 'hours' 'minutes' 'seconds'
-# retry_count          #NEW# number of retries before scripts stops
+# retry_max_count      number of retries before scripts stops
 #
-# use_ipv6             #NEW# detecting/sending IPv6 address
-# force_ipversion      #NEW# force usage of IPv4 or IPv6 for the whole detection and update communication
-# dns_server           #NEW# using a non default dns server to get Registered IP from Internet
-# force_dnstcp         #NEW# force communication with DNS server via TCP instead of default UDP
-# proxy                        #NEW# using a proxy for communication !!! ALSO used to detect local IP via web => return proxy's IP !!!
-# use_logfile          #NEW# self-explanatory "/var/log/ddns/$SECTION_ID.log"
+# use_ipv6             detecting/sending IPv6 address
+# force_ipversion      force usage of IPv4 or IPv6 for the whole detection and update communication
+# dns_server           using a non default dns server to get Registered IP from Internet
+# force_dnstcp         force communication with DNS server via TCP instead of default UDP
+# proxy                        using a proxy for communication !!! ALSO used to detect local IP via web => return proxy's IP !!!
+# use_logfile          self-explanatory "/var/log/ddns/$SECTION_ID.log"
+# is_glue                      the record that should be updated is a glue record
 #
-# some functionality needs 
+# some functionality needs
 # - GNU Wget or cURL installed for sending updates to DDNS service
 # - BIND host installed to detect Registered IP
 #
 ################################################################################
 
-# verify and load SECTION_ID is exists
-[ "$(uci_get ddns $SECTION_ID)" != "service" ] && {
-       [ $VERBOSE_MODE -le 1 ] && VERBOSE_MODE=2       # force console out and logfile output
-       [ -f $LOGFILE ] && rm -f $LOGFILE               # clear logfile before first entry
-       write_log  7 "************ ************** ************** **************"
-       write_log  5 "PID '$$' started at $(eval $DATE_PROG)"
-       write_log  7 "uci configuration:\n$(uci -q show ddns | grep '=service' | sort)"
-       write_log 14 "Service section '$SECTION_ID' not defined"
-}
 load_all_config_options "ddns" "$SECTION_ID"
-
-write_log  7 "************ ************** ************** **************"
-write_log  5 "PID '$$' started at $(eval $DATE_PROG)"
-case $VERBOSE_MODE in
-       0) write_log  7 "verbose mode '0' - run normal, NO console output";;
-       1) write_log  7 "verbose mode '1' - run normal, console mode";;
-       2) write_log  7 "verbose mode '2' - run once, NO retry on error";;
-       3) write_log  7 "verbose mode '3' - run once, NO retry on error, NOT sending update";;
-       *) write_log 14 "error detecting VERBOSE_MODE '$VERBOSE_MODE'";;
-esac
-write_log 7 "uci configuraion:\n$(uci -q show ddns.$SECTION_ID | sort)"
+ERR_LAST=$?    # save return code - equal 0 if SECTION_ID found
 
 # set defaults if not defined
 [ -z "$enabled" ]        && enabled=0
-[ -z "$retry_count" ]    && retry_count=5
-[ -z "$use_syslog" ]      && use_syslog=0      # not use syslog
+[ -z "$retry_max_count" ] && retry_max_count=0 # endless retry
+[ -z "$use_syslog" ]      && use_syslog=2      # syslog "Notice"
 [ -z "$use_https" ]       && use_https=0       # not use https
-[ -z "$use_logfile" ]     && use_logfile=1     # NEW - use logfile by default
-[ -z "$use_ipv6" ]       && use_ipv6=0         # NEW - use IPv4 by default
-[ -z "$force_ipversion" ] && force_ipversion=0 # NEW - default let system decide
-[ -z "$force_dnstcp" ]   && force_dnstcp=0     # NEW - default UDP
+[ -z "$use_logfile" ]     && use_logfile=1     # use logfile by default
+[ -z "$use_ipv6" ]       && use_ipv6=0         # use IPv4 by default
+[ -z "$force_ipversion" ] && force_ipversion=0 # default let system decide
+[ -z "$force_dnstcp" ]   && force_dnstcp=0     # default UDP
 [ -z "$ip_source" ]      && ip_source="network"
+[ -z "$is_glue" ]        && is_glue=0          # default the ddns record is not a glue record
 [ "$ip_source" = "network" -a -z "$ip_network" -a $use_ipv6 -eq 0 ] && ip_network="wan"  # IPv4: default wan
 [ "$ip_source" = "network" -a -z "$ip_network" -a $use_ipv6 -eq 1 ] && ip_network="wan6" # IPv6: default wan6
 [ "$ip_source" = "web" -a -z "$ip_url" -a $use_ipv6 -eq 0 ] && ip_url="http://checkip.dyndns.com"
 [ "$ip_source" = "web" -a -z "$ip_url" -a $use_ipv6 -eq 1 ] && ip_url="http://checkipv6.dyndns.com"
 [ "$ip_source" = "interface" -a -z "$ip_interface" ] && ip_interface="eth1"
 
+# url encode username (might be email or something like this)
+# and password (might have special chars for security reason)
+# and optional parameter "param_enc"
+[ -n "$username" ] && urlencode URL_USER "$username"
+[ -n "$password" ] && urlencode URL_PASS "$password"
+[ -n "$param_enc" ] && urlencode URL_PENC "$param_enc"
+
+# SECTION_ID does not exists
+[ $ERR_LAST -ne 0 ] && {
+       [ $VERBOSE -le 1 ] && VERBOSE=2         # force console out and logfile output
+       [ -f $LOGFILE ] && rm -f $LOGFILE       # clear logfile before first entry
+       write_log  7 "************ ************** ************** **************"
+       write_log  5 "PID '$$' started at $(eval $DATE_PROG)"
+       write_log  7 "ddns version  : $VERSION"
+       write_log  7 "uci configuration:${N}$(uci -q show ddns | grep '=service' | sort)"
+       write_log 14 "Service section '$SECTION_ID' not defined"
+}
+
+write_log 7 "************ ************** ************** **************"
+write_log 5 "PID '$$' started at $(eval $DATE_PROG)"
+write_log 7 "ddns version  : $VERSION"
+write_log 7 "uci configuration:${N}$(uci -q show ddns.$SECTION_ID | sort)"
+# write_log 7 "ddns version  : $(opkg list-installed ddns-scripts | cut -d ' ' -f 3)"
+case $VERBOSE in
+       0) write_log  7 "verbose mode  : 0 - run normal, NO console output";;
+       1) write_log  7 "verbose mode  : 1 - run normal, console mode";;
+       2) write_log  7 "verbose mode  : 2 - run once, NO retry on error";;
+       3) write_log  7 "verbose mode  : 3 - run once, NO retry on error, NOT sending update";;
+       *) write_log 14 "error detecting VERBOSE '$VERBOSE'";;
+esac
+
 # check enabled state otherwise we don't need to continue
 [ $enabled -eq 0 ] && write_log 14 "Service section disabled!"
 
-# without domain or username or password we can do nothing for you
-[ -z "$domain" -o -z "$username" -o -z "$password" ] && write_log 14 "Service section not correctly configured!"
-urlencode URL_USER "$username" # encode username, might be email or something like this
-urlencode URL_PASS "$password" # encode password, might have special chars for security reason
+# determine what update url we're using if a service_name is supplied
+# otherwise update_url is set inside configuration (custom update url)
+# or update_script is set inside configuration (custom update script)
+[ -n "$service_name" ] && {
+       # Check first if we have a custom service provider with this name
+       get_service_data "$service_name" "/usr/share/ddns/custom" update_url update_script UPD_ANSWER
+       if [ "$?" != "0" ]; then
+               get_service_data "$service_name" "/usr/share/ddns/default" update_url update_script UPD_ANSWER
+       fi
+}
+
+[ -z "$update_url" -a -z "$update_script" ] && write_log 14 "No update_url found/defined or no update_script found/defined!"
+[ -n "$update_script" -a ! -f "$update_script" ] && write_log 14 "Custom update_script not found!"
 
-# verify ip_source script if configured and executable
+# temporary needed to convert existing uci settings
+[ -z "$lookup_host" ] && {
+       uci -q set ddns.$SECTION_ID.lookup_host="$domain"
+       uci -q commit ddns
+       lookup_host="$domain"
+}
+# later versions only check if configured correctly
+
+# without lookup host and possibly other required options we can do nothing for you
+[ -z "$lookup_host" ] && write_log 14 "Service section not configured correctly! Missing 'lookup_host'"
+
+# verify validity of variables
+[ -n "$lookup_host" ] && sanitize_variable lookup_host "$DNS_CHARSET" ""
+[ -n "$dns_server" ] && sanitize_variable dns_server "$DNS_CHARSET" ""
+[ -n "$domain" ] && sanitize_variable domain "$DNS_CHARSET_DOMAIN" ""
+
+# Filter shell escape characters, if these are required in the URL, they
+# can still be passed url encoded
+[ -n "$param_opt" ] && sanitize_variable param_opt "" "$SHELL_ESCAPE"
+
+[ -n "$update_url" ] && {
+       # only check if update_url is given, update_scripts have to check themselves
+       [ -z "$domain" ] && $(echo "$update_url" | grep "\[DOMAIN\]" >/dev/null 2>&1) && \
+               write_log 14 "Service section not configured correctly! Missing 'domain'"
+       [ -z "$username" ] && $(echo "$update_url" | grep "\[USERNAME\]" >/dev/null 2>&1) && \
+               write_log 14 "Service section not configured correctly! Missing 'username'"
+       [ -z "$password" ] && $(echo "$update_url" | grep "\[PASSWORD\]" >/dev/null 2>&1) && \
+               write_log 14 "Service section not configured correctly! Missing 'password'"
+       [ -z "$param_enc" ] && $(echo "$update_url" | grep "\[PARAMENC\]" >/dev/null 2>&1) && \
+               write_log 14 "Service section not configured correctly! Missing 'param_enc'"
+       [ -z "$param_opt" ] && $(echo "$update_url" | grep "\[PARAMOPT\]" >/dev/null 2>&1) && \
+               write_log 14 "Service section not configured correctly! Missing 'param_opt'"
+}
+
+# verify ip_source 'script' if script is configured and executable
 if [ "$ip_source" = "script" ]; then
-       [ -z "$ip_script" ] && write_log 14 "No script defined to detect local IP!"
-       [ -x "$ip_script" ] || write_log 14 "Script to detect local IP not found or not executable!"
+       set -- $ip_script       #handling script with parameters, we need a trick
+       [ -z "$1" ] && write_log 14 "No script defined to detect local IP!"
+       [ -x "$1" ] || write_log 14 "Script to detect local IP not executable!"
 fi
 
 # compute update interval in seconds
@@ -174,32 +293,18 @@ get_seconds RETRY_SECONDS ${retry_interval:-60} ${retry_unit:-"seconds"} # defau
 write_log 7 "check interval: $CHECK_SECONDS seconds"
 write_log 7 "force interval: $FORCE_SECONDS seconds"
 write_log 7 "retry interval: $RETRY_SECONDS seconds"
-write_log 7 "retry counter : $retry_count times"
-
-# determine what update url we're using if a service_name is supplied
-# otherwise update_url is set inside configuration (custom update url)
-# or update_script is set inside configuration (custom update script)
-[ -n "$service_name" ] && get_service_data update_url update_script
-[ -z "$update_url" -a -z "$update_script" ] && write_log 14 "No update_url found/defined or no update_script found/defined!"
-[ -n "$update_script" -a ! -f "$update_script" ] && write_log 14 "Custom update_script not found!"
+write_log 7 "retry max count : $retry_max_count times"
 
-#kill old process if it exists & set new pid file
-if [ -d $RUNDIR ]; then
-       #if process for section is already running, stop it
-       stop_section_processes "$SECTION_ID"
-       [ $? -gt 0 ] && write_log 7 "Send 'SIGTERM' to old process" || write_log 7 "No old process"
-else
-       #make dir since it doesn't exist
-       mkdir -p $RUNDIR
-       write_log 7 "No old process"
-fi
+# kill old process if it exists & set new pid file
+stop_section_processes "$SECTION_ID"
+[ $? -gt 0 ] && write_log 7 "'SIGTERM' was send to old process" || write_log 7 "No old process"
 echo $$ > $PIDFILE
 
 # determine when the last update was
-# the following lines should prevent multiple updates if hotplug fires multiple startups 
+# the following lines should prevent multiple updates if hotplug fires multiple startups
 # as described in Ticket #7820, but did not function if never an update take place
 # i.e. after a reboot (/var is linked to /tmp)
-# using uptime as reference because date might not be updated via NTP client 
+# using uptime as reference because date might not be updated via NTP client
 get_uptime CURR_TIME
 [ -e "$UPDFILE" ] && {
        LAST_TIME=$(cat $UPDFILE)
@@ -211,20 +316,12 @@ get_uptime CURR_TIME
 if [ $LAST_TIME -eq 0 ]; then
        write_log 7 "last update: never"
 else
-       EPOCH_TIME=$(( $(date +%s) - CURR_TIME + LAST_TIME ))
-       EPOCH_TIME="date -d @$EPOCH_TIME +'$DATE_FORMAT'"
+       EPOCH_TIME=$(( $(date +%s) - $CURR_TIME + $LAST_TIME ))
+       EPOCH_TIME="date -d @$EPOCH_TIME +'$ddns_dateformat'"
        write_log 7 "last update: $(eval $EPOCH_TIME)"
 fi
 
-# we need time here because hotplug.d is fired by netifd
-# but IP addresses are not set by DHCP/DHCPv6 etc.
-write_log 7 "Waiting 10 seconds for interfaces to fully come up"
-sleep 10 &
-PID_SLEEP=$!
-wait $PID_SLEEP        # enable trap-handler
-PID_SLEEP=0
-
-# verify DNS server 
+# verify DNS server
 [ -n "$dns_server" ] && verify_dns "$dns_server"
 
 # verify Proxy server and set environment
@@ -238,15 +335,20 @@ PID_SLEEP=0
        }
 }
 
-# let's check if there is already an IP registered at the web
-# but ignore errors if not
+# let's check if there is already an IP registered on the web
 get_registered_ip REGISTERED_IP "NO_RETRY"
+ERR_LAST=$?
+#     No error    or     No IP set      otherwise retry
+[ $ERR_LAST -eq 0 -o $ERR_LAST -eq 127 ] || get_registered_ip REGISTERED_IP
+# on IPv6 we use expanded version to be shure when comparing
+[ $use_ipv6 -eq 1 ] && expand_ipv6 "$REGISTERED_IP" REGISTERED_IP
 
 # loop endlessly, checking ip every check_interval and forcing an updating once every force_interval
 write_log 6 "Starting main loop at $(eval $DATE_PROG)"
 while : ; do
 
        get_local_ip LOCAL_IP           # read local IP
+       [ $use_ipv6 -eq 1 ] && expand_ipv6 "$LOCAL_IP" LOCAL_IP # on IPv6 we use expanded version
 
        # prepare update
        # never updated or forced immediate then NEXT_TIME = 0
@@ -258,8 +360,8 @@ while : ; do
 
        # send update when current time > next time or local ip different from registered ip
        if [ $CURR_TIME -ge $NEXT_TIME -o "$LOCAL_IP" != "$REGISTERED_IP" ]; then
-               if [ $VERBOSE_MODE -gt 2 ]; then
-                       write_log 7 "Verbose Mode: $VERBOSE_MODE - NO UPDATE send"
+               if [ $VERBOSE -gt 2 ]; then
+                       write_log 7 "Verbose Mode: $VERBOSE - NO UPDATE send"
                elif [ "$LOCAL_IP" != "$REGISTERED_IP" ]; then
                        write_log 7 "Update needed - L: '$LOCAL_IP' <> R: '$REGISTERED_IP'"
                else
@@ -267,59 +369,67 @@ while : ; do
                fi
 
                ERR_LAST=0
-               [ $VERBOSE_MODE -lt 3 ] && {
-                       # only send if VERBOSE_MODE < 3
+               [ $VERBOSE -lt 3 ] && {
+                       # only send if VERBOSE < 3
                        send_update "$LOCAL_IP"
                        ERR_LAST=$?     # save return value
                }
 
-               # error sending local IP to provider 
+               # error sending local IP to provider
                # we have no communication error (handled inside send_update/do_transfer)
                # but update was not recognized
                # do NOT retry after RETRY_SECONDS, do retry after CHECK_SECONDS
                # to early retrys will block most DDNS provider
                # providers answer is checked inside send_update() function
-               [ $ERR_LAST -eq 0 ] && {
+               if [ $ERR_LAST -eq 0 ]; then
                        get_uptime LAST_TIME            # we send update, so
                        echo $LAST_TIME > $UPDFILE      # save LASTTIME to file
                        [ "$LOCAL_IP" != "$REGISTERED_IP" ] \
                                && write_log 6 "Update successful - IP '$LOCAL_IP' send" \
                                || write_log 6 "Forced update successful - IP: '$LOCAL_IP' send"
-               } || write_log 3 "Can not update IP at DDNS Provider"
+               elif [ $ERR_LAST -eq 127 ]; then
+                       write_log 3 "No update send to DDNS Provider"
+               else
+                       write_log 3 "IP update not accepted by DDNS Provider"
+               fi
        fi
 
        # now we wait for check interval before testing if update was recognized
-       # only sleep if VERBOSE_MODE <= 2 because otherwise nothing was send
-       [ $VERBOSE_MODE -le 2 ] && {
+       # only sleep if VERBOSE <= 2 because otherwise nothing was send
+       [ $VERBOSE -le 2 ] && {
                write_log 7 "Waiting $CHECK_SECONDS seconds (Check Interval)"
                sleep $CHECK_SECONDS &
                PID_SLEEP=$!
                wait $PID_SLEEP # enable trap-handler
                PID_SLEEP=0
-       } || write_log 7 "Verbose Mode: $VERBOSE_MODE - NO Check Interval waiting"
+       } || write_log 7 "Verbose Mode: $VERBOSE - NO Check Interval waiting"
 
        REGISTERED_IP=""                # clear variable
        get_registered_ip REGISTERED_IP # get registered/public IP
+       [ $use_ipv6 -eq 1 ] && expand_ipv6 "$REGISTERED_IP" REGISTERED_IP       # on IPv6 we use expanded version
 
        # IP's are still different
        if [ "$LOCAL_IP" != "$REGISTERED_IP" ]; then
-               if [ $VERBOSE_MODE -le 1 ]; then        # VERBOSE_MODE <=1 then retry
+               if [ $VERBOSE -le 1 ]; then     # VERBOSE <=1 then retry
                        ERR_UPDATE=$(( $ERR_UPDATE + 1 ))
-                       [ $ERR_UPDATE -gt $retry_count ] && write_log 14 "Updating IP at DDNS provider failed after $retry_count retries"
-                       write_log 4 "Updating IP at DDNS provider failed - starting retry $ERR_UPDATE/$retry_count"
+                       [ $retry_max_count -gt 0 -a $ERR_UPDATE -gt $retry_max_count ] && \
+                               write_log 14 "Updating IP at DDNS provider failed after $retry_max_count retries"
+                       write_log 4 "Updating IP at DDNS provider failed - starting retry $ERR_UPDATE/$retry_max_count"
                        continue # loop to beginning
                else
                        write_log 4 "Updating IP at DDNS provider failed"
-                       write_log 7 "Verbose Mode: $VERBOSE_MODE - NO retry"; exit 1
+                       write_log 7 "Verbose Mode: $VERBOSE - NO retry"; exit 1
                fi
        else
                # we checked successful the last update
                ERR_UPDATE=0                    # reset error counter
        fi
 
-       # force_update=0 or VERBOSE_MODE > 1 - leave here
-       [ $VERBOSE_MODE -gt 1 ]  && write_log 7 "Verbose Mode: $VERBOSE_MODE - NO reloop"; exit 0
-       [ $FORCE_SECONDS -eq 0 ] && write_log 6 "Configured to run once"; exit 0
+       # force_update=0 or VERBOSE > 1 - leave here
+       [ $VERBOSE -gt 1 ]  && write_log 7 "Verbose Mode: $VERBOSE - NO reloop"
+       [ $FORCE_SECONDS -eq 0 ] && write_log 6 "Configured to run once"
+       [ $VERBOSE -gt 1 -o $FORCE_SECONDS -eq 0 ] && exit 0
+
        write_log 6 "Rerun IP check at $(eval $DATE_PROG)"
 done
 # we should never come here there must be a programming error