|
@@ -12,7 +12,7 @@
|
12
|
12
|
# - IPv6 DDNS services
|
13
|
13
|
# - setting DNS Server to retrieve current IP including TCP transport
|
14
|
14
|
# - Proxy Server to send out updates or retrieving WEB based IP detection
|
15
|
|
-# - force_interval=0 to run once (usefull for cron jobs etc.)
|
|
15
|
+# - force_interval=0 to run once (useful for cron jobs etc.)
|
16
|
16
|
# - the usage of BIND's host instead of BusyBox's nslookup if installed (DNS via TCP)
|
17
|
17
|
# - extended Verbose Mode and log file support for better error detection
|
18
|
18
|
#
|
|
@@ -32,17 +32,20 @@
|
32
|
32
|
SECTION_ID="" # hold config's section name
|
33
|
33
|
VERBOSE_MODE=1 # default mode is log to console, but easily changed with parameter
|
34
|
34
|
|
|
35
|
+# allow NON-public IP's
|
|
36
|
+ALLOW_LOCAL_IP=$(uci -q get ddns.global.allow_local_ip) || ALLOW_LOCAL_IP=0
|
35
|
37
|
# directory to store run information to.
|
36
|
38
|
RUNDIR=$(uci -q get ddns.global.run_dir) || RUNDIR="/var/run/ddns"
|
37
|
39
|
[ -d $RUNDIR ] || mkdir -p -m755 $RUNDIR
|
38
|
|
-# NEW # directory to store log files
|
|
40
|
+# directory to store log files
|
39
|
41
|
LOGDIR=$(uci -q get ddns.global.log_dir) || LOGDIR="/var/log/ddns"
|
40
|
42
|
[ -d $LOGDIR ] || mkdir -p -m755 $LOGDIR
|
41
|
|
-LOGFILE="" # NEW # logfile can be enabled as new option
|
|
43
|
+LOGFILE="" # logfile - all files are set in dynamic_dns_updater.sh
|
42
|
44
|
PIDFILE="" # pid file
|
43
|
45
|
UPDFILE="" # store UPTIME of last update
|
44
|
|
-DATFILE="" # save stdout data of WGet and other extern programs called
|
45
|
|
-ERRFILE="" # save stderr output of WGet and other extern programs called
|
|
46
|
+DATFILE="" # save stdout data of WGet and other external programs called
|
|
47
|
+ERRFILE="" # save stderr output of WGet and other external programs called
|
|
48
|
+TLDFILE=/usr/lib/ddns/tld_names.dat # TLD file used by split_FQDN
|
46
|
49
|
|
47
|
50
|
# number of lines to before rotate logfile
|
48
|
51
|
LOGLINES=$(uci -q get ddns.global.log_lines) || LOGLINES=250
|
|
@@ -314,8 +317,8 @@ get_service_data() {
|
314
|
317
|
done
|
315
|
318
|
IFS=$__OLD_IFS
|
316
|
319
|
|
317
|
|
- # check is URL or SCRIPT is given
|
318
|
|
- __URL=$(echo "$__DATA" | grep "^http:")
|
|
320
|
+ # check if URL or SCRIPT is given
|
|
321
|
+ __URL=$(echo "$__DATA" | grep "^http")
|
319
|
322
|
[ -z "$__URL" ] && __SCRIPT="/usr/lib/ddns/$__DATA"
|
320
|
323
|
|
321
|
324
|
eval "$1=\"$__URL\""
|
|
@@ -340,15 +343,15 @@ get_seconds() {
|
340
|
343
|
|
341
|
344
|
timeout() {
|
342
|
345
|
# copied from http://www.ict.griffith.edu.au/anthony/software/timeout.sh
|
343
|
|
- # only did the folloing changes
|
|
346
|
+ # only did the following changes
|
344
|
347
|
# - commented out "#!/bin/bash" and usage section
|
345
|
348
|
# - replace exit by return for usage as function
|
346
|
|
- # - some reformating
|
|
349
|
+ # - some reformatting
|
347
|
350
|
#
|
348
|
351
|
# timeout [-SIG] time [--] command args...
|
349
|
352
|
#
|
350
|
353
|
# Run the given command until completion, but kill it if it runs too long.
|
351
|
|
- # Specifically designed to exit immediatally (no sleep interval) and clean up
|
|
354
|
+ # Specifically designed to exit immediately (no sleep interval) and clean up
|
352
|
355
|
# nicely without messages or leaving any extra processes when finished.
|
353
|
356
|
#
|
354
|
357
|
# Example use
|
|
@@ -402,7 +405,7 @@ timeout() {
|
402
|
405
|
shift # next option
|
403
|
406
|
done
|
404
|
407
|
|
405
|
|
- # run main command in backgrouds and get its pid
|
|
408
|
+ # run main command in backgrounds and get its pid
|
406
|
409
|
"$@" &
|
407
|
410
|
command_pid=$!
|
408
|
411
|
|
|
@@ -443,28 +446,45 @@ timeout() {
|
443
|
446
|
verify_host_port() {
|
444
|
447
|
local __HOST=$1
|
445
|
448
|
local __PORT=$2
|
446
|
|
- local __IP __IPV4 __IPV6 __RUNPROG __ERR
|
|
449
|
+ local __IP __IPV4 __IPV6 __RUNPROG __PROG __ERR
|
447
|
450
|
# return codes
|
448
|
451
|
# 1 system specific error
|
449
|
|
- # 2 nslookup error
|
|
452
|
+ # 2 nslookup/host error
|
450
|
453
|
# 3 nc (netcat) error
|
451
|
454
|
# 4 unmatched IP version
|
452
|
455
|
|
453
|
456
|
[ $# -ne 2 ] && write_log 12 "Error calling 'verify_host_port()' - wrong number of parameters"
|
454
|
457
|
|
455
|
|
- __RUNPROG="/usr/bin/nslookup $__HOST >$DATFILE 2>$ERRFILE"
|
456
|
|
- write_log 7 "#> $__RUNPROG"
|
457
|
|
- eval $__RUNPROG
|
458
|
|
- __ERR=$?
|
459
|
|
- # command error
|
460
|
|
- [ $__ERR -gt 0 ] && {
|
461
|
|
- write_log 3 "DNS Resolver Error - BusyBox nslookup Error '$__ERR'"
|
462
|
|
- write_log 7 "$(cat $ERRFILE)"
|
463
|
|
- return 2
|
|
458
|
+ # check if ip or FQDN was given
|
|
459
|
+ __IPV4=$(echo $__HOST | grep -m 1 -o "$IPV4_REGEX$") # do not detect ip in 0.0.0.0.example.com
|
|
460
|
+ __IPV6=$(echo $__HOST | grep -m 1 -o "$IPV6_REGEX")
|
|
461
|
+ # if FQDN given get IP address
|
|
462
|
+ [ -z "$__IPV4" -a -z "$__IPV6" ] && {
|
|
463
|
+ if [ -x /usr/bin/host ]; then # use BIND host if installed
|
|
464
|
+ __PROG="BIND host"
|
|
465
|
+ __RUNPROG="/usr/bin/host -t ANY $__HOST >$DATFILE 2>$ERRFILE"
|
|
466
|
+ else # use BusyBox nslookup
|
|
467
|
+ __PROG="BusyBox nslookup"
|
|
468
|
+ __RUNPROG="/usr/bin/nslookup $__HOST >$DATFILE 2>$ERRFILE"
|
|
469
|
+ fi
|
|
470
|
+ write_log 7 "#> $__RUNPROG"
|
|
471
|
+ eval $__RUNPROG
|
|
472
|
+ __ERR=$?
|
|
473
|
+ # command error
|
|
474
|
+ [ $__ERR -gt 0 ] && {
|
|
475
|
+ write_log 3 "DNS Resolver Error - $__PROG Error '$__ERR'"
|
|
476
|
+ write_log 7 "$(cat $ERRFILE)"
|
|
477
|
+ return 2
|
|
478
|
+ }
|
|
479
|
+ # extract IP address
|
|
480
|
+ if [ -x /usr/bin/host ]; then # use BIND host if installed
|
|
481
|
+ __IPV4=$(cat $DATFILE | awk -F "address " '/has address/ {print $2; exit}' )
|
|
482
|
+ __IPV6=$(cat $DATFILE | awk -F "address " '/has IPv6/ {print $2; exit}' )
|
|
483
|
+ else # use BusyBox nslookup
|
|
484
|
+ __IPV4=$(cat $DATFILE | sed -ne "3,\$ { s/^Address[0-9 ]\{0,\}: \($IPV4_REGEX\).*$/\\1/p }")
|
|
485
|
+ __IPV6=$(cat $DATFILE | sed -ne "3,\$ { s/^Address[0-9 ]\{0,\}: \($IPV6_REGEX\).*$/\\1/p }")
|
|
486
|
+ fi
|
464
|
487
|
}
|
465
|
|
- # extract IP address
|
466
|
|
- __IPV4=$(cat $DATFILE | sed -ne "3,\$ { s/^Address [0-9]*: \($IPV4_REGEX\).*$/\\1/p }")
|
467
|
|
- __IPV6=$(cat $DATFILE | sed -ne "3,\$ { s/^Address [0-9]*: \($IPV6_REGEX\).*$/\\1/p }")
|
468
|
488
|
|
469
|
489
|
# check IP version if forced
|
470
|
490
|
if [ $force_ipversion -ne 0 ]; then
|
|
@@ -487,9 +507,9 @@ verify_host_port() {
|
487
|
507
|
# connectivity test
|
488
|
508
|
# run busybox nc to HOST PORT
|
489
|
509
|
# busybox might be compiled with "FEATURE_PREFER_IPV4_ADDRESS=n"
|
490
|
|
- # then nc will try to connect via IPv6 if there is any IPv6 availible on any host interface
|
491
|
|
- # not worring, if there is an IPv6 wan address
|
492
|
|
- # so if not "force_ipversion" to use_ipv6 then connect test via ipv4, if availible
|
|
510
|
+ # then nc will try to connect via IPv6 if there is any IPv6 available on any host interface
|
|
511
|
+ # not worrying, if there is an IPv6 wan address
|
|
512
|
+ # so if not "force_ipversion" to use_ipv6 then connect test via ipv4, if available
|
493
|
513
|
[ $force_ipversion -ne 0 -a $use_ipv6 -ne 0 -o -z "$__IPV4" ] && __IP=$__IPV6 || __IP=$__IPV4
|
494
|
514
|
|
495
|
515
|
if [ -n "$__NCEXT" ]; then # BusyBox nc compiled with extensions (timeout support)
|
|
@@ -512,7 +532,7 @@ verify_host_port() {
|
512
|
532
|
fi
|
513
|
533
|
}
|
514
|
534
|
|
515
|
|
-# verfiy given DNS server if connectable
|
|
535
|
+# verify given DNS server if connectable
|
516
|
536
|
# $1 DNS server to verify
|
517
|
537
|
verify_dns() {
|
518
|
538
|
local __ERR=255 # last error buffer
|
|
@@ -546,7 +566,7 @@ verify_dns() {
|
546
|
566
|
return 0
|
547
|
567
|
}
|
548
|
568
|
|
549
|
|
-# analyse and verfiy given proxy string
|
|
569
|
+# analyze and verify given proxy string
|
550
|
570
|
# $1 Proxy-String to verify
|
551
|
571
|
verify_proxy() {
|
552
|
572
|
# complete entry user:password@host:port
|
|
@@ -643,7 +663,7 @@ do_transfer() {
|
643
|
663
|
# 2nd choice is cURL IPv4/IPv6/HTTPS
|
644
|
664
|
# libcurl might be compiled without Proxy Support (default in trunk)
|
645
|
665
|
elif [ -x /usr/bin/curl ]; then
|
646
|
|
- __PROG="/usr/bin/curl -sS -o $DATFILE --stderr $ERRFILE"
|
|
666
|
+ __PROG="/usr/bin/curl -RsS -o $DATFILE --stderr $ERRFILE"
|
647
|
667
|
# force ip version to use
|
648
|
668
|
if [ $force_ipversion -eq 1 ]; then
|
649
|
669
|
[ $use_ipv6 -eq 0 ] && __PROG="$__PROG -4" || __PROG="$__PROG -6" # force IPv4/IPv6
|
|
@@ -730,10 +750,14 @@ send_update() {
|
730
|
750
|
|
731
|
751
|
[ $# -ne 1 ] && write_log 12 "Error calling 'send_update()' - wrong number of parameters"
|
732
|
752
|
|
733
|
|
- # verify given IP / no private IPv4's / no IPv6 addr starting with fxxx of with ":"
|
734
|
|
- [ $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)")
|
735
|
|
- [ $use_ipv6 -eq 1 ] && __IP=$(echo $1 | grep "^[0-9a-eA-E]")
|
736
|
|
- [ -z "$__IP" ] && write_log 4 "Private or invalid or no IP '$1' given"
|
|
753
|
+ if [ $ALLOW_LOCAL_IP -eq 0 ]; then
|
|
754
|
+ # verify given IP / no private IPv4's / no IPv6 addr starting with fxxx of with ":"
|
|
755
|
+ [ $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)")
|
|
756
|
+ [ $use_ipv6 -eq 1 ] && __IP=$(echo $1 | grep "^[0-9a-eA-E]")
|
|
757
|
+ [ -z "$__IP" ] && write_log 14 "Private or invalid or no IP '$1' given! Please check your configuration"
|
|
758
|
+ else
|
|
759
|
+ __IP="$1"
|
|
760
|
+ fi
|
737
|
761
|
|
738
|
762
|
if [ -n "$update_script" ]; then
|
739
|
763
|
write_log 7 "parsing script '$update_script'"
|
|
@@ -751,7 +775,7 @@ send_update() {
|
751
|
775
|
write_log 7 "DDNS Provider answered:\n$(cat $DATFILE)"
|
752
|
776
|
|
753
|
777
|
return 0
|
754
|
|
- # TODO analyse providers answer
|
|
778
|
+ # TODO analyze providers answer
|
755
|
779
|
# "good" or "nochg" = dyndns.com compatible API
|
756
|
780
|
# grep -i -E "good|nochg" $DATFILE >/dev/null 2>&1
|
757
|
781
|
# return $? # "0" if found
|
|
@@ -915,7 +939,7 @@ get_registered_ip() {
|
915
|
939
|
if [ "$__PROG" = "BIND host" ]; then
|
916
|
940
|
__DATA=$(cat $DATFILE | awk -F "address " '/has/ {print $2; exit}' )
|
917
|
941
|
else
|
918
|
|
- __DATA=$(cat $DATFILE | sed -ne "3,\$ { s/^Address [0-9]*: \($__REGEX\).*$/\\1/p }" )
|
|
942
|
+ __DATA=$(cat $DATFILE | sed -ne "3,\$ { s/^Address[0-9 ]\{0,\}: \($__REGEX\).*$/\\1/p }" )
|
919
|
943
|
fi
|
920
|
944
|
[ -n "$__DATA" ] && {
|
921
|
945
|
write_log 7 "Registered IP '$__DATA' detected"
|
|
@@ -974,7 +998,7 @@ trap_handler() {
|
974
|
998
|
write_log 4 "PID '$$' exit WITH ERROR '$__ERR' at $(eval $DATE_PROG)\n"
|
975
|
999
|
fi ;;
|
976
|
1000
|
1) write_log 6 "PID '$$' received 'SIGHUP' at $(eval $DATE_PROG)"
|
977
|
|
- # reload config via starting the script again
|
|
1001
|
+ # reload config via starting the script again
|
978
|
1002
|
eval "/usr/lib/ddns/dynamic_dns_updater.sh $SECTION_ID $VERBOSE_MODE &"
|
979
|
1003
|
exit 0 ;; # and leave this one
|
980
|
1004
|
2) write_log 5 "PID '$$' terminated by 'SIGINT' at $(eval $DATE_PROG)\n";;
|
|
@@ -999,3 +1023,55 @@ trap_handler() {
|
999
|
1023
|
trap - 0 1 2 3 15
|
1000
|
1024
|
[ $1 -gt 0 ] && kill -$1 $$
|
1001
|
1025
|
}
|
|
1026
|
+
|
|
1027
|
+split_FQDN() {
|
|
1028
|
+ # $1 FQDN to split
|
|
1029
|
+ # $2 name of variable to store TLD
|
|
1030
|
+ # $3 name of variable to store (reg)Domain
|
|
1031
|
+ # $4 name of variable to store Host/Subdomain
|
|
1032
|
+
|
|
1033
|
+ [ $# -ne 4 ] && write_log 12 "Error calling 'split_FQDN()' - wrong number of parameters"
|
|
1034
|
+
|
|
1035
|
+ _SET="$@" # save given parameters
|
|
1036
|
+ local _FHOST _FTLD _FOUND
|
|
1037
|
+ local _FDOM=$(echo "$1" | tr [A-Z] [a-z]) # to lower
|
|
1038
|
+
|
|
1039
|
+ set -- $(echo "$_FDOM" | tr "." " ") # replace DOT with SPACE and set as script parameters
|
|
1040
|
+ _FDOM="" # clear variable for later reuse
|
|
1041
|
+
|
|
1042
|
+ while [ -n "$1" ] ; do # as long we have parameters
|
|
1043
|
+ _FTLD=$(echo $@ | tr " " ".") # build back dot separated as TLD
|
|
1044
|
+ # look if match excludes "!" in tld_names.dat
|
|
1045
|
+ grep -E "^!$_FTLD$" $TLDFILE >/dev/null 2>&1 || {
|
|
1046
|
+ # Don't match excludes
|
|
1047
|
+ # check if match any "*" in tld_names.dat
|
|
1048
|
+ grep -E "^*.$_FTLD$" $TLDFILE >/dev/null 2>&1 && {
|
|
1049
|
+ _FOUND="VALID"
|
|
1050
|
+ break # found leave while
|
|
1051
|
+ }
|
|
1052
|
+ # check if exact match in tld_names.dat
|
|
1053
|
+ grep -E "^$_FTLD$" $TLDFILE >/dev/null 2>&1 && {
|
|
1054
|
+ _FOUND="VALID"
|
|
1055
|
+ break # found leave while
|
|
1056
|
+ }
|
|
1057
|
+ }
|
|
1058
|
+ # nothing match so
|
|
1059
|
+ _FHOST="$_FHOST $_FDOM" # append DOMAIN to last found HOST
|
|
1060
|
+ _FDOM="$1" # set 1st parameter as DOMAIN
|
|
1061
|
+ _FTLD="" # clear TLD
|
|
1062
|
+ shift # delete 1st parameter and retry with the rest
|
|
1063
|
+ done
|
|
1064
|
+
|
|
1065
|
+ set -- $_SET # set back parameters from function call
|
|
1066
|
+ [ -n "$_FHOST" ] && _FHOST=$(echo $_FHOST | tr " " ".") # put dots back into HOST
|
|
1067
|
+ [ -n "$_FOUND" ] && {
|
|
1068
|
+ eval "$2=$_FTLD" # set found TLD
|
|
1069
|
+ eval "$3=$_FDOM" # set found registrable domain
|
|
1070
|
+ eval "$4=$_FHOST" # set found HOST/SUBDOMAIN
|
|
1071
|
+ return 0
|
|
1072
|
+ }
|
|
1073
|
+ eval "$2=''" # clear TLD
|
|
1074
|
+ eval "$3=''" # clear registrable domain
|
|
1075
|
+ eval "$4=''" # clear HOST/SUBDOMAIN
|
|
1076
|
+ return 1
|
|
1077
|
+}
|