diff options
author | Christian Schoenebeck <christian.schoenebeck@gmail.com> | 2014-11-09 16:37:11 +0100 |
---|---|---|
committer | Christian Schoenebeck <christian.schoenebeck@gmail.com> | 2014-11-09 16:37:11 +0100 |
commit | 419265144890548d65608e7c3deb37d4d8f476af (patch) | |
tree | 95b0c67dda1e332e1a5fc15e5ca89c1871750ef9 /net/ddns-scripts/files/usr/lib | |
parent | 43d2457b9891dce4def5e95d65cd33a30ca1c24e (diff) |
ddns-scripts: Update to Version 2.1.0-1 see description
- fixed postinst and prerm in Makefile
- implementation of provider specific update scripts into services and
services_ipv6 file.
first Provider "no-ip.com" - Thanks to DarkStarXxX for
request and testing
- finished uci/ddns wiki at http://wiki.openwrt.org/doc/uci/ddns
- rewritten retry management
- rewritten logging including following Issue 469
https://github.com/openwrt/packages/issues/469
- stop running sections on hotplug ifdown event (like start on ifup)
- implement trap detection
also kill "sleep" child processes
SIGHUP to reload configuration (not really reloading, simply
starting a new process)
/etc/init.d/ddns reload implemented
- code optimization
- new provider LoopiaDNS.se Issue 494
https://github.com/openwrt/packages/issues/494
Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com>
Diffstat (limited to 'net/ddns-scripts/files/usr/lib')
-rw-r--r-- | net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_functions.sh | 722 | ||||
-rwxr-xr-x | net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_updater.sh | 340 | ||||
-rw-r--r-- | net/ddns-scripts/files/usr/lib/ddns/services | 58 | ||||
-rw-r--r-- | net/ddns-scripts/files/usr/lib/ddns/services_ipv6 | 54 | ||||
-rw-r--r-- | net/ddns-scripts/files/usr/lib/ddns/update_no-ip.sh | 47 | ||||
-rw-r--r-- | net/ddns-scripts/files/usr/lib/ddns/update_sample.sh | 24 |
6 files changed, 704 insertions, 541 deletions
diff --git a/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_functions.sh b/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_functions.sh index aeabe5280..f535d033c 100644 --- a/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_functions.sh +++ b/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_functions.sh @@ -16,7 +16,7 @@ # - the usage of BIND's host instead of BusyBox's nslookup if installed (DNS via TCP) # - extended Verbose Mode and log file support for better error detection # -# function __timeout +# function timeout # copied from http://www.ict.griffith.edu.au/anthony/software/timeout.sh # @author Anthony Thyssen 6 April 2011 # @@ -31,7 +31,6 @@ # GLOBAL VARIABLES # SECTION_ID="" # hold config's section name VERBOSE_MODE=1 # default mode is log to console, but easily changed with parameter -LUCI_HELPER="" # set by dynamic_dns_lucihelper.sh, if filled supress all error logging PIDFILE="" # pid file UPDFILE="" # store UPTIME of last update @@ -43,13 +42,12 @@ LOGDIR=$(uci -q get ddns.global.log_dir) || LOGDIR="/var/log/ddns" LOGFILE="" # NEW # logfile can be enabled as new option # number of lines to before rotate logfile LOGLINES=$(uci -q get ddns.global.log_lines) || LOGLINES=250 +LOGLINES=$((LOGLINES + 1)) # correct sed handling CHECK_SECONDS=0 # calculated seconds out of given FORCE_SECONDS=0 # interval and unit RETRY_SECONDS=0 # in configuration -OLD_PID=0 # Holds the PID of already running process for the same config section - LAST_TIME=0 # holds the uptime of last successful update CURR_TIME=0 # holds the current uptime NEXT_TIME=0 # calculated time for next FORCED update @@ -58,12 +56,13 @@ EPOCH_TIME=0 # seconds since 1.1.1970 00:00:00 REGISTERED_IP="" # holds the IP read from DNS LOCAL_IP="" # holds the local IP read from the box +URL_USER="" # url encoded $username from config file +URL_PASS="" # url encoded $password from config file + ERR_LAST=0 # used to save $? return code of program and function calls -ERR_LOCAL_IP=0 # error counter on getting local ip -ERR_REG_IP=0 # error counter on getting DNS registered ip -ERR_SEND=0 # error counter on sending update to DNS provider ERR_UPDATE=0 # error counter on different local and registered ip -ERR_VERIFY=0 # error counter verifying proxy- and dns-servers + +PID_SLEEP=0 # ProcessID of current background "sleep" # format to show date information in log and luci-app-ddns default ISO 8601 format DATE_FORMAT=$(uci -q get ddns.global.date_format) || DATE_FORMAT="%F %R" @@ -113,9 +112,26 @@ load_all_config_options() return 0 } +# read's all service sections from ddns config +# $1 = Name of variable to store +load_all_service_sections() { + local __DATA="" + config_cb() + { + # only look for section type "service", ignore everything else + [ "$1" = "service" ] && __DATA="$__DATA $2" + } + config_load "ddns" + + eval "$1='$__DATA'" + return +} + # starts updater script for all given sections or only for the one given # $1 = interface (Optional: when given only scripts are started # configured for that interface) +# used by /etc/hotplug.d/iface/25-ddns on IFUP +# and by /etc/init.d/ddns start start_daemon_for_all_ddns_sections() { local __EVENTIF="$1" @@ -123,59 +139,102 @@ start_daemon_for_all_ddns_sections() local __SECTIONID="" local __IFACE="" - config_cb() - { - # only look for section type "service", ignore everything else - [ "$1" = "service" ] && __SECTIONS="$__SECTIONS $2" + load_all_service_sections __SECTIONS + for __SECTIONID in $__SECTIONS; do + config_get __IFACE "$__SECTIONID" interface "wan" + [ -z "$__EVENTIF" -o "$__IFACE" = "$__EVENTIF" ] || continue + /usr/lib/ddns/dynamic_dns_updater.sh $__SECTIONID 0 > /dev/null 2>&1 & + done +} + +# stop sections process incl. childs (sleeps) +# $1 = section +stop_section_processes() { + local __PID=0 + local __PIDFILE="$RUNDIR/$1.pid" + [ $# -ne 1 ] && write_log 12 "Error calling 'stop_section_processes()' - wrong number of parameters" + + [ -e "$__PIDFILE" ] && { + __PID=$(cat $__PIDFILE) + ps | grep "^[\t ]*$__PID" >/dev/null 2>&1 && kill $__PID || __PID=0 # terminate it } - config_load "ddns" + [ $__PID -eq 0 ] # report if process was running +} - for __SECTIONID in $__SECTIONS - do +# stop updater script for all defines sections or only for one given +# $1 = interface (optional) +# used by /etc/hotplug.d/iface/25-ddns on 'ifdown' +# and by /etc/init.d/ddns stop +# needed because we also need to kill "sleep" child processes +stop_daemon_for_all_ddns_sections() { + local __EVENTIF="$1" + local __SECTIONS="" + local __SECTIONID="" + local __IFACE="" + + load_all_service_sections __SECTIONS + for __SECTIONID in $__SECTIONS; do config_get __IFACE "$__SECTIONID" interface "wan" [ -z "$__EVENTIF" -o "$__IFACE" = "$__EVENTIF" ] || continue - /usr/lib/ddns/dynamic_dns_updater.sh $__SECTIONID 0 > /dev/null 2>&1 & + stop_section_processes "$__SECTIONID" done } -verbose_echo() -{ - [ -n "$LUCI_HELPER" ] && return # nothing to report when used by LuCI helper script - [ $VERBOSE_MODE -gt 0 ] && echo -e " $*" - if [ ${use_logfile:-0} -eq 1 -o $VERBOSE_MODE -gt 1 ]; then +# reports to console, logfile, syslog +# $1 loglevel 7 == Debug to 0 == EMERG +# value +10 will exit the scripts +# $2..n text to report +write_log() { + local __LEVEL __EXIT __CMD __MSG + local __TIME=$(date +%H%M%S) + [ $1 -ge 10 ] && { + __LEVEL=$(($1-10)) + __EXIT=1 + } || { + __LEVEL=$1 + __EXIT=0 + } + shift # remove loglevel + [ $__EXIT -eq 0 ] && __MSG="$*" || __MSG="$* - TERMINATE" + case $__LEVEL in # create log message and command depending on loglevel + 0) __CMD="logger -p user.emerg -t ddns-scripts[$$] $SECTION_ID: $__MSG" + __MSG=" $__TIME EMERG : $__MSG" ;; + 1) __CMD="logger -p user.alert -t ddns-scripts[$$] $SECTION_ID: $__MSG" + __MSG=" $__TIME ALERT : $__MSG" ;; + 2) __CMD="logger -p user.crit -t ddns-scripts[$$] $SECTION_ID: $__MSG" + __MSG=" $__TIME CRIT : $__MSG" ;; + 3) __CMD="logger -p user.err -t ddns-scripts[$$] $SECTION_ID: $__MSG" + __MSG=" $__TIME ERROR : $__MSG" ;; + 4) __CMD="logger -p user.warn -t ddns-scripts[$$] $SECTION_ID: $__MSG" + __MSG=" $__TIME WARN : $__MSG" ;; + 5) __CMD="logger -p user.notice -t ddns-scripts[$$] $SECTION_ID: $__MSG" + __MSG=" $__TIME note : $__MSG" ;; + 6) __CMD="logger -p user.info -t ddns-scripts[$$] $SECTION_ID: $__MSG" + __MSG=" $__TIME info : $__MSG" ;; + 7) __MSG=" $__TIME : $__MSG";; + *) return;; + esac + + # verbose echo + [ $VERBOSE_MODE -gt 0 -o $__EXIT -gt 0 ] && echo -e "$__MSG" + # write to logfile + if [ ${use_logfile:-1} -eq 1 -o $VERBOSE_MODE -gt 1 ]; then [ -d $LOGDIR ] || mkdir -p -m 755 $LOGDIR - echo -e " $*" >> $LOGFILE + echo -e "$__MSG" >> $LOGFILE # VERBOSE_MODE > 1 then NO loop so NO truncate log to $LOGLINES lines [ $VERBOSE_MODE -gt 1 ] || sed -i -e :a -e '$q;N;'$LOGLINES',$D;ba' $LOGFILE fi + [ "$SECTION_ID" = "lucihelper" ] && return # nothing else todo when running LuCI helper script + [ $__LEVEL -eq 7 ] && return # no syslog for debug messages + [ $__EXIT -eq 1 ] && { + $__CMD # force syslog before exit + exit 1 + } + [ $use_syslog -eq 0 ] && return + [ $((use_syslog + __LEVEL)) -le 7 ] && $__CMD return } -syslog_info(){ - [ $use_syslog -eq 1 ] && logger -p user.info -t ddns-scripts[$$] "$SECTION_ID: $*" - return -} -syslog_notice(){ - [ $use_syslog -ge 1 -a $use_syslog -le 2 ] && logger -p user.notice -t ddns-scripts[$$] "$SECTION_ID: $*" - return -} -syslog_warn(){ - [ $use_syslog -ge 1 -a $use_syslog -le 3 ] && logger -p user.warn -t ddns-scripts[$$] "$SECTION_ID: $*" - return -} -syslog_err(){ - [ $use_syslog -ge 1 ] && logger -p user.err -t ddns-scripts[$$] "$SECTION_ID: $*" - return -} - -critical_error() { - [ -n "$LUCI_HELPER" ] && return # nothing to report when used by LuCI helper script - verbose_echo "\n CRITICAL ERROR =: $* - EXITING\n" - [ $VERBOSE_MODE -eq 0 ] && echo -e "\n$SECTION_ID: CRITICAL ERROR - $* - EXITING\n" - logger -t ddns-scripts[$$] -p user.crit "$SECTION_ID: CRITICAL ERROR - $* - EXITING" - exit 1 # critical error -> leave here -} - # replace all special chars to their %hex value # used for USERNAME and PASSWORD in update_url # unchanged: "-"(minus) "_"(underscore) "."(dot) "~"(tilde) @@ -183,13 +242,15 @@ critical_error() { # "$"(Dollar) # because used as variable output # tested with the following string stored via Luci Application as password / username # A B!"#AA$1BB%&'()*+,-./:;<=>?@[\]^_`{|}~ without problems at Dollar or quotes -__urlencode() { +urlencode() { # $1 Name of Variable to store encoded string to # $2 string to encode local __STR __LEN __CHAR __OUT local __ENC="" local __POS=1 + [ $# -ne 2 ] && write_log 12 "Error calling 'urlencode()' - wrong number of parameters" + __STR="$2" # read string to encode __LEN=${#__STR} # get string length @@ -218,14 +279,15 @@ __urlencode() { # extract url or script for given DDNS Provider from # file /usr/lib/ddns/services for IPv4 or from # file /usr/lib/ddns/services_ipv6 for IPv6 +# $1 Name of Variable to store url to +# $2 Name of Variable to store script to get_service_data() { - # $1 Name of Variable to store url to - # $2 Name of Variable to store script to local __LINE __FILE __NAME __URL __SERVICES __DATA local __SCRIPT="" local __OLD_IFS=$IFS local __NEWLINE_IFS=' ' #__NEWLINE_IFS + [ $# -ne 2 ] && write_log 12 "Error calling 'get_service_data()' - wrong number of parameters" __FILE="/usr/lib/ddns/services" # IPv4 [ $use_ipv6 -ne 0 ] && __FILE="/usr/lib/ddns/services_ipv6" # IPv6 @@ -256,10 +318,12 @@ get_service_data() { return 0 } +# Calculate seconds from interval and unit +# $1 Name of Variable to store result in +# $2 Number and +# $3 Unit of time interval get_seconds() { - # $1 Name of Variable to store result in - # $2 Number and - # $3 Unit of time interval + [ $# -ne 3 ] && write_log 12 "Error calling 'get_seconds()' - wrong number of parameters" case "$3" in "days" ) eval "$1=$(( $2 * 86400 ))";; "hours" ) eval "$1=$(( $2 * 3600 ))";; @@ -269,7 +333,7 @@ get_seconds() { return 0 } -__timeout() { +timeout() { # copied from http://www.ict.griffith.edu.au/anthony/software/timeout.sh # only did the folloing changes # - commented out "#!/bin/bash" and usage section @@ -314,7 +378,7 @@ __timeout() { SIG=-TERM - while [ $# -gt 0 ]; do + while [ $# -gt 0 ]; do case "$1" in --) # forced end of user options @@ -368,9 +432,10 @@ __timeout() { return $status } -__verify_host_port() { - # $1 Host/IP to verify - # $2 Port to verify +#verify given host and port is connectable +# $1 Host/IP to verify +# $2 Port to verify +verify_host_port() { local __HOST=$1 local __PORT=$2 local __TMP __IP __IPV4 __IPV6 __RUNPROG __ERRPROG __ERR @@ -380,92 +445,119 @@ __verify_host_port() { # 3 nc (netcat) error # 4 unmatched IP version + [ $# -ne 2 ] && write_log 12 "Error calling 'verify_host_port()' - wrong number of parameters" + __RUNPROG="nslookup $__HOST 2>/dev/null" __ERRPROG="nslookup $__HOST 2>&1" - verbose_echo " resolver prog =: '$__RUNPROG'" + write_log 7 "#> $__RUNPROG" __TMP=$(eval $__RUNPROG) # test if nslookup runs without errors __ERR=$? # command error [ $__ERR -gt 0 ] && { - verbose_echo "\n!!!!!!!!! ERROR =: BusyBox nslookup Error '$__ERR'\n$(eval $__ERRPROG)\n" - syslog_err "DNS Resolver Error - BusyBox nslookup Error '$__ERR'" + write_log 7 "Error:\n$(eval $__ERRPROG)" + write_log 3 "DNS Resolver Error - BusyBox nslookup Error '$__ERR'" return 2 - } || { - # we need to run twice because multi-line output needs to be directly piped to grep because - # pipe returns return code of last prog in pipe but we need errors from nslookup command - __IPV4=$(eval $__RUNPROG | sed -ne "3,\$ { s/^Address [0-9]*: \($IPV4_REGEX\).*$/\\1/p }") - __IPV6=$(eval $__RUNPROG | sed -ne "3,\$ { s/^Address [0-9]*: \($IPv6_REGEX\).*$/\\1/p }") } + # extract IP address + __IPV4=$(echo "$__TMP" | sed -ne "3,\$ { s/^Address [0-9]*: \($IPV4_REGEX\).*$/\\1/p }") + __IPV6=$(echo "$__TMP" | sed -ne "3,\$ { s/^Address [0-9]*: \($IPV6_REGEX\).*$/\\1/p }") # check IP version if forced if [ $force_ipversion -ne 0 ]; then __ERR=0 [ $use_ipv6 -eq 0 -a -z "$__IPV4" ] && __ERR=4 [ $use_ipv6 -eq 1 -a -z "$__IPV6" ] && __ERR=6 - [ $__ERR -gt 0 ] && critical_error "Invalid host: Error '4' - Force IP Version IPv$__ERR not supported" + [ $__ERR -gt 0 ] && { + [ "$SECTION_ID" = "lucihelper" ] && return 4 + write_log 14 "Invalid host Error '4' - Forced IP Version IPv$__ERR don't match" + } fi # verify nc command # busybox nc compiled without -l option "NO OPT l!" -> critical error - nc --help 2>&1 | grep -iq "NO OPT l!" && \ - critical_error "Busybox nc: netcat compiled without -l option, error 'NO OPT l!'" + nc --help 2>&1 | grep -i "NO OPT l!" >/dev/null 2>&1 && \ + write_log 12 "Busybox nc (netcat) compiled without '-l' option, error 'NO OPT l!'" # busybox nc compiled with extensions - nc --help 2>&1 | grep -q "\-w" && __NCEXT="TRUE" + nc --help 2>&1 | grep "\-w" >/dev/null 2>&1 && __NCEXT="TRUE" # connectivity test # run busybox nc to HOST PORT # busybox might be compiled with "FEATURE_PREFER_IPV4_ADDRESS=n" - # then nc will try to connect via IPv6 if there is an IPv6 availible for host - # not worring if there is an IPv6 wan address - # so if not "forced_ipversion" to use ipv6 then connect test via ipv4 if availible - [ $force_ipversion -ne 0 -a $use_ipv6 -ne 0 -o -z "$__IPV4" ] && { - # force IPv6 - __IP=$__IPV6 - } || __IP=$__IPV4 + # then nc will try to connect via IPv6 if there is any IPv6 availible on any host interface + # not worring, if there is an IPv6 wan address + # so if not "force_ipversion" to use_ipv6 then connect test via ipv4, if availible + [ $force_ipversion -ne 0 -a $use_ipv6 -ne 0 -o -z "$__IPV4" ] && __IP=$__IPV6 || __IP=$__IPV4 if [ -n "$__NCEXT" ]; then # nc compiled with extensions (timeout support) __RUNPROG="nc -w 1 $__IP $__PORT </dev/null >/dev/null 2>&1" __ERRPROG="nc -vw 1 $__IP $__PORT </dev/null 2>&1" - verbose_echo " connect prog =: '$__RUNPROG'" + write_log 7 "#> $__RUNPROG" eval $__RUNPROG __ERR=$? [ $__ERR -eq 0 ] && return 0 - verbose_echo "\n!!!!!!!!! ERROR =: BusyBox nc Error '$__ERR'\n$(eval $__ERRPROG)\n" - syslog_err "host verify Error - BusyBox nc Error '$__ERR'" + write_log 7 "Error:\n$(eval $__ERRPROG)" + write_log 3 "Connect error - BusyBox nc (netcat) Error '$__ERR'" return 3 else # nc compiled without extensions (no timeout support) - __RUNPROG="__timeout 2 -- nc $__IP $__PORT </dev/null >/dev/null 2>&1" - verbose_echo " connect prog =: '$__RUNPROG'" + __RUNPROG="timeout 2 -- nc $__IP $__PORT </dev/null >/dev/null 2>&1" + write_log 7 "#> $__RUNPROG" eval $__RUNPROG __ERR=$? [ $__ERR -eq 0 ] && return 0 - verbose_echo "\n!!!!!!!!! ERROR =: BusyBox nc Error '$__ERR' (timeout)" - syslog_err "host verify Error - BusyBox nc Error '$__ERR' (timeout)" + write_log 3 "Connect error - BusyBox nc (netcat) timeout Error '$__ERR'" return 3 fi } +# verfiy given DNS server if connectable +# $1 DNS server to verify verify_dns() { - # $1 DNS server to verify - # we need DNS server to verify otherwise exit with ERROR 1 - [ -z "$1" ] && return 1 + local __ERR=255 # last error buffer + local __CNT=0 # error counter + + [ $# -ne 1 ] && write_log 12 "Error calling 'verify_dns()' - wrong number of parameters" + write_log 7 "Verify DNS server '$1'" - # DNS uses port 53 - __verify_host_port "$1" "53" + while [ $__ERR -gt 0 ]; do + # DNS uses port 53 + verify_host_port "$1" "53" + __ERR=$? + if [ "$SECTION_ID" = "lucihelper" ]; then # no retry if called by LuCI helper script + return $__ERR + elif [ $__ERR -gt 0 -a $VERBOSE_MODE -gt 1 ]; then # VERBOSE_MODE > 1 then NO retry + write_log 7 "Verbose Mode: $VERBOSE_MODE - NO retry on error" + return $__ERR + elif [ $__ERR -gt 0 ]; then + __CNT=$(( $__CNT + 1 )) # increment error counter + # if error count > retry_count leave here + [ $__CNT -gt $retry_count ] && \ + write_log 14 "Verify DNS server '$1' failed after $retry_count retries" + + write_log 4 "Verify DNS server '$1' failed - retry $__CNT/$retry_count in $RETRY_SECONDS seconds" + sleep $RETRY_SECONDS & + PID_SLEEP=$! + wait $PID_SLEEP # enable trap-handler + PID_SLEEP=0 + fi + done + return 0 } +# analyse and verfiy given proxy string +# $1 Proxy-String to verify verify_proxy() { - # $1 Proxy-String to verify - # complete entry user:password@host:port - # inside user and password NO '@' of ":" allowed - # host and port only host:port - # host only host ERROR unsupported - # IPv4 address instead of host 123.234.234.123 - # IPv6 address instead of host [xxxx:....:xxxx] in square bracket + # complete entry user:password@host:port + # inside user and password NO '@' of ":" allowed + # host and port only host:port + # host only host ERROR unsupported + # IPv4 address instead of host 123.234.234.123 + # IPv6 address instead of host [xxxx:....:xxxx] in square bracket local __TMP __HOST __PORT + local __ERR=255 # last error buffer + local __CNT=0 # error counter - # we need Proxy-Sting to verify otherwise exit with ERROR 1 - [ -z "$1" ] && return 1 + [ $# -ne 1 ] && write_log 12 "Error calling 'verify_proxy()' - wrong number of parameters" + write_log 7 "Verify Proxy server 'http://$1'" # try to split user:password "@" host:port __TMP=$(echo $1 | awk -F "@" '{print $2}') @@ -481,24 +573,51 @@ verify_proxy() { __HOST=$(echo $__TMP | awk -F ":" '{print $1}') __PORT=$(echo $__TMP | awk -F ":" '{print $2}') fi - # No Port detected - [ -z "$__PORT" ] && critical_error "Invalid Proxy server Error '5' - proxy port missing" + # No Port detected - EXITING + [ -z "$__PORT" ] && { + [ "$SECTION_ID" = "lucihelper" ] && return 5 + write_log 14 "Invalid Proxy server Error '5' - proxy port missing" + } - __verify_host_port "$__HOST" "$__PORT" + while [ $__ERR -gt 0 ]; do + verify_host_port "$__HOST" "$__PORT" + __ERR=$? + if [ "$SECTION_ID" = "lucihelper" ]; then # no retry if called by LuCI helper script + return $__ERR + elif [ $__ERR -gt 0 -a $VERBOSE_MODE -gt 1 ]; then # VERBOSE_MODE > 1 then NO retry + write_log 7 "Verbose Mode: $VERBOSE_MODE - NO retry on error" + return $__ERR + elif [ $__ERR -gt 0 ]; then + __CNT=$(( $__CNT + 1 )) # increment error counter + # if error count > retry_count leave here + [ $__CNT -gt $retry_count ] && \ + write_log 14 "Verify Proxy server '$1' failed after $retry_count retries" + + write_log 4 "Verify Proxy server '$1' failed - retry $__CNT/$retry_count in $RETRY_SECONDS seconds" + sleep $RETRY_SECONDS & + PID_SLEEP=$! + wait $PID_SLEEP # enable trap-handler + PID_SLEEP=0 + fi + done + return 0 } -__do_transfer() { +do_transfer() { # $1 # Variable to store Answer of transfer # $2 # URL to use local __URL="$2" local __ERR=0 + local __CNT=0 # error counter local __PROG __RUNPROG __ERRPROG __DATA + [ $# -ne 2 ] && write_log 12 "Error in 'do_transfer()' - wrong number of parameters" + # lets prefer GNU Wget because it does all for us - IPv4/IPv6/HTTPS/PROXY/force IP version - if /usr/bin/wget --version 2>&1 | grep -q "\+ssl"; then + if /usr/bin/wget --version 2>&1 | grep "\+ssl" >/dev/null 2>&1 ; then __PROG="/usr/bin/wget -t 2 -O -" # standard output only 2 retrys on error # force ip version to use - if [ $force_ipversion -eq 1 ]; then + if [ $force_ipversion -eq 1 ]; then [ $use_ipv6 -eq 0 ] && __PROG="$__PROG -4" || __PROG="$__PROG -6" # force IPv4/IPv6 fi # set certificate parameters @@ -510,7 +629,7 @@ __do_transfer() { elif [ -d "$cacert" ]; then __PROG="$__PROG --ca-directory=${cacert}" else # exit here because it makes no sense to start loop - critical_error "Wget: No valid certificate(s) found for running HTTPS" + write_log 14 "No valid certificate(s) found at '$cacert' for HTTPS communication" fi fi # disable proxy if no set (there might be .wgetrc or .curlrc or wrong environment set) @@ -518,21 +637,14 @@ __do_transfer() { __RUNPROG="$__PROG -q '$__URL' 2>/dev/null" # do transfer with "-q" to suppress not needed output __ERRPROG="$__PROG -d '$__URL' 2>&1" # do transfer with "-d" for debug mode - verbose_echo " transfer prog =: $__RUNPROG" - __DATA=$(eval $__RUNPROG) - __ERR=$? - [ $__ERR -gt 0 ] && { - verbose_echo "\n!!!!!!!!! ERROR =: GNU Wget Error '$__ERR'\n$(eval $__ERRPROG)\n" - syslog_err "Communication Error - GNU Wget Error: '$__ERR'" - return 1 - } + __PROG="GNU Wget" # reuse for error logging # 2nd choice is cURL IPv4/IPv6/HTTPS # libcurl might be compiled without Proxy Support (default in trunk) elif [ -x /usr/bin/curl ]; then __PROG="/usr/bin/curl" # force ip version to use - if [ $force_ipversion -eq 1 ]; then + if [ $force_ipversion -eq 1 ]; then [ $use_ipv6 -eq 0 ] && __PROG="$__PROG -4" || __PROG="$__PROG -6" # force IPv4/IPv6 fi # set certificate parameters @@ -544,7 +656,7 @@ __do_transfer() { elif [ -d "$cacert" ]; then __PROG="$__PROG --capath $cacert" else # exit here because it makes no sense to start loop - critical_error "cURL: No valid certificate(s) found for running HTTPS" + write_log 14 "No valid certificate(s) found at '$cacert' for HTTPS communication" fi fi # disable proxy if no set (there might be .wgetrc or .curlrc or wrong environment set) @@ -554,163 +666,218 @@ __do_transfer() { else # if libcurl has no proxy support and proxy should be used then force ERROR # libcurl currently no proxy support by default - grep -iq all_proxy /usr/lib/libcurl.so* || \ - critical_error "cURL: libcurl compiled without Proxy support" + grep -i "all_proxy" /usr/lib/libcurl.so* >/dev/null 2>&1 || \ + write_log 13 "cURL: libcurl compiled without Proxy support" fi __RUNPROG="$__PROG -q '$__URL' 2>/dev/null" # do transfer with "-s" to suppress not needed output __ERRPROG="$__PROG -v '$__URL' 2>&1" # do transfer with "-v" for verbose mode - verbose_echo " transfer prog =: $__RUNPROG" - __DATA=$(eval $__RUNPROG) - __ERR=$? - [ $__ERR -gt 0 ] && { - verbose_echo "\n!!!!!!!!! ERROR =: cURL Error '$__ERR'\n$(eval $__ERRPROG)\n" - syslog_err "Communication Error - cURL Error: '$__ERR'" - return 1 - } + __PROG="cURL" # reuse for error logging # busybox Wget (did not support neither IPv6 nor HTTPS) elif [ -x /usr/bin/wget ]; then __PROG="/usr/bin/wget -O -" # force ip version not supported [ $force_ipversion -eq 1 ] && \ - critical_error "BusyBox Wget: can not force IP version to use" + write_log 14 "BusyBox Wget: can not force IP version to use" # https not supported [ $use_https -eq 1 ] && \ - critical_error "BusyBox Wget: no HTTPS support" + write_log 14 "BusyBox Wget: no HTTPS support" # disable proxy if no set (there might be .wgetrc or .curlrc or wrong environment set) [ -z "$proxy" ] && __PROG="$__PROG -Y off" - + __RUNPROG="$__PROG -q '$__URL' 2>/dev/null" # do transfer with "-q" to suppress not needed output - __ERRPROG="$__PROG '$__URL' 2>&1" - verbose_echo " transfer prog =: $__RUNPROG" + __ERRPROG="$__PROG '$__URL' 2>&1" # + __PROG="Busybox Wget" # reuse for error logging + + else + write_log 13 "Neither 'Wget' nor 'cURL' installed or executable" + fi + + while : ; do + write_log 7 "#> $__RUNPROG" __DATA=$(eval $__RUNPROG) __ERR=$? - [ $__ERR -gt 0 ] && { - verbose_echo "\n!!!!!!!!! ERROR =: BusyBox Wget Error '$__ERR'\n$(eval $__ERRPROG)\n" - syslog_err "Communication Error - BusyBox Wget Error: '$__ERR'" + [ $__ERR -eq 0 ] && { + eval "$1='$__DATA'" # everything ok + return 0 # return + } + + [ "$SECTION_ID" = "lucihelper" ] && return 1 # no retry if called by LuCI helper script + + write_log 7 "Error:\n$(eval $__ERRPROG)" # report error + write_log 3 "$__PROG error: '$__ERR'" + __DATA="" + + [ $VERBOSE_MODE -gt 1 ] && { + # VERBOSE_MODE > 1 then NO retry + write_log 7 "Verbose Mode: $VERBOSE_MODE - NO retry on error" return 1 } - else - critical_error "Program not found - Neither 'Wget' nor 'cURL' installed or executable" - fi + __CNT=$(( $__CNT + 1 )) # increment error counter + # if error count > retry_count leave here + [ $__CNT -gt $retry_count ] && \ + write_log 14 "Transfer failed after $retry_count retries" - eval "$1='$__DATA'" - return 0 + write_log 4 "Transfer failed - retry $__CNT/$retry_count in $RETRY_SECONDS seconds" + sleep $RETRY_SECONDS & + PID_SLEEP=$! + wait $PID_SLEEP # enable trap-handler + PID_SLEEP=0 + done + # we should never come here there must be a programming error + write_log 12 "Error in 'do_transfer()' - program coding error" } send_update() { # $1 # IP to set at DDNS service provider local __IP + [ $# -ne 1 ] && write_log 12 "Error calling 'send_update()' - wrong number of parameters" + # verify given IP / no private IPv4's / no IPv6 addr starting with fxxx of with ":" [ $use_ipv6 -eq 0 ] && __IP=$(echo $1 | grep -v -E "(^0|^10\.|^127|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-1]\.|^192\.168)") [ $use_ipv6 -eq 1 ] && __IP=$(echo $1 | grep "^[0-9a-eA-E]") - [ -z "$__IP" ] && critical_error "Private or invalid or no IP '$1' given" + [ -z "$__IP" ] && write_log 14 "Private or invalid or no IP '$1' given" if [ -n "$update_script" ]; then - verbose_echo " update =: parsing script '$update_script'" + write_log 7 "parsing script '$update_script'" . $update_script else - local __URL __ANSWER __ERR __USER __PASS + local __URL __ANSWER __ERR # do replaces in URL - __urlencode __USER "$username" # encode username, might be email or something like this - __urlencode __PASS "$password" # encode password, might have special chars for security reason - __URL=$(echo $update_url | sed -e "s#\[USERNAME\]#$__USER#g" -e "s#\[PASSWORD\]#$__PASS#g" \ + __URL=$(echo $update_url | sed -e "s#\[USERNAME\]#$URL_USER#g" -e "s#\[PASSWORD\]#$URL_PASS#g" \ -e "s#\[DOMAIN\]#$domain#g" -e "s#\[IP\]#$__IP#g") [ $use_https -ne 0 ] && __URL=$(echo $__URL | sed -e 's#^http:#https:#') - __do_transfer __ANSWER "$__URL" - __ERR=$? - [ $__ERR -gt 0 ] && { - verbose_echo "\n!!!!!!!!! ERROR =: Error sending update to DDNS Provider\n" - return 1 - } - verbose_echo " update send =: DDNS Provider answered\n$__ANSWER" - return 0 + do_transfer __ANSWER "$__URL" || return 1 # if VERBOSE_MODE > 1 + + write_log 7 "DDNS Provider answered:\n$__ANSWER" + + # analyse provider answers + # "good [IP_ADR]" = successful + # "nochg [IP_ADR]" = no change but OK + echo "$__ANSWER" | grep -E "good|nochg" >/dev/null 2>&1 + return $? # "0" if "good" or "nochg" found fi } get_local_ip () { # $1 Name of Variable to store local IP (LOCAL_IP) - local __RUNPROG __IP __URL __ANSWER - - case $ip_source in - network ) - # set correct program - [ $use_ipv6 -eq 0 ] && __RUNPROG="network_get_ipaddr" \ - || __RUNPROG="network_get_ipaddr6" - $__RUNPROG __IP "$ip_network" - verbose_echo " local ip =: '$__IP' detected on network '$ip_network'" - ;; - interface ) - if [ $use_ipv6 -eq 0 ]; then - __IP=$(ifconfig $ip_interface | awk ' - /inet addr:/ { # Filter IPv4 - # inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255.0 - $1=""; # remove inet - $3=""; # remove Bcast: ... - $4=""; # remove Mask: ... - FS=":"; # separator ":" - $0=$0; # reread to activate separator - $1=""; # remove addr - FS=" "; # set back separator to default " " - $0=$0; # reread to activate separator (remove whitespaces) - print $1; # print IPv4 addr - }' - ) - else - __IP=$(ifconfig $ip_interface | awk ' - /inet6/ && /: [0-9a-eA-E]/ && !/\/128/ { # Filter IPv6 exclude fxxx and /128 prefix - # inet6 addr: 2001:db8::xxxx:xxxx/32 Scope:Global - FS="/"; # separator "/" - $0=$0; # reread to activate separator - $2=""; # remove everything behind "/" - FS=" "; # set back separator to default " " - $0=$0; # reread to activate separator - print $3; # print IPv6 addr - }' - ) - fi - verbose_echo " local ip =: '$__IP' detected on interface '$ip_interface'" - ;; - script ) - # get ip from script - __IP=$($ip_script) - verbose_echo " local ip =: '$__IP' detected via script '$ip_script'" - ;; - * ) - for __URL in $ip_url; do - __do_transfer __ANSWER "$__URL" - [ -n "$__IP" ] && break # Answer detected, leave for loop - done - # use correct regular expression - [ $use_ipv6 -eq 0 ] \ - && __IP=$(echo "$__ANSWER" | grep -m 1 -o "$IPV4_REGEX") \ - || __IP=$(echo "$__ANSWER" | grep -m 1 -o "$IPV6_REGEX") - verbose_echo " local ip =: '$__IP' detected via web at '$__URL'" - ;; - esac + local __CNT=0 # error counter + local __RUNPROG __DATA __URL __ANSWER + + [ $# -ne 1 ] && write_log 12 "Error calling 'get_local_ip()' - wrong number of parameters" + write_log 7 "Detect local IP" + + while : ; do + case $ip_source in + network) + # set correct program + [ $use_ipv6 -eq 0 ] && __RUNPROG="network_get_ipaddr" \ + || __RUNPROG="network_get_ipaddr6" + write_log 7 "#> $__RUNPROG __DATA '$ip_network'" + $__RUNPROG __DATA "$ip_network" + [ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected on network '$ip_network'" + ;; + interface) + write_log 7 "#> ifconfig '$ip_interface'" + if [ $use_ipv6 -eq 0 ]; then + __DATA=$(ifconfig $ip_interface | awk ' + /inet addr:/ { # Filter IPv4 + # inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255.0 + $1=""; # remove inet + $3=""; # remove Bcast: ... + $4=""; # remove Mask: ... + FS=":"; # separator ":" + $0=$0; # reread to activate separator + $1=""; # remove addr + FS=" "; # set back separator to default " " + $0=$0; # reread to activate separator (remove whitespaces) + print $1; # print IPv4 addr + }' + ) + else + __DATA=$(ifconfig $ip_interface | awk ' + /inet6/ && /: [0-9a-eA-E]/ && !/\/128/ { # Filter IPv6 exclude fxxx and /128 prefix + # inet6 addr: 2001:db8::xxxx:xxxx/32 Scope:Global + FS="/"; # separator "/" + $0=$0; # reread to activate separator + $2=""; # remove everything behind "/" + FS=" "; # set back separator to default " " + $0=$0; # reread to activate separator + print $3; # print IPv6 addr + }' + ) + fi + [ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected on interface '$ip_interface'" + ;; + script) + write_log 7 "#> $ip_script" + __DATA=$($ip_script) # get ip from script + [ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected via script '$ip_script'" + ;; + web) + for __URL in $ip_url; do + do_transfer __ANSWER "$__URL" + [ -n "$__ANSWER" ] && break # Answer detected, leave "for do done" + done + # use correct regular expression + [ $use_ipv6 -eq 0 ] \ + && __DATA=$(echo "$__ANSWER" | grep -m 1 -o "$IPV4_REGEX") \ + || __DATA=$(echo "$__ANSWER" | grep -m 1 -o "$IPV6_REGEX") + [ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected on web at '$__URL'" + ;; + *) + write_log 12 "Error in 'get_local_ip()' - unhandled ip_source '$ip_source'" + ;; + esac + # valid data found return here + [ -n "$__DATA" ] && { + eval "$1='$__DATA'" + return 0 + } - # if NO IP was found - [ -z "$__IP" ] && return 1 + [ "$SECTION_ID" = "lucihelper" ] && return 1 # no retry if called by LuCI helper script + [ $VERBOSE_MODE -gt 1 ] && { + # VERBOSE_MODE > 1 then NO retry + write_log 7 "Verbose Mode: $VERBOSE_MODE - NO retry on error" + return 1 + } - eval "$1='$__IP'" - return 0 + __CNT=$(( $__CNT + 1 )) # increment error counter + # if error count > retry_count leave here + [ $__CNT -gt $retry_count ] && \ + write_log 14 "Get local IP via '$ip_source' failed after $retry_count retries" + + write_log 4 "Get local IP via '$ip_source' failed - retry $__CNT/$retry_count in $RETRY_SECONDS seconds" + sleep $RETRY_SECONDS & + PID_SLEEP=$! + wait $PID_SLEEP # enable trap-handler + PID_SLEEP=0 + done + # we should never come here there must be a programming error + write_log 12 "Error in 'get_local_ip()' - program coding error" } get_registered_ip() { # $1 Name of Variable to store public IP (REGISTERED_IP) - local __IP __REGEX __PROG __RUNPROG __ERRPROG __ERR + # $2 (optional) if set, do not retry on error + local __CNT=0 # error counter + local __ERR=255 + local __REGEX __PROG __RUNPROG __ERRPROG __DATA # return codes # 1 no IP detected + [ $# -lt 1 -o $# -gt 2 ] && write_log 12 "Error calling 'get_registered_ip()' - wrong number of parameters" + write_log 7 "Detect registered/public IP" + # set correct regular expression [ $use_ipv6 -eq 0 ] && __REGEX="$IPV4_REGEX" || __REGEX="$IPV6_REGEX" - if [ -x /usr/bin/host ]; then # otherwise try to use BIND host + if [ -x /usr/bin/host ]; then __PROG="/usr/bin/host" [ $use_ipv6 -eq 0 ] && __PROG="$__PROG -t A" || __PROG="$__PROG -t AAAA" if [ $force_ipversion -eq 1 ]; then # force IP version @@ -720,55 +887,106 @@ get_registered_ip() { __RUNPROG="$__PROG $domain $dns_server 2>/dev/null" __ERRPROG="$__PROG -v $domain $dns_server 2>&1" - verbose_echo " resolver prog =: $__RUNPROG" - __IP=$(eval $__RUNPROG) - __ERR=$? - # command error - [ $__ERR -gt 0 ] && { - verbose_echo "\n!!!!!!!!! ERROR =: BIND host Error '$__ERR'\n$(eval $__ERRPROG)\n" - syslog_err "DNS Resolver Error - BIND host Error: '$__ERR'" - return 1 - } || { - # we need to run twice because multi-line output needs to be directly piped to grep because - # pipe returns return code of last prog in pipe but we need errors from host command - __IP=$(eval $__RUNPROG | awk -F "address " '/has/ {print $2; exit}' ) - } - + __PROG="BIND host" elif [ -x /usr/bin/nslookup ]; then # last use BusyBox nslookup [ $force_ipversion -ne 0 -o $force_dnstcp -ne 0 ] && \ - critical_error "nslookup - no support to 'force IP Version' or 'DNS over TCP'" + write_log 14 "Busybox nslookup - no support to 'force IP Version' or 'DNS over TCP'" __RUNPROG="nslookup $domain $dns_server 2>/dev/null" __ERRPROG="nslookup $domain $dns_server 2>&1" - verbose_echo " resolver prog =: $__RUNPROG" - __IP=$(eval $__RUNPROG) - __ERR=$? - # command error - [ $__ERR -gt 0 ] && { - verbose_echo "\n!!!!!!!!! ERROR =: BusyBox nslookup Error '$__ERR'\n$(eval $__ERRPROG)\n" - syslog_err "DNS Resolver Error - BusyBox nslookup Error: '$__ERR'" - return 1 - } || { - # we need to run twice because multi-line output needs to be directly piped to grep because - # pipe returns return code of last prog in pipe but we need errors from nslookup command - __IP=$(eval $__RUNPROG | sed -ne "3,\$ { s/^Address [0-9]*: \($__REGEX\).*$/\\1/p }" ) - } - - else # there must be an error - critical_error "No program found to request public registered IP" + __PROG="BusyBox nslookup" + else # there must be an error + write_log 12 "Error in 'get_registered_ip()' - no supported Name Server lookup software accessible" fi - verbose_echo " resolved ip =: '$__IP'" + while : ; do + write_log 7 "#> $__RUNPROG" + __DATA=$(eval $__RUNPROG) + __ERR=$? + if [ $__ERR -ne 0 ]; then + write_log 7 "Error:\n$(eval $__ERRPROG)" + write_log 3 "$__PROG error: '$__ERR'" + __DATA="" + else + if [ "$__PROG" = "BIND host" ]; then + __DATA=$(echo "$__DATA" | awk -F "address " '/has/ {print $2; exit}' ) + else + __DATA=$(echo "$__DATA" | sed -ne "3,\$ { s/^Address [0-9]*: \($__REGEX\).*$/\\1/p }" ) + fi + [ -n "$__DATA" ] && { + write_log 7 "Registered IP '$__DATA' detected" + eval "$1='$__DATA'" # valid data found + return 0 # leave here + } + write_log 4 "NO valid IP found" + __ERR=127 + fi + + [ "$SECTION_ID" = "lucihelper" ] && return $__ERR # no retry if called by LuCI helper script + [ -n "$2" ] && return $__ERR # $2 is given -> no retry + [ $VERBOSE_MODE -gt 1 ] && { + # VERBOSE_MODE > 1 then NO retry + write_log 7 "Verbose Mode: $VERBOSE_MODE - NO retry on error" + return $__ERR + } - # if NO IP was found - [ -z "$__IP" ] && return 1 + __CNT=$(( $__CNT + 1 )) # increment error counter + # if error count > retry_count leave here + [ $__CNT -gt $retry_count ] && \ + write_log 14 "Get registered/public IP for '$domain' failed after $retry_count retries" - eval "$1='$__IP'" - return 0 + write_log 4 "Get registered/public IP for '$domain' failed - retry $__CNT/$retry_count in $RETRY_SECONDS seconds" + sleep $RETRY_SECONDS & + PID_SLEEP=$! + wait $PID_SLEEP # enable trap-handler + PID_SLEEP=0 + done + # we should never come here there must be a programming error + write_log 12 "Error in 'get_registered_ip()' - program coding error" } get_uptime() { # $1 Variable to store result in + [ $# -ne 1 ] && write_log 12 "Error calling 'verify_host_port()' - wrong number of parameters" local __UPTIME=$(cat /proc/uptime) eval "$1='${__UPTIME%%.*}'" } + +trap_handler() { + # $1 trap signal + # $2 optional (exit status) + local __PIDS __PID + local __ERR=${2:-0} + local __OLD_IFS=$IFS + local __NEWLINE_IFS=' +' #__NEWLINE_IFS + + [ $PID_SLEEP -ne 0 ] && kill -$1 $PID_SLEEP 2>/dev/null # kill pending sleep if exist + + case $1 in + 0) if [ $__ERR -eq 0 ]; then + write_log 5 "PID '$$' exit normal at $(eval $DATE_PROG)\n" + else + write_log 4 "PID '$$' exit WITH ERROR '$__ERR' at $(eval $DATE_PROG)\n" + fi ;; + 1) write_log 6 "PID '$$' received 'SIGHUP' at $(eval $DATE_PROG)" + eval "$0 $SECTION_ID $VERBOSE_MODE &" # reload config via restarting script + exit 0 ;; + 2) write_log 5 "PID '$$' terminated by 'SIGINT' at $(eval $DATE_PROG)\n";; + 3) write_log 5 "PID '$$' terminated by 'SIGQUIT' at $(eval $DATE_PROG)\n";; + 15) write_log 5 "PID '$$' terminated by 'SIGTERM' at $(eval $DATE_PROG)\n";; + *) write_log 13 "Unhandled signal '$1' in 'trap_handler()'";; + esac + + __PIDS=$(pgrep -P $$) # get my childs (pgrep prints with "newline") + IFS=$__NEWLINE_IFS + for __PID in $__PIDS; do + kill -$1 $__PID # terminate it + done + IFS=$__OLD_IFS + + # exit with correct handling: + # remove trap handling settings and send kill to myself + trap - 0 1 2 3 15 + [ $1 -gt 0 ] && kill -$1 $$ +} diff --git a/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_updater.sh b/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_updater.sh index 6c715cb49..107d0ebd5 100755 --- a/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_updater.sh +++ b/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_updater.sh @@ -10,11 +10,12 @@ # by Christian Schoenebeck <christian dot schoenebeck at gmail dot com> # to support: # - IPv6 DDNS services -# - DNS Server to retrieve registered IP including TCP transport +# - DNS Server to retrieve registered IP including TCP transport (Ticket 7820) # - Proxy Server to send out updates -# - force_interval=0 to run once +# - 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 # # variables in small chars are read from /etc/config/ddns # variables in big chars are defined inside these scripts as global vars @@ -38,7 +39,7 @@ . /usr/lib/ddns/dynamic_dns_functions.sh # global vars are also defined here SECTION_ID="$1" -VERBOSE_MODE=${2:-1} #default mode is log to console +VERBOSE_MODE=${2:-1} # default mode is log to console # set file names PIDFILE="$RUNDIR/$SECTION_ID.pid" # Process ID file @@ -47,15 +48,23 @@ LOGFILE="$LOGDIR/$SECTION_ID.log" # log file # VERBOSE_MODE > 1 delete logfile if exist to create an empty one # only with this data of this run for easier diagnostic -# new one created by verbose_echo function +# new one created by write_log function [ $VERBOSE_MODE -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 15" 15 # SIGTERM Termination + ################################################################################ # Leave this comment here, to clearly document variable names that are expected/possible # Use load_all_config_options to load config options, which is a much more flexible solution. # # config_load "ddns" -# config_get <variable> $SECTION_ID <option]> +# config_get <variable> $SECTION_ID <option> # # defined options (also used as variable): # @@ -108,23 +117,23 @@ LOGFILE="$LOGDIR/$SECTION_ID.log" # log file [ "$(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 - verbose_echo "\n ************** =: ************** ************** **************" - verbose_echo " STARTED =: PID '$$' at $(eval $DATE_PROG)" - verbose_echo " UCI CONFIG =:\n$(uci -q show ddns | grep '=service' | sort)" - critical_error "Service '$SECTION_ID' not defined" + 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" -verbose_echo "\n ************** =: ************** ************** **************" -verbose_echo " STARTED =: PID '$$' at $(eval $DATE_PROG)" +write_log 7 "************ ************** ************** **************" +write_log 5 "PID '$$' started at $(eval $DATE_PROG)" case $VERBOSE_MODE in - 0) verbose_echo " verbose mode =: '0' - run normal, NO console output";; - 1) verbose_echo " verbose mode =: '1' - run normal, console mode";; - 2) verbose_echo " verbose mode =: '2' - run once, NO retry on error";; - 3) verbose_echo " verbose mode =: '3' - run once, NO retry on error, NOT sending update";; - *) critical_error "ERROR detecting VERBOSE_MODE '$VERBOSE_MODE'" + 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 -verbose_echo " UCI CONFIG =:\n$(uci -q show ddns.$SECTION_ID | sort)" +write_log 7 "uci configuraion:\n$(uci -q show ddns.$SECTION_ID | sort)" # set defaults if not defined [ -z "$enabled" ] && enabled=0 @@ -142,48 +151,47 @@ verbose_echo " UCI CONFIG =:\n$(uci -q show ddns.$SECTION_ID | sort)" [ "$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" -# check configuration and enabled state -[ -z "$domain" -o -z "$username" -o -z "$password" ] && critical_error "Service Configuration not correctly configured" -[ $enabled -eq 0 ] && critical_error "Service Configuration is disabled" +# 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 -# verify script if configured and executable +# verify ip_source script if configured and executable if [ "$ip_source" = "script" ]; then - [ -z "$ip_script" ] && critical_error "No script defined to detect local IP" - [ -x "$ip_script" ] || critical_error "Script to detect local IP not found or not executable" + [ -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!" fi # compute update interval in seconds get_seconds CHECK_SECONDS ${check_interval:-10} ${check_unit:-"minutes"} # default 10 min get_seconds FORCE_SECONDS ${force_interval:-72} ${force_unit:-"hours"} # default 3 days get_seconds RETRY_SECONDS ${retry_interval:-60} ${retry_unit:-"seconds"} # default 60 sec -verbose_echo "check interval =: $CHECK_SECONDS seconds" -verbose_echo "force interval =: $FORCE_SECONDS seconds" -verbose_echo "retry interval =: $RETRY_SECONDS seconds" -verbose_echo " retry counter =: $retry_count times" +[ $CHECK_SECONDS -lt 300 ] && CHECK_SECONDS=300 # minimum 5 minutes +[ $FORCE_SECONDS -gt 0 -a $FORCE_SECONDS -lt $CHECK_SECONDS ] && FORCE_SECONDS=$CHECK_SECONDS # FORCE_SECONDS >= CHECK_SECONDS or 0 +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 service) +# 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" ] && critical_error "no update_url found/defined or no update_script found/defined" -[ -n "$update_script" -a ! -f "$update_script" ] && critical_error "custom update_script not found" +[ -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!" #kill old process if it exists & set new pid file if [ -d $RUNDIR ]; then - #if process is already running, stop it - if [ -e "$PIDFILE" ]; then - OLD_PID=$(cat $PIDFILE) - ps | grep -q "^[\t ]*$OLD_PID" && { - verbose_echo " old process =: PID '$OLD_PID'" - kill $OLD_PID - } || verbose_echo "old process id =: PID 'none'" - else - verbose_echo "old process id =: PID 'none'" - fi + #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 - verbose_echo "old process id =: PID 'none'" + write_log 7 "No old process" fi echo $$ > $PIDFILE @@ -201,242 +209,118 @@ get_uptime CURR_TIME [ $LAST_TIME -gt $CURR_TIME ] && LAST_TIME=0 } if [ $LAST_TIME -eq 0 ]; then - verbose_echo " last update =: never" + write_log 7 "last update: never" else EPOCH_TIME=$(( $(date +%s) - CURR_TIME + LAST_TIME )) EPOCH_TIME="date -d @$EPOCH_TIME +'$DATE_FORMAT'" - verbose_echo " last update =: $(eval $EPOCH_TIME)" + 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. -verbose_echo " waiting =: 10 seconds for interfaces to fully come up" -sleep 10 - -# verify DNS server: -# do with retry's because there might be configurations -# not directly could connect to outside dns when interface is already up -ERR_VERIFY=0 # reset err counter -while [ -n "$dns_server" ]; do - [ $ERR_VERIFY -eq 0 ] && verbose_echo "******* VERIFY =: DNS server '$dns_server'" - verify_dns "$dns_server" - ERR_LAST=$? # save return value - [ $ERR_LAST -eq 0 ] && break # everything ok leave while loop - ERR_VERIFY=$(( $ERR_VERIFY + 1 )) - # if error count > retry_count leave here with critical error - [ $ERR_VERIFY -gt $retry_count ] && { - case $ERR_LAST in - 2) critical_error "Invalid DNS server Error: '2' - nslookup can not resolve host";; - 3) critical_error "Invalid DNS server Error: '3' - nc (netcat) can not connect";; - *) critical_error "Invalid DNS server Error: '$ERR_LAST' - unspecific error";; - esac - } - case $ERR_LAST in - 2) syslog_err "Invalid DNS server Error: '2' - nslookup can not resolve host - retry $ERR_VERIFY/$retry_count in $RETRY_SECONDS seconds\n";; - 3) syslog_err "Invalid DNS server Error: '3' - nc (netcat) can not connect - retry $ERR_VERIFY/$retry_count in $RETRY_SECONDS seconds\n";; - *) syslog_err "Invalid DNS server Error: '$ERR_LAST' - unspecific error - retry $ERR_VERIFY/$retry_count in $RETRY_SECONDS seconds\n";; - esac - [ $VERBOSE_MODE -gt 1 ] && { - # VERBOSE_MODE > 1 then NO retry - verbose_echo "\n!!!!!!!!! ERROR =: Verbose Mode - NO retry\n" - break - } - verbose_echo "******** RETRY =: DNS server '$dns_server' - retry $ERR_VERIFY/$retry_count in $RETRY_SECONDS seconds" - sleep $RETRY_SECONDS -done +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 +[ -n "$dns_server" ] && verify_dns "$dns_server" # verify Proxy server and set environment -# do with retry's because there might be configurations -# not directly could connect to outside dns when interface is already up -ERR_VERIFY=0 # reset err counter [ -n "$proxy" ] && { - [ $ERR_VERIFY -eq 0 ] && verbose_echo "******* VERIFY =: Proxy server 'http://$proxy'" - verify_proxy "$proxy" - ERR_LAST=$? # save return value - [ $ERR_LAST -eq 0 ] && { - # everything ok set proxy and leave while loop + verify_proxy "$proxy" && { + # everything ok set proxy export HTTP_PROXY="http://$proxy" export HTTPS_PROXY="http://$proxy" export http_proxy="http://$proxy" export https_proxy="http://$proxy" - break } - ERR_VERIFY=$(( $ERR_VERIFY + 1 )) - # if error count > retry_count leave here with critical error - [ $ERR_VERIFY -gt $retry_count ] && { - case $ERR_LAST in - 2) critical_error "Invalid Proxy server Error '2' - nslookup can not resolve host";; - 3) critical_error "Invalid Proxy server Error '3' - nc (netcat) can not connect";; - *) critical_error "Invalid Proxy server Error '$ERR_LAST' - unspecific error";; - esac - } - case $ERR_LAST in - 2) syslog_err "Invalid Proxy server Error '2' - nslookup can not resolve host - retry $ERR_VERIFY/$retry_count in $RETRY_SECONDS seconds\n";; - 3) syslog_err "Invalid Proxy server Error '3' - nc (netcat) can not connect - retry $ERR_VERIFY/$retry_count in $RETRY_SECONDS seconds\n";; - *) syslog_err "Invalid Proxy server Error '$ERR_LAST' - unspecific error - retry $ERR_VERIFY/$retry_count in $RETRY_SECONDS seconds\n";; - esac - [ $VERBOSE_MODE -gt 1 ] && { - # VERBOSE_MODE > 1 then NO retry - verbose_echo "\n!!!!!!!!! ERROR =: Verbose Mode - NO retry\n" - break - } - verbose_echo "******** RETRY =: Proxy server 'http://$proxy' - retry $ERR_VERIFY/$retry_count in $RETRY_SECONDS seconds" - sleep $RETRY_SECONDS } # let's check if there is already an IP registered at the web # but ignore errors if not -verbose_echo "******* DETECT =: Registered IP" -get_registered_ip REGISTERED_IP +get_registered_ip REGISTERED_IP "NO_RETRY" # loop endlessly, checking ip every check_interval and forcing an updating once every force_interval -# NEW: ### Luci Ticket 538 -# a "force_interval" of "0" will run this script only once -# the update is only done once when an interface goes up -# or you run /etc/init.d/ddns start or you can use a cron job -# it will force an update without check when lastupdate happen -# but it will verify after "check_interval" if update is seen in the web -# and retries on error retry_count times -# CHANGES: ### Ticket 16363 -# modified nslookup / sed / grep to detect registered ip -# NEW: ### Ticket 7820 -# modified nslookup to support non standard dns_server (needs to be defined in /etc/config/ddns) -# support for BIND host command. -# Wait for interface to fully come up, before the first update is done -verbose_echo "*** START LOOP =: $(eval $DATE_PROG)" -# we run NOT once -[ $FORCE_SECONDS -gt 0 -o $VERBOSE_MODE -le 1 ] && syslog_info "Starting main loop" - +write_log 6 "Starting main loop at $(eval $DATE_PROG)" while : ; do - # read local IP - verbose_echo "******* DETECT =: Local IP" - get_local_ip LOCAL_IP - ERR_LAST=$? # save return value - # Error in function - [ $ERR_LAST -gt 0 ] && { - if [ $VERBOSE_MODE -le 1 ]; then # VERBOSE_MODE <= 1 then retry - # we can't read local IP - ERR_LOCAL_IP=$(( $ERR_LOCAL_IP + 1 )) - [ $ERR_LOCAL_IP -gt $retry_count ] && critical_error "Can not detect local IP" - verbose_echo "\n!!!!!!!!! ERROR =: detecting local IP - retry $ERR_LOCAL_IP/$retry_count in $RETRY_SECONDS seconds\n" - syslog_err "Error detecting local IP - retry $ERR_LOCAL_IP/$retry_count in $RETRY_SECONDS seconds" - sleep $RETRY_SECONDS - continue # jump back to the beginning of while loop - else - verbose_echo "\n!!!!!!!!! ERROR =: detecting local IP - NO retry\n" - fi - } - ERR_LOCAL_IP=0 # reset err counter + get_local_ip LOCAL_IP # read local IP # prepare update - # never updated or forced immediate then NEXT_TIME = 0 + # never updated or forced immediate then NEXT_TIME = 0 [ $FORCE_SECONDS -eq 0 -o $LAST_TIME -eq 0 ] \ && NEXT_TIME=0 \ || NEXT_TIME=$(( $LAST_TIME + $FORCE_SECONDS )) - # get current uptime - get_uptime CURR_TIME - - # send update when current time > next time or local ip different from registered ip (as loop on error) - ERR_SEND=0 - while [ $CURR_TIME -ge $NEXT_TIME -o "$LOCAL_IP" != "$REGISTERED_IP" ]; do + + get_uptime CURR_TIME # get current uptime + + # 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 - verbose_echo " VERBOSE MODE =: NO UPDATE send to DDNS provider" + write_log 7 "Verbose Mode: $VERBOSE_MODE - NO UPDATE send" elif [ "$LOCAL_IP" != "$REGISTERED_IP" ]; then - verbose_echo "******* UPDATE =: LOCAL: '$LOCAL_IP' <> REGISTERED: '$REGISTERED_IP'" + write_log 7 "Update needed - L: '$LOCAL_IP' <> R: '$REGISTERED_IP'" else - verbose_echo "******* FORCED =: LOCAL: '$LOCAL_IP' == REGISTERED: '$REGISTERED_IP'" + write_log 7 "Forced Update - L: '$LOCAL_IP' == R: '$REGISTERED_IP'" fi - # only send if VERBOSE_MODE < 3 + ERR_LAST=0 [ $VERBOSE_MODE -lt 3 ] && { - send_update "$LOCAL_IP" + # only send if VERBOSE_MODE < 3 + send_update "$LOCAL_IP" ERR_LAST=$? # save return value } - # Error in function - if [ $ERR_LAST -gt 0 ]; then - if [ $VERBOSE_MODE -le 1 ]; then # VERBOSE_MODE <=1 then retry - # error sending local IP - ERR_SEND=$(( $ERR_SEND + 1 )) - [ $ERR_SEND -gt $retry_count ] && critical_error "can not send update to DDNS Provider" - verbose_echo "\n!!!!!!!!! ERROR =: sending update - retry $ERR_SEND/$retry_count in $RETRY_SECONDS seconds\n" - syslog_err "Error sending update - retry $ERR_SEND/$retry_count in $RETRY_SECONDS seconds" - sleep $RETRY_SECONDS - continue # re-loop - else - verbose_echo "\n!!!!!!!!! ERROR =: sending update to DDNS service - NO retry\n" - break - fi - else - # we send data so save "last time" - get_uptime LAST_TIME + # 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 ] && { + get_uptime LAST_TIME # we send update, so echo $LAST_TIME > $UPDFILE # save LASTTIME to file [ "$LOCAL_IP" != "$REGISTERED_IP" ] \ - && syslog_notice "Changed IP: '$LOCAL_IP' successfully send" \ - || syslog_notice "Forced Update: IP: '$LOCAL_IP' successfully send" - break # leave while - fi - done + && 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" + fi # now we wait for check interval before testing if update was recognized - # only sleep if VERBOSE_MODE <= 2 because nothing send so do not wait + # only sleep if VERBOSE_MODE <= 2 because otherwise nothing was send [ $VERBOSE_MODE -le 2 ] && { - verbose_echo "****** WAITING =: $CHECK_SECONDS seconds (Check Interval) before continue" - sleep $CHECK_SECONDS - } || verbose_echo " VERBOSE MODE =: NO WAITING for Check Interval\n" - - # read at DDNS service registered IP (in loop on error) - REGISTERED_IP="" - ERR_REG_IP=0 - while : ; do - verbose_echo "******* DETECT =: Registered IP" - get_registered_ip REGISTERED_IP - ERR_LAST=$? # save return value - - # No Error in function we leave while loop - [ $ERR_LAST -eq 0 ] && break - - # we can't read Registered IP - if [ $VERBOSE_MODE -le 1 ]; then # VERBOSE_MODE <=1 then retry - ERR_REG_IP=$(( $ERR_REG_IP + 1 )) - [ $ERR_REG_IP -gt $retry_count ] && critical_error "can not detect registered local IP" - verbose_echo "\n!!!!!!!!! ERROR =: detecting Registered IP - retry $ERR_REG_IP/$retry_count in $RETRY_SECONDS seconds\n" - syslog_err "Error detecting Registered IP - retry $ERR_REG_IP/$retry_count in $RETRY_SECONDS seconds" - sleep $RETRY_SECONDS - else - verbose_echo "\n!!!!!!!!! ERROR =: detecting Registered IP - NO retry\n" - break # leave while loop - fi - done + 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" + + REGISTERED_IP="" # clear variable + get_registered_ip REGISTERED_IP # get registered/public IP # IP's are still different if [ "$LOCAL_IP" != "$REGISTERED_IP" ]; then if [ $VERBOSE_MODE -le 1 ]; then # VERBOSE_MODE <=1 then retry ERR_UPDATE=$(( $ERR_UPDATE + 1 )) - [ $ERR_UPDATE -gt $retry_count ] && critical_error "Registered IP <> Local IP - LocalIP: '$LOCAL_IP' - RegisteredIP: '$REGISTERED_IP'" - verbose_echo "\n!!!!!!!!! ERROR =: Registered IP <> Local IP - starting retry $ERR_UPDATE/$retry_count\n" - syslog_warn "Warning: Registered IP <> Local IP - starting retry $ERR_UPDATE/$retry_count" + [ $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" continue # loop to beginning else - verbose_echo "\n!!!!!!!!! ERROR =: Registered IP <> Local IP - LocalIP: '$LOCAL_IP' - RegisteredIP: '$REGISTERED_IP' - NO retry\n" + write_log 4 "Updating IP at DDNS provider failed" + write_log 7 "Verbose Mode: $VERBOSE_MODE - NO retry"; exit 1 fi - fi - - # we checked successful the last update - ERR_UPDATE=0 # reset error counter + else + # we checked successful the last update + ERR_UPDATE=0 # reset error counter + fi - # force_update=0 or VERBOSE_MODE > 1 - leave the main loop - [ $FORCE_SECONDS -eq 0 -o $VERBOSE_MODE -gt 1 ] && { - verbose_echo "****** LEAVING =: $(eval $DATE_PROG)" - syslog_info "Leaving" - break - } - verbose_echo "********* LOOP =: $(eval $DATE_PROG)" - syslog_info "Rerun IP check" + # 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 + write_log 6 "Rerun IP check at $(eval $DATE_PROG)" done - -verbose_echo "****** STOPPED =: PID '$$' at $(eval $DATE_PROG)\n" -syslog_info "Done" - -exit 0 +# we should never come here there must be a programming error +write_log 12 "Error in 'dynamic_dns_updater.sh - program coding error" diff --git a/net/ddns-scripts/files/usr/lib/ddns/services b/net/ddns-scripts/files/usr/lib/ddns/services index bb447fb41..0bb596817 100644 --- a/net/ddns-scripts/files/usr/lib/ddns/services +++ b/net/ddns-scripts/files/usr/lib/ddns/services @@ -1,45 +1,54 @@ -# This file contains the update urls for various dynamic dns services. -# Column one contains the service name, column two contains the update url. -# within the update url there are 4 variables you can use: [USERNAME], -# [PASSWORD], [DOMAIN] and [IP]. These are substituted for the username, -# password, and domain name specified in the /etc/config/ddns file when an -# update is performed. The IP is substituted for the current ip address of the -# router. These variables are case sensitive, while urls generally are not, so -# if you need to enter the same text in the url (which seems very unlikely) put -# that text in lowercase, while the variables should remain in uppercase +#444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444 +#4 +#4 This file contains the update urls for various dynamic dns services. +#4 Column one contains the service name, column two contains the update url. +#4 within the update url there are 4 variables you can use: [USERNAME], +#4 [PASSWORD], [DOMAIN] and [IP]. These are substituted for the username, +#4 password, and domain name specified in the /etc/config/ddns file when an +#4 update is performed. The IP is substituted for the current ip address of the +#4 router. These variables are case sensitive, while urls generally are not, so +#4 if you need to enter the same text in the url (which seems very unlikely) put +#4 that text in lowercase, while the variables should remain in uppercase +#4 +#4 There are TONS of dynamic dns services out there. There's a huge list of them at: +#4 http://www.dmoz.org/Computers/Software/Internet/Servers/Address_Management/Dynamic_DNS_Services/ +#4 If anyone has time they could update this file to be compatible with a bunch of them +#4 +#4 !!! Since ddns-scripts Version 2.x the update of IPv6 addresses is also supported +#4 !!! This file is used for update of IPv4 adresses only. For IPv6 use services_ipv6 +#4 +#4 !!! Since ddns-scripts Version 2.x the update via provider specific update scripts is supported. +#4 !!! This scripts must be located at /usr/lib/ddns directory if defined inside this file. +#4 !!! Use only the script name (without path). Sample: +#4 !!! "example.com" "update_sample.sh" +#4 +#444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444 "dyndns.org" "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]" "changeip.com" "http://[USERNAME]:[PASSWORD]@nic.changeip.com/nic/update?u=[USERNAME]&p=[PASSWORD]&cmd=update&hostname=[DOMAIN]&ip=[IP]" "zoneedit.com" "http://[USERNAME]:[PASSWORD]@dynamic.zoneedit.com/auth/dynamic.html?host=[DOMAIN]&dnsto=[IP]" "free.editdns.net" "http://dyndns-free.editdns.net/api/dynLinux.php?p=[PASSWORD]&r=[DOMAIN]" -#noip is an alias of no-ip, so allow both names for the same service -"no-ip.com" "http://[USERNAME]:[PASSWORD]@dynupdate.no-ip.com/nic/update?hostname=[DOMAIN]&myip=[IP]" -"noip.com" "http://[USERNAME]:[PASSWORD]@dynupdate.no-ip.com/nic/update?hostname=[DOMAIN]&myip=[IP]" +# noip is an alias of no-ip, so allow both names for the same service +# use provider specific update script +"no-ip.com" "update_no-ip.sh" +"noip.com" "update_no-ip.sh" #freedns.afraid.org is weird, you just need an update code, for which we use the password variable "freedns.afraid.org" "http://freedns.afraid.org/dynamic/update.php?[PASSWORD]&address=[IP]" -#### ADD YOURS HERE! ###################################################################################### -# # -# There are TONS of dynamic dns services out there. There's a huge list of them at: # -# http://www.dmoz.org/Computers/Software/Internet/Servers/Address_Management/Dynamic_DNS_Services/ # -# If anyone has time they could update this file to be compatible with a bunch of them # -# # -########################################################################################################### - # DNS Max and resellers' update urls "dnsmax.com" "http://update.dnsmax.com/update/?username=[USERNAME]&password=[PASSWORD]&resellerid=1&clientname=openwrt&clientversion=8.09&protocolversion=2.0&updatehostname=[DOMAIN]&ip=[IP]" "thatip.com" "http://update.dnsmax.com/update/?username=[USERNAME]&password=[PASSWORD]&resellerid=2&clientname=openwrt&clientversion=8.09&protocolversion=2.0&updatehostname=[DOMAIN]&ip=[IP]" # Hurricane Electric Dynamic DNS -"he.net" "http://[DOMAIN]:[PASSWORD]@dyn.dns.he.net/nic/update?hostname=[DOMAIN]&myip=[IP]" +"he.net" "http://[DOMAIN]:[PASSWORD]@dyn.dns.he.net/nic/update?hostname=[DOMAIN]&myip=[IP]" # DNSdynamic.org "dnsdynamic.org" "http://[USERNAME]:[PASSWORD]@www.dnsdynamic.org/api/?hostname=[DOMAIN]&myip=[IP]" # dnsExit.com free dynamic DNS update url -"dnsexit.com" "http://www.dnsexit.com/RemoteUpdate.sv?login=[USERNAME]&password=[PASSWORD]&host=[DOMAIN]&myip=[IP]" +"dnsexit.com" "http://www.dnsexit.com/RemoteUpdate.sv?login=[USERNAME]&password=[PASSWORD]&host=[DOMAIN]&myip=[IP]" # OVH "ovh.com" "http://[USERNAME]:[PASSWORD]@www.ovh.com/nic/update?system=dyndns&hostname=[DOMAIN]&myip=[IP]" @@ -56,7 +65,7 @@ "namecheap.com" "http://dynamicdns.park-your-domain.com/update?host=[USERNAME]&domain=[DOMAIN]&password=[PASSWORD]&ip=[IP]" # easydns.com dynamic DNS -"easydns.com" "http://[USERNAME]:[PASSWORD]@api.cp.easydns.com/dyn/tomato.php?hostname=[DOMAIN]&myip=[IP]" +"easydns.com" "http://[USERNAME]:[PASSWORD]@api.cp.easydns.com/dyn/tomato.php?hostname=[DOMAIN]&myip=[IP]" # Winco DDNS "ddns.com.br" "http://[DOMAIN]:[PASSWORD]@members.ddns.com.br/nic/update?hostname=[DOMAIN]&myip=[IP]" @@ -75,3 +84,6 @@ # MyDNS.JP "mydns.jp" "http://www.mydns.jp/directip.html?MID=[USERNAME]&PWD=[PASSWORD]&IPV4ADDR=[IP]" + +# LoopiaDNS +"loopia.se" "http://[USERNAME]:[PASSWORD]@dns.loopia.se/XDynDNSServer/XDynDNS.php?system=custom&hostname=[DOMAIN]&myip=[IP]" diff --git a/net/ddns-scripts/files/usr/lib/ddns/services_ipv6 b/net/ddns-scripts/files/usr/lib/ddns/services_ipv6 index b0faf4d47..8aeb4e127 100644 --- a/net/ddns-scripts/files/usr/lib/ddns/services_ipv6 +++ b/net/ddns-scripts/files/usr/lib/ddns/services_ipv6 @@ -1,32 +1,34 @@ -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# !!!!! IPv6 Version of original services file !!!!! -# !!!!! funtionally and syntax is the same !!!!! -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# This file contains the update urls for various dynamic dns services. -# Column one contains the service name, column two contains the update url. -# within the update url there are 4 variables you can use: [USERNAME], -# [PASSWORD], [DOMAIN] and [IP]. These are substituted for the username, -# password, and domain name specified in the /etc/config/ddns file when an -# update is performed. The IP is substituted for the current ip address of the -# router. These variables are case sensitive, while urls generally are not, so -# if you need to enter the same text in the url (which seems very unlikely) put -# that text in lowercase, while the variables should remain in uppercase +#666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 +#6 +#6 This file contains the update urls for various dynamic dns services. +#6 Column one contains the service name, column two contains the update url. +#6 within the update url there are 4 variables you can use: [USERNAME], +#6 [PASSWORD], [DOMAIN] and [IP]. These are substituted for the username, +#6 password, and domain name specified in the /etc/config/ddns file when an +#6 update is performed. The IP is substituted for the current ip address of the +#6 router. These variables are case sensitive, while urls generally are not, so +#6 if you need to enter the same text in the url (which seems very unlikely) put +#6 that text in lowercase, while the variables should remain in uppercase +#6 +#6 There are TONS of dynamic dns services out there. There's a huge list of them at: +#6 http://www.dmoz.org/Computers/Software/Internet/Servers/Address_Management/Dynamic_DNS_Services/ +#6 If anyone has time they could update this file to be compatible with a bunch of them +#6 +#6 !!! Since ddns-scripts Version 2.x the update of IPv6 addresses is also supported +#6 !!! This file is used for update of IPv6 adresses only. For IPv4 use services +#6 +#6 !!! Since ddns-scripts Version 2.x the update via provider specific update scripts is supported. +#6 !!! This scripts must be located at /usr/lib/ddns directory if defined inside this file. +#6 !!! Use only the script name (without path). Sample: +#6 !!! "example.com" "update_sample.sh" +#6 +#666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 -# tested with - -# Securepoint Dynamic-DNS-Service +#IPv6 @ Securepoint Dynamic-DNS-Service "spdns.de" "http://[USERNAME]:[PASSWORD]@update.spdns.de/nic/update?hostname=[DOMAIN]&myip=[IP]" -# Hurricane Electric Dynamic DNS +#IPv6 @ Hurricane Electric Dynamic DNS "he.net" "http://[DOMAIN]:[PASSWORD]@dyn.dns.he.net/nic/update?hostname=[DOMAIN]&myip=[IP]" -#### ADD YOURS HERE! ###################################################################################### -# # -# There are TONS of dynamic dns services out there. There's a huge list of them at: # -# http://www.dmoz.org/Computers/Software/Internet/Servers/Address_Management/Dynamic_DNS_Services/ # -# If anyone has time they could update this file to be compatible with a bunch of them # -# # -########################################################################################################### - -# MyDNS.JP +#IPv6 @ MyDNS.JP "mydns.jp" "http://www.mydns.jp/directip.html?MID=[USERNAME]&PWD=[PASSWORD]&IPV6ADDR=[IP]" diff --git a/net/ddns-scripts/files/usr/lib/ddns/update_no-ip.sh b/net/ddns-scripts/files/usr/lib/ddns/update_no-ip.sh new file mode 100644 index 000000000..e7e86d650 --- /dev/null +++ b/net/ddns-scripts/files/usr/lib/ddns/update_no-ip.sh @@ -0,0 +1,47 @@ +# +# script for sending updates to no-ip.com / noip.com +# 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com> +# +# This script is parsed by dynamic_dns_functions.sh inside send_update() function +# +# provider did not reactivate records, if no IP change was recognized +# so we send a dummy (localhost) and a seconds later we send the correct IP addr +# +local __ANSWER __LH +local __UPDURL="http://[USERNAME]:[PASSWORD]@dynupdate.no-ip.com/nic/update?hostname=[DOMAIN]&myip=[IP]" + +# set IP version dependend dummy (localhost) +[ $use_ipv6 -eq 0 ] && __LH="127.0.0.1" || __LH="::1" + +# lets do DUMMY transfer +write_log 7 "sending dummy IP to 'no-ip.com'" +__URL=$(echo $__UPDURL | sed -e "s#\[USERNAME\]#$URL_USER#g" -e "s#\[PASSWORD\]#$URL_PASS#g" \ + -e "s#\[DOMAIN\]#$domain#g" -e "s#\[IP\]#$__LH#g") +[ $use_https -ne 0 ] && __URL=$(echo $__URL | sed -e 's#^http:#https:#') + +do_transfer __ANSWER "$__URL" || return 1 + +write_log 7 "'no-ip.com' answered:\n$__ANSWER" +# analyse provider answers +# "good [IP_ADR]" = successful +# "nochg [IP_ADR]" = no change but OK +echo "$__ANSWER" | grep -E "good|nochg" >/dev/null 2>&1 || return 1 + +# lets wait a seconds +sleep 1 + +# now send the correct data +write_log 7 "sending real IP to 'no-ip.com'" +__URL=$(echo $__UPDURL | sed -e "s#\[USERNAME\]#$URL_USER#g" -e "s#\[PASSWORD\]#$URL_PASS#g" \ + -e "s#\[DOMAIN\]#$domain#g" -e "s#\[IP\]#$__IP#g") +[ $use_https -ne 0 ] && __URL=$(echo $__URL | sed -e 's#^http:#https:#') + +do_transfer __ANSWER "$__URL" || return 1 + +write_log 7 "'no-ip.com' answered:\n$__ANSWER" +# analyse provider answers +# "good [IP_ADR]" = successful +# "nochg [IP_ADR]" = no change but OK +echo "$__ANSWER" | grep -E "good|nochg" >/dev/null 2>&1 +return $? # "0" if "good" or "nochg" found + diff --git a/net/ddns-scripts/files/usr/lib/ddns/update_sample.sh b/net/ddns-scripts/files/usr/lib/ddns/update_sample.sh index fb69081ac..5faafc8cc 100644 --- a/net/ddns-scripts/files/usr/lib/ddns/update_sample.sh +++ b/net/ddns-scripts/files/usr/lib/ddns/update_sample.sh @@ -16,22 +16,22 @@ # # the code here is the copy of the default used inside send_update() # -local __USER __PASS __ANSWER +local __ANSWER # tested with spdns.de local __URL="http://[USERNAME]:[PASSWORD]@update.spdns.de/nic/update?hostname=[DOMAIN]&myip=[IP]" # do replaces in URL -__urlencode __USER "$username" # encode username, might be email or something like this -__urlencode __PASS "$password" # encode password, might have special chars for security reason -__URL=$(echo $__URL | sed -e "s#\[USERNAME\]#$__USER#g" -e "s#\[PASSWORD\]#$__PASS#g" \ +__URL=$(echo $__URL | sed -e "s#\[USERNAME\]#$URL_USER#g" -e "s#\[PASSWORD\]#$URL_PASS#g" \ -e "s#\[DOMAIN\]#$domain#g" -e "s#\[IP\]#$__IP#g") [ $use_https -ne 0 ] && __URL=$(echo $__URL | sed -e 's#^http:#https:#') -__do_transfer __ANSWER "$__URL" -__ERR=$? -[ $__ERR -gt 0 ] && { - verbose_echo "\n!!!!!!!!! ERROR =: Error sending update to DDNS Provider\n" - return 1 -} -verbose_echo " update send =: DDNS Provider answered\n$__ANSWER" -return 0 +do_transfer __ANSWER "$__URL" || return 1 + +write_log 7 "DDNS Provider answered:\n$__ANSWER" + +# analyse provider answers +# "good [IP_ADR]" = successful +# "nochg [IP_ADR]" = no change but OK +echo "$__ANSWER" | grep -E "good|nochg" >/dev/null 2>&1 +return $? # "0" if "good" or "nochg" found + |