ddns-scripts: update to version 2.1.0-4

* remove CHANGELOG from distribution
* fix syslog output printing "\n" or other formating chars
* ddns configuration
    - new UCI-config value ddns.global.allow_local_ip "0" or "1"
(default "0") - (OpenWrt Ticket 18642)
* dynamic_dns_functions.sh
- new function split_FQDN() splits a given FQDN into host,
(registerable) domainname, and TLD using
https://publicsuffix.org/list/effective_tld_names.dat
- verify_host_port() use BIND host, if installed
- verify_host_port() not detecting ip, if already given
- fixed regexp for IP detection from nslookup's answer - (OpenWrt
Ticket 16363)
- support ddns.global.allow_local_ip to allow sending non public IP's
to DDNS provider like 127.x, 192.168.x.x or fxxx - (OpenWrt Ticket
18642)
* new file tld_names.dat
- used by dynamic_dns_functions.sh inside split_FQDN() function to
find valid TLD's
* update_cloudflare.sh
- modified subdomain/domain splitting using split_FQDN()
- modified support for AA12.09 (json_get_keys())
- minor fixes and cleanup
- many thanks to Aaron Tanner for testing

Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com>
This commit is contained in:
Christian Schoenebeck
2015-01-11 15:39:47 +01:00
parent 881f9d0107
commit 64250aebc7
8 changed files with 10038 additions and 197 deletions

View File

@@ -12,7 +12,7 @@
# - IPv6 DDNS services
# - setting DNS Server to retrieve current IP including TCP transport
# - Proxy Server to send out updates or retrieving WEB based IP detection
# - force_interval=0 to run once (usefull for cron jobs etc.)
# - force_interval=0 to run once (useful for cron jobs etc.)
# - 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
#
@@ -32,17 +32,20 @@
SECTION_ID="" # hold config's section name
VERBOSE_MODE=1 # default mode is log to console, but easily changed with parameter
# allow NON-public IP's
ALLOW_LOCAL_IP=$(uci -q get ddns.global.allow_local_ip) || ALLOW_LOCAL_IP=0
# directory to store run information to.
RUNDIR=$(uci -q get ddns.global.run_dir) || RUNDIR="/var/run/ddns"
[ -d $RUNDIR ] || mkdir -p -m755 $RUNDIR
# NEW # directory to store log files
# directory to store log files
LOGDIR=$(uci -q get ddns.global.log_dir) || LOGDIR="/var/log/ddns"
[ -d $LOGDIR ] || mkdir -p -m755 $LOGDIR
LOGFILE="" # NEW # logfile can be enabled as new option
LOGFILE="" # logfile - all files are set in dynamic_dns_updater.sh
PIDFILE="" # pid file
UPDFILE="" # store UPTIME of last update
DATFILE="" # save stdout data of WGet and other extern programs called
ERRFILE="" # save stderr output of WGet and other extern programs called
DATFILE="" # save stdout data of WGet and other external programs called
ERRFILE="" # save stderr output of WGet and other external programs called
TLDFILE=/usr/lib/ddns/tld_names.dat # TLD file used by split_FQDN
# number of lines to before rotate logfile
LOGLINES=$(uci -q get ddns.global.log_lines) || LOGLINES=250
@@ -314,8 +317,8 @@ get_service_data() {
done
IFS=$__OLD_IFS
# check is URL or SCRIPT is given
__URL=$(echo "$__DATA" | grep "^http:")
# check if URL or SCRIPT is given
__URL=$(echo "$__DATA" | grep "^http")
[ -z "$__URL" ] && __SCRIPT="/usr/lib/ddns/$__DATA"
eval "$1=\"$__URL\""
@@ -340,15 +343,15 @@ get_seconds() {
timeout() {
# copied from http://www.ict.griffith.edu.au/anthony/software/timeout.sh
# only did the folloing changes
# only did the following changes
# - commented out "#!/bin/bash" and usage section
# - replace exit by return for usage as function
# - some reformating
# - some reformatting
#
# timeout [-SIG] time [--] command args...
#
# Run the given command until completion, but kill it if it runs too long.
# Specifically designed to exit immediatally (no sleep interval) and clean up
# Specifically designed to exit immediately (no sleep interval) and clean up
# nicely without messages or leaving any extra processes when finished.
#
# Example use
@@ -402,7 +405,7 @@ timeout() {
shift # next option
done
# run main command in backgrouds and get its pid
# run main command in backgrounds and get its pid
"$@" &
command_pid=$!
@@ -443,28 +446,45 @@ timeout() {
verify_host_port() {
local __HOST=$1
local __PORT=$2
local __IP __IPV4 __IPV6 __RUNPROG __ERR
local __IP __IPV4 __IPV6 __RUNPROG __PROG __ERR
# return codes
# 1 system specific error
# 2 nslookup error
# 2 nslookup/host error
# 3 nc (netcat) error
# 4 unmatched IP version
[ $# -ne 2 ] && write_log 12 "Error calling 'verify_host_port()' - wrong number of parameters"
__RUNPROG="/usr/bin/nslookup $__HOST >$DATFILE 2>$ERRFILE"
write_log 7 "#> $__RUNPROG"
eval $__RUNPROG
__ERR=$?
# command error
[ $__ERR -gt 0 ] && {
write_log 3 "DNS Resolver Error - BusyBox nslookup Error '$__ERR'"
write_log 7 "$(cat $ERRFILE)"
return 2
# check if ip or FQDN was given
__IPV4=$(echo $__HOST | grep -m 1 -o "$IPV4_REGEX$") # do not detect ip in 0.0.0.0.example.com
__IPV6=$(echo $__HOST | grep -m 1 -o "$IPV6_REGEX")
# if FQDN given get IP address
[ -z "$__IPV4" -a -z "$__IPV6" ] && {
if [ -x /usr/bin/host ]; then # use BIND host if installed
__PROG="BIND host"
__RUNPROG="/usr/bin/host -t ANY $__HOST >$DATFILE 2>$ERRFILE"
else # use BusyBox nslookup
__PROG="BusyBox nslookup"
__RUNPROG="/usr/bin/nslookup $__HOST >$DATFILE 2>$ERRFILE"
fi
write_log 7 "#> $__RUNPROG"
eval $__RUNPROG
__ERR=$?
# command error
[ $__ERR -gt 0 ] && {
write_log 3 "DNS Resolver Error - $__PROG Error '$__ERR'"
write_log 7 "$(cat $ERRFILE)"
return 2
}
# extract IP address
if [ -x /usr/bin/host ]; then # use BIND host if installed
__IPV4=$(cat $DATFILE | awk -F "address " '/has address/ {print $2; exit}' )
__IPV6=$(cat $DATFILE | awk -F "address " '/has IPv6/ {print $2; exit}' )
else # use BusyBox nslookup
__IPV4=$(cat $DATFILE | sed -ne "3,\$ { s/^Address[0-9 ]\{0,\}: \($IPV4_REGEX\).*$/\\1/p }")
__IPV6=$(cat $DATFILE | sed -ne "3,\$ { s/^Address[0-9 ]\{0,\}: \($IPV6_REGEX\).*$/\\1/p }")
fi
}
# extract IP address
__IPV4=$(cat $DATFILE | sed -ne "3,\$ { s/^Address [0-9]*: \($IPV4_REGEX\).*$/\\1/p }")
__IPV6=$(cat $DATFILE | sed -ne "3,\$ { s/^Address [0-9]*: \($IPV6_REGEX\).*$/\\1/p }")
# check IP version if forced
if [ $force_ipversion -ne 0 ]; then
@@ -487,9 +507,9 @@ verify_host_port() {
# 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 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
# then nc will try to connect via IPv6 if there is any IPv6 available on any host interface
# not worrying, if there is an IPv6 wan address
# so if not "force_ipversion" to use_ipv6 then connect test via ipv4, if available
[ $force_ipversion -ne 0 -a $use_ipv6 -ne 0 -o -z "$__IPV4" ] && __IP=$__IPV6 || __IP=$__IPV4
if [ -n "$__NCEXT" ]; then # BusyBox nc compiled with extensions (timeout support)
@@ -512,7 +532,7 @@ verify_host_port() {
fi
}
# verfiy given DNS server if connectable
# verify given DNS server if connectable
# $1 DNS server to verify
verify_dns() {
local __ERR=255 # last error buffer
@@ -546,7 +566,7 @@ verify_dns() {
return 0
}
# analyse and verfiy given proxy string
# analyze and verify given proxy string
# $1 Proxy-String to verify
verify_proxy() {
# complete entry user:password@host:port
@@ -643,7 +663,7 @@ do_transfer() {
# 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 -sS -o $DATFILE --stderr $ERRFILE"
__PROG="/usr/bin/curl -RsS -o $DATFILE --stderr $ERRFILE"
# force ip version to use
if [ $force_ipversion -eq 1 ]; then
[ $use_ipv6 -eq 0 ] && __PROG="$__PROG -4" || __PROG="$__PROG -6" # force IPv4/IPv6
@@ -730,10 +750,14 @@ send_update() {
[ $# -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" ] && write_log 4 "Private or invalid or no IP '$1' given"
if [ $ALLOW_LOCAL_IP -eq 0 ]; then
# 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" ] && write_log 14 "Private or invalid or no IP '$1' given! Please check your configuration"
else
__IP="$1"
fi
if [ -n "$update_script" ]; then
write_log 7 "parsing script '$update_script'"
@@ -751,7 +775,7 @@ send_update() {
write_log 7 "DDNS Provider answered:\n$(cat $DATFILE)"
return 0
# TODO analyse providers answer
# TODO analyze providers answer
# "good" or "nochg" = dyndns.com compatible API
# grep -i -E "good|nochg" $DATFILE >/dev/null 2>&1
# return $? # "0" if found
@@ -915,7 +939,7 @@ get_registered_ip() {
if [ "$__PROG" = "BIND host" ]; then
__DATA=$(cat $DATFILE | awk -F "address " '/has/ {print $2; exit}' )
else
__DATA=$(cat $DATFILE | sed -ne "3,\$ { s/^Address [0-9]*: \($__REGEX\).*$/\\1/p }" )
__DATA=$(cat $DATFILE | sed -ne "3,\$ { s/^Address[0-9 ]\{0,\}: \($__REGEX\).*$/\\1/p }" )
fi
[ -n "$__DATA" ] && {
write_log 7 "Registered IP '$__DATA' detected"
@@ -974,7 +998,7 @@ trap_handler() {
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)"
# reload config via starting the script again
# reload config via starting the script again
eval "/usr/lib/ddns/dynamic_dns_updater.sh $SECTION_ID $VERBOSE_MODE &"
exit 0 ;; # and leave this one
2) write_log 5 "PID '$$' terminated by 'SIGINT' at $(eval $DATE_PROG)\n";;
@@ -999,3 +1023,55 @@ trap_handler() {
trap - 0 1 2 3 15
[ $1 -gt 0 ] && kill -$1 $$
}
split_FQDN() {
# $1 FQDN to split
# $2 name of variable to store TLD
# $3 name of variable to store (reg)Domain
# $4 name of variable to store Host/Subdomain
[ $# -ne 4 ] && write_log 12 "Error calling 'split_FQDN()' - wrong number of parameters"
_SET="$@" # save given parameters
local _FHOST _FTLD _FOUND
local _FDOM=$(echo "$1" | tr [A-Z] [a-z]) # to lower
set -- $(echo "$_FDOM" | tr "." " ") # replace DOT with SPACE and set as script parameters
_FDOM="" # clear variable for later reuse
while [ -n "$1" ] ; do # as long we have parameters
_FTLD=$(echo $@ | tr " " ".") # build back dot separated as TLD
# look if match excludes "!" in tld_names.dat
grep -E "^!$_FTLD$" $TLDFILE >/dev/null 2>&1 || {
# Don't match excludes
# check if match any "*" in tld_names.dat
grep -E "^*.$_FTLD$" $TLDFILE >/dev/null 2>&1 && {
_FOUND="VALID"
break # found leave while
}
# check if exact match in tld_names.dat
grep -E "^$_FTLD$" $TLDFILE >/dev/null 2>&1 && {
_FOUND="VALID"
break # found leave while
}
}
# nothing match so
_FHOST="$_FHOST $_FDOM" # append DOMAIN to last found HOST
_FDOM="$1" # set 1st parameter as DOMAIN
_FTLD="" # clear TLD
shift # delete 1st parameter and retry with the rest
done
set -- $_SET # set back parameters from function call
[ -n "$_FHOST" ] && _FHOST=$(echo $_FHOST | tr " " ".") # put dots back into HOST
[ -n "$_FOUND" ] && {
eval "$2=$_FTLD" # set found TLD
eval "$3=$_FDOM" # set found registrable domain
eval "$4=$_FHOST" # set found HOST/SUBDOMAIN
return 0
}
eval "$2=''" # clear TLD
eval "$3=''" # clear registrable domain
eval "$4=''" # clear HOST/SUBDOMAIN
return 1
}

View File

@@ -116,7 +116,7 @@ trap "trap_handler 15" 15 # SIGTERM Termination
################################################################################
# verify and load SECTION_ID is exists
[ "$(uci_get ddns $SECTION_ID)" != "service" ] && {
[ "$(uci -q 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 "************ ************** ************** **************"
@@ -129,6 +129,7 @@ load_all_config_options "ddns" "$SECTION_ID"
write_log 7 "************ ************** ************** **************"
write_log 5 "PID '$$' started at $(eval $DATE_PROG)"
write_log 7 "uci configuraion:\n$(uci -q show ddns.$SECTION_ID | sort)"
write_log 7 "ddns version : $(opkg list-installed ddns-scripts | awk '{print $3}')"
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";;

File diff suppressed because it is too large Load Diff

View File

@@ -11,17 +11,19 @@
# option domain - your full hostname to update, in cloudflare its subdomain.domain
# i.e. myhost.example.com where myhost is the subdomain and example.com is your domain
#
# Attention !!! script will only work if there is only one subdomain-level at your domain
# subdomain2.subdomain1.domain i.e. mail.host.example.com will not work
#
# variable __IP already defined with the ip-address to use for update
#
[ $use_https -eq 0 ] && write_log 14 "Cloudflare only support updates via Secure HTTP (HTTPS). Please correct configuration!"
local __RECID __URL __KEY __KEYS __FOUND __DOMREC
local __SUBDOM=$(echo $domain | awk -F "." '{print $1}')
local __DOMAIN=$(echo $domain | awk -F "${__SUBDOM}." '{print $2}')
local __TMP="/tmp/$$.json"
local __RECID __URL __KEY __KEYS __FOUND __SUBDOM __DOMAIN __TLD
# split given Host/Domain into TLD, registrable domain, and subdomain
split_FQDN $domain __TLD __DOMAIN __SUBDOM
[ $? -ne 0 -o -z "$__DOMAIN" ] && \
write_log 14 "Wrong Host/Domain configuration ($domain). Please correct configuration!"
# put together what we need
__DOMAIN="$__DOMAIN.$__TLD"
# parse OpenWrt script with
# functions for parsing and generating json
@@ -29,17 +31,17 @@ local __TMP="/tmp/$$.json"
# function copied from /usr/share/libubox/jshn.sh
# from BB14.09 for backward compatibility to AA12.09
json_get_keys() {
local __dest="$1"
local _tbl_cur
grep -i "json_get_keys" /usr/share/libubox/jshn.sh >/dev/null 2>&1 || json_get_keys() {
local __dest="$1"
local _tbl_cur
if [ -n "$2" ]; then
json_get_var _tbl_cur "$2"
else
_json_get_var _tbl_cur JSON_CUR
fi
local __var="${JSON_PREFIX}KEYS_${_tbl_cur}"
eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]"
if [ -n "$2" ]; then
json_get_var _tbl_cur "$2"
else
_json_get_var _tbl_cur JSON_CUR
fi
local __var="${JSON_PREFIX}KEYS_${_tbl_cur}"
eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]"
}
# function to "sed" unwanted string parts from DATFILE
@@ -77,15 +79,13 @@ json_select "recs"
json_select "objs"
json_get_keys __KEYS
for __KEY in $__KEYS; do
local __ZONE __NAME __DISPLAY __TYPE
local __ZONE __DISPLAY __NAME __TYPE
json_select "$__KEY"
json_get_var __ZONE "zone_name"
# json_get_var __ZONE "zone_name" # for debugging
# json_get_var __DISPLAY "display_name" # for debugging
json_get_var __NAME "name"
json_get_var __DISPLAY "display_name"
json_get_var __TYPE "type"
# if "zone_name" == "name" == "display_name" == $domain, then we found a valid domain record
if [ "$__NAME" = "$domain" ]; then
[ "$__DISPLAY" = "$__ZONE" ] && __DOMREC=1 || __DOMREC=0
# we must verify IPv4 and IPv6 because there might be both for the same host
[ \( $use_ipv6 -eq 0 -a "$__TYPE" = "A" \) -o \( $use_ipv6 -eq 1 -a "$__TYPE" = "AAAA" \) ] && {
__FOUND=1 # mark found
@@ -110,14 +110,14 @@ __URL="${__URL}?a=rec_edit" # -d 'a=rec_edit'
__URL="${__URL}&tkn=$password" # -d 'tkn=8afbe6dea02407989af4dd4c97bb6e25'
__URL="${__URL}&id=$__RECID" # -d 'id=9001'
__URL="${__URL}&email=$username" # -d 'email=sample@example.com'
[ $__DOMREC -eq 0 ] && __URL="${__URL}&z=$__DOMAIN" # -d 'z=example.com'
[ $__DOMREC -eq 1 ] && __URL="${__URL}&z=$domain" # -d 'z=example.com'
__URL="${__URL}&z=$__DOMAIN" # -d 'z=example.com'
[ $use_ipv6 -eq 0 ] && __URL="${__URL}&type=A" # -d 'type=A' (IPv4)
[ $use_ipv6 -eq 1 ] && __URL="${__URL}&type=AAAA" # -d 'type=AAAA' (IPv6)
[ $__DOMREC -eq 0 ] && __URL="${__URL}&name=$__SUBDOM" # -d 'name=sub' (HOST/SUBDOMAIN)
[ $__DOMREC -eq 1 ] && __URL="${__URL}&name=$domain" # -d 'name=example.com'(DOMAIN)
# handle subdomain or domain record
[ -n "$__SUBDOM" ] && __URL="${__URL}&name=$__SUBDOM" # -d 'name=sub' (HOST/SUBDOMAIN)
[ -z "$__SUBDOM" ] && __URL="${__URL}&name=$__DOMAIN" # -d 'name=example.com'(DOMAIN)
__URL="${__URL}&content=$__IP" # -d 'content=1.2.3.4'
__URL="${__URL}&service_mode=0" # -d 'service_mode=0'