Squashed commit of the following: commitlilik-openwrt-22.03fc1d42f069
Author: Christian Schoenebeck <christian.schoenebeck@gmail.com> Date: Sun Sep 21 18:01:43 2014 +0200 [ddns-scripts] Update to Version 2.0.1-1 commit731f9b4df0
Author: Christian Schoenebeck <christian.schoenebeck@gmail.com> Date: Sun Sep 21 17:59:25 2014 +0200 [ddns-scripts] Update to Version 2.0.1-1 personal helper script to create hashes for CA-Certificates for Wget and cURL using https protocol without errors. Sorry GitHub web interface only supports single commits that will be summarized into one pull request. Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com> commitdf8f6c9d5d
Author: Christian Schoenebeck <christian.schoenebeck@gmail.com> Date: Sun Sep 21 17:56:05 2014 +0200 [ddns-scripts] Update to Version 2.0.1-1 rewritten Sorry GitHub web interface only supports single commits that will be summarized into one pull request. Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com> commit50cdf5acb9
Author: Christian Schoenebeck <christian.schoenebeck@gmail.com> Date: Sun Sep 21 17:54:40 2014 +0200 [ddns-scripts] Update to Version 2.0.1-1 rewritten Sorry GitHub web interface only supports single commits that will be summarized into one pull request. Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com> commitb1d650a345
Author: Christian Schoenebeck <christian.schoenebeck@gmail.com> Date: Sun Sep 21 17:52:52 2014 +0200 [ddns-scripts] Update to Version 2.0.1-1 not needed in this version Sorry GitHub web interface only supports single commits that will be summarized into one pull request. Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com> commit9532114b03
Author: Christian Schoenebeck <christian.schoenebeck@gmail.com> Date: Sun Sep 21 17:51:39 2014 +0200 [ddns-scripts] Update to Version 2.0.1-1 same function as existing services file but used for IPv6 Sorry GitHub web interface only supports single commits that will be summarized into one pull request. Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com> commita636bc25c6
Author: Christian Schoenebeck <christian.schoenebeck@gmail.com> Date: Sun Sep 21 17:46:56 2014 +0200 [ddns-scripts] Update to Version 2.0.1-1 New file explaining availible parameters. Sorry GitHub web interface only supports single commits that will be summarized into one pull request. Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com> commit52332354fc
Author: Christian Schoenebeck <christian.schoenebeck@gmail.com> Date: Sun Sep 21 17:44:45 2014 +0200 [ddns-scripts] Update to Version 2.0.1-1 Sorry GitHub web interface only supports single commits that will be summarized into one pull request. Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com>
@ -1,97 +1,29 @@ | |||
################################################################# | |||
# In order to enable dynamic dns you need at least one section, | |||
# and in that seciton the "enabled" option must be set to one | |||
# | |||
# Each section represents an update to a different service | |||
# | |||
# You specify your domain name, your username and your password | |||
# with the optins "domain", "username" and "password" respectively | |||
# Please read ddns.sample | |||
# | |||
# Next you need to specify the name of the service you are | |||
# connecting to "eg. dyndns.org". The format of the update | |||
# urls for several different dynamic dns services is specified | |||
# in the /usr/lib/ddns/services file. This list is hardly complete | |||
# as there are many, many different dynamic dns services. If your | |||
# service is on the list you can merely specify it with the | |||
# "service_name" option. Otherwise you will need to determine | |||
# the format of the url to update with. You can either add an | |||
# entry to the /usr/lib/ddns/services file or specify this with | |||
# the "update_url" option. | |||
# | |||
# We also need to specify the source of the ip address to associate with | |||
# your domain. The "ip_source" option can be "network", "interface" | |||
# or "web", with "network" as the default. | |||
# | |||
# If "ip_source" is "network" you specify a network section in your | |||
# /etc/network config file (e.g. "wan", which is the default) with | |||
# the "ip_network" option. If you specify "wan", you will update | |||
# with whatever the ip for your wan is. | |||
# | |||
# If "ip_source" is "interface" you specify a hardware interface | |||
# (e.g. "eth1") and whatever the current ip of this interface is | |||
# will be associated with the domain when an update is performed. | |||
# | |||
# If "ip_source" is "script" you specify a script to obtain ip address. | |||
# The "ip_script" option should contain path to your script. | |||
# | |||
# The last possibility is that "ip_source" is "web", which means | |||
# that in order to obtain our ip address we will connect to a | |||
# website, and the first valid ip address listed on that page | |||
# will be assumed to be ours. If you are behind another firewall | |||
# this is the best option since none of the local networks or | |||
# interfaces will have the external ip. The website to connect | |||
# to is specified by the "ip_url" option. You may specify multiple | |||
# urls in the option, separated by whitespace. | |||
# | |||
# Finally we need to specify how often to check whether we need | |||
# to check whether the ip address has changed (and if so update | |||
# it) and how often we need to force an update ( many services | |||
# will expire your domain if you don't connect and do an update | |||
# every so often). Use the "check_interval" to specify how | |||
# often to check whether an update is necessary, the "retry_interval" | |||
# to specify how often to retry in case the update has failed, and | |||
# the "force_interval" option to specify how often to force an | |||
# update. Specify the units for these values with the "check_unit", | |||
# the "retry_init" and the "force_unit" options. Units can be | |||
# "days", "hours", "minutes" or "seconds". The default force_unit | |||
# is hours, the default retry_unit is seconds and the default | |||
# check_unit is seconds. The default check_interval is 600 seconds, | |||
# or ten minutes. The default retry_interval is 60 seconds, or one | |||
# minute. The default force_interval is 72 hours or 3 days. | |||
# | |||
# | |||
######################################################### | |||
config ddns "global" | |||
option date_format "%F %R" | |||
# option run_dir "/var/run/ddns" | |||
# option log_dir "/var/log/ddns" | |||
option log_lines "250" | |||
config service "myddns" | |||
option enabled "0" | |||
option interface "wan" | |||
option use_syslog "1" | |||
config service "myddns_ipv4" | |||
option service_name "dyndns.org" | |||
option domain "mypersonaldomain.dyndns.org" | |||
option username "myusername" | |||
option password "mypassword" | |||
option use_https "0" | |||
option force_interval "72" | |||
option force_unit "hours" | |||
option check_interval "10" | |||
option check_unit "minutes" | |||
option retry_interval "60" | |||
option retry_unit "seconds" | |||
#option ip_source "network" | |||
#option ip_network "wan" | |||
#option ip_source "interface" | |||
#option ip_interface "eth0.1" | |||
#option ip_source "script" | |||
#option ip_script "path to your scrip" | |||
option ip_source "web" | |||
option ip_url "http://checkip.dyndns.com/" | |||
#option update_url "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]" | |||
option domain "yourhost.dyndns.org" | |||
option username "your_username" | |||
option password "your_password" | |||
option interface "wan" | |||
option ip_source "network" | |||
option ip_network "wan" | |||
config service "myddns_ipv6" | |||
option update_url "http://[USERNAME]:[PASSWORD]@your.provider.net/nic/update?hostname=[DOMAIN]&myip=[IP]" | |||
option domain "yourhost.dyndns.org" | |||
option username "your_username" | |||
option password "your_password" | |||
option use_ipv6 "1" | |||
option interface "wan6" | |||
option ip_source "network" | |||
option ip_network "wan6" | |||
@ -0,0 +1,272 @@ | |||
# | |||
# | |||
# Here you find a description on every parameter supported | |||
# and used by ddns-scripts and corresponding LuCI application | |||
# | |||
# Inside your ddns configuration file (/etc/config/ddns) | |||
# you might not find some of below described options. | |||
# This is because you don't need to define options | |||
# if using there defaults. The LuCI application will delete | |||
# options that configured to there default values. | |||
# | |||
# If you have a working ddns configuration from old ddns-scripts (Version 1.x) | |||
# everything will function the same with new scripts | |||
# without any changes to the configuration. | |||
# | |||
# If you like to use this file for your configuration then | |||
# use a copy, because the used software to modify the | |||
# configuration files will throw away all empty lines | |||
# and those starting with # (comments). | |||
# | |||
##################################################################### | |||
# Global application settings | |||
# | |||
config ddns "global" | |||
########### | |||
# set date format to use for display date in logfiles | |||
# and LuCI web application. | |||
# For codes see man pages of date command. | |||
# default: "%F %R" (ISO 8601 format) | |||
# option date_format "%F %R" | |||
########### | |||
# set run directory to use for .pid and .update files | |||
# there will be a separate file for every running service section | |||
# default: "/var/run/ddns" | |||
# option run_dir "/var/run/ddns" | |||
########### | |||
# set log directory to use for .log files | |||
# there will be a separate file for every running service section | |||
# default: "/var/log/ddns" | |||
# option log_dir "/var/log/ddns" | |||
########### | |||
# set number of lines stored in .log file before auto truncated | |||
# default: "250" lines | |||
# option log_lines "250" | |||
##################################################################### | |||
# DDNS service settings | |||
# | |||
# for each service you want to serve you need a separate configuration | |||
# if you need IPv4 and IPv6 you need to setup 2 separate configurations | |||
# with different names. (i.e. "myddns_ipv4" and "myddns_ipv6") | |||
# do not use white-spaces or dashes "-" or "@" ":" "!" or | |||
# other special characters inside name. | |||
config service "myddns" | |||
########### Basic settings ######################## | |||
########### | |||
# enable/disable this service section | |||
# default: "0" disabled | |||
option enabled "0" | |||
########### | |||
# detecting/sending IPv4 or IPv6 address to the DDNS provider | |||
# set to "1" if you want to use IPv6 | |||
# default: "0" use IPv4 | |||
option use_ipv6 "0" | |||
########### | |||
# defines the network as defined in /etc/config/network | |||
# to be monitored for up/down events to start via hotplug | |||
default: "wan" for IPv4 | |||
default: "wan6" for IPv6 | |||
option interface "wan" | |||
########### | |||
# Next you need to specify the name of the service you are | |||
# connecting to "eg. dyndns.org". The format of the update | |||
# urls for several different dynamic dns services is specified | |||
# in the "/usr/lib/ddns/services" file for IPv4 and in | |||
# "/usr/lib/ddns/service_ipv6" file. This list is hardly complete | |||
# as there are many, many different dynamic dns services. | |||
# If your service is on the list you can merely specify it with the | |||
# "service_name" option. Otherwise you will need to determine | |||
# the format of the url to update with. You can either add an | |||
# entry to the "/usr/lib/ddns/services" or "services_ipv6" file | |||
# or specify this with the "update_url" option. | |||
# default: none | |||
option service_name "dyndns.org" | |||
# sample: | |||
# "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]" | |||
# option update_url "" | |||
########### | |||
# You must specify your domain/host name, your username and your password | |||
# as you get from you DDNS provider. Keep an eye on providers help pages. | |||
# | |||
# Your DNS name / replace [DOMAIN] in update_url | |||
# default: none | |||
option domain "" | |||
# Username of your DDNS service account / replace [USERNAME] in update_url | |||
# default: none | |||
option username "" | |||
# Password of your DDNS service account / replace [PASSWORD] in update_url | |||
# default: none | |||
option password "" | |||
########### | |||
# use HTTPS for secure communication with you DDNS provider | |||
# personally found some providers having problems when not sending | |||
# updates via HTTPS. Yyou must not specify "https://" in update_url. | |||
# It's modified by the scripts themselves | |||
# Needs GNU Wget (with SSL support) or cURL to be installed. | |||
# default: "0" do not use HTTPS | |||
option use_https "0" | |||
# if using HTTPS (see above) the transfer program tries to verify | |||
# the providers server certificate. For verification there needs to be | |||
# the counterpart on this machine. Specify the path or path/file where | |||
# the transfer program can find them. (might need package CA-certificates) | |||
# if you don't want to verify servers certificate (insecure) you should | |||
# this parameter to "IGNORE" (in capital letters) | |||
# default: "/etc/cacert" path where CA-certificate package is installed | |||
option cacert "/etc/cacert" | |||
########### | |||
# for logging and control if everything work fine you can get information inside | |||
# system log . Critical Errors are always send to system log. | |||
# You can define which information you like to log | |||
# 1 == info, notice, warning, errors | |||
# 2 == notice, warning, errors | |||
# 3 == warning, errors | |||
# 4 == errors | |||
# default: "0" off | |||
option use_syslog "0" | |||
########### | |||
# for logging and control if everything work fine you can get information inside | |||
# log file. You find the file per default in /var/log/ddns/[sectionname].log | |||
# The path can be modified for all log files in ddns.global section (see above) | |||
# default: "1" on | |||
option use_logfile "1" | |||
########### Advanced settings ##################### | |||
########### | |||
# you need to specify how ddns-scripts should detect you current local ip. | |||
# the ip_source could be set to "network", "web", "interface" or "script" | |||
# the parameters below specifying the additional information needed for | |||
# the corresponding ip_spource configuration | |||
# default: "network" | |||
# ip_source "network" additional uses option ip_network and detects the | |||
# current local ip on network as defined in /etc/config/network | |||
# default: "wan" using IPv4 | |||
# default: "wan6" using IPv6 | |||
option ip_source "network" | |||
option ip_network "wan" | |||
# ip_source "web" additional uses option ip_url and detects the current | |||
# local ip from special web sides that response with the ip address of | |||
# calling host. If you are behind a firewall/NAT this is the best option | |||
# since none of the local networks or interfaces will have the external ip. | |||
# default: "http://checkip.dyndns.com" using IPv4 | |||
# default: "http://checkipv6.dyndns.com" using IPv6 | |||
# option ip_source "web" | |||
# option ip_url "http://checkip.dyndns.com" | |||
# ip_source "interface" additional uses option ip_interface | |||
# ip_source "interface" uses one of the locally installed physical interfaces | |||
# to detect independent from network they configured to. | |||
# default: none | |||
# option ip_source "interface" | |||
# option ip_interface "eth1" | |||
# ip_source "script" additional uses option ip_script | |||
# it's useful if you want to write your own script to detect the | |||
# current local ip. put full path into ip_script option. | |||
# The script must be executable. | |||
# default: none | |||
# option ip_source "script" | |||
# option ip_script "" | |||
########### | |||
# force_ipversion option will set the "-4" respectively "-6" parameter | |||
# on command line of transfer and DNS lookup program. | |||
# So the whole communication uses the selected IP version between both ends. | |||
# needs GNU Wget or cURL installed for transfer and | |||
# BIND's host for DNS lookup. | |||
# default: "0" disabled | |||
option force_ipversion "0" | |||
########### | |||
# normally the current (in the internet) registered ip is detected using the | |||
# local defined name lookup policies (i.e. /etc/resolve.conf etc.) | |||
# Specify here a DNS server to use instead of the defaults. | |||
# you can use hostname or ip address | |||
# IPv6 address must be in squared brackets "[...]" | |||
# i.e. "google-public-dns-a.google.com" | |||
# default: none | |||
# option dns_server "google-public-dns-a.google.com" | |||
# By default every DNS call is made via UDP protocol | |||
# Some internet provider offer modems that cache UDP DNS requests. | |||
# They also redirect calls to external servers to local. | |||
# To force the usage of TCP for DNS requests enable this option | |||
# Needs BIND's host program be installed | |||
# default: "0" disabled | |||
# option force_dnstcp "0" | |||
########### | |||
# If a Proxy is need to access HTTP/HTTPS pages on the WEB | |||
# it can be configured here also for sending updates to the | |||
# DDNS provider. If you configured use_https='1' above, you | |||
# need to setup your HTTPS proxy here, otherwise your | |||
# HTTP proxy. !!! You should not detect your current IP | |||
# ip_source='web' (see above) because this request is also | |||
# send via the configured proxy !!! | |||
# Syntax: [user:password@]proxy:port !port is required ! | |||
# default: none | |||
# option proxy '' | |||
########### Timer settings ######################## | |||
########### | |||
# defines the time interval to check if local IP has changed | |||
# After the first start and first update send, the system will | |||
# wait this time before verify if update was successful send. | |||
# !!! checks below 5 minutes make no sense because the Internet | |||
# needs about 5-10 minutes to sync an IP-change to all DNS servers !!! | |||
# accepted unit entry’s: 'seconds' 'minutes' 'hours' 'days' | |||
# minimum 5 minutes == 300 seconds | |||
# default 10 minutes | |||
option check_interval '10' | |||
option check_unit 'minutes' | |||
########### | |||
# force to send an update to service provider, if no change was detected. | |||
# consult DDNS providers documentation if your DDNS entry might timeout. | |||
# accepted unit entry’s: 'seconds' 'minutes' 'hours' 'days' | |||
# minimum needs to be greater or equal check interval (see above) | |||
# A special setting of '0' is allowed, which forces the script to run once. | |||
# It sends an update, verify if update was accepted by DNS | |||
# (retry if not) and finish. Useful if you want to start by your own (i.e. cron) | |||
# default 3 days == 72 hours | |||
option force_interval '72' | |||
option force_unit 'hours' | |||
########### | |||
# if error happen on detecting, sending or updating the | |||
# script will retry the relevant action for retry_count times | |||
# before stopping script execution. | |||
# default: 5 | |||
option retry_count '5' | |||
########### | |||
# if error happen on detecting, sending or updating the | |||
# script will retry the relevant action. | |||
# here you define the time to wait before retry is started | |||
# accepted unit entry’s: 'seconds' 'minutes' 'hours' 'days' | |||
# default: 60 seconds | |||
option retry_interval '60' | |||
option retry_unit 'seconds' |
@ -0,0 +1,34 @@ | |||
#!/bin/sh | |||
# | |||
#set -vx | |||
[ -d /etc/ssl/certs ] || { | |||
echo "CA-Certificates not istalled - please install first" | |||
exit 1 | |||
} | |||
NUMCERT=$(find /etc/ssl/certs -name *.crt 2>/dev/null | wc -l) | |||
NUMLINK=$(find /etc/ssl/certs -type l 2>/dev/null | wc -l) | |||
[ $NUMLINK -gt 0 ] && { | |||
echo "File-Links already exist. Exiting" | |||
exit 0 | |||
} | |||
[ -f /usr/bin/openssl ] && OPENSSL="EXIST" | |||
[ -z "$OPENSSL" ] && { | |||
opkg update || exit 1 | |||
opkg install openssl-util 2>/dev/null | |||
} | |||
for CERTFILE in `ls -1 $(1)/etc/ssl/certs`; do \ | |||
HASH=`openssl x509 -hash -noout -in /etc/ssl/certs/$CERTFILE` | |||
SUFFIX=0 | |||
while [ -h "/etc/ssl/certs/$HASH.$SUFFIX" ]; do | |||
let "SUFFIX += 1" | |||
done | |||
ln -s "$CERTFILE" "/etc/ssl/certs/$HASH.$SUFFIX" | |||
echo "link $HASH.$SUFFIX created for $CERTFILE" | |||
done | |||
[ -z "$OPENSSL" ] && opkg remove --force-remove --autoremove openssl-util 2>/dev/null |
@ -1,144 +1,715 @@ | |||
# /usr/lib/dynamic_dns/dynamic_dns_functions.sh | |||
#!/bin/sh | |||
# /usr/lib/ddns/dynamic_dns_functions.sh | |||
# | |||
# Written by Eric Paul Bishop, Janary 2008 | |||
# Original written by Eric Paul Bishop, January 2008 | |||
# Distributed under the terms of the GNU General Public License (GPL) version 2.0 | |||
# | |||
# This script is (loosely) based on the one posted by exobyte in the forums here: | |||
# (Loosely) based on the script on the one posted by exobyte in the forums here: | |||
# http://forum.openwrt.org/viewtopic.php?id=14040 | |||
# | |||
# extended and partial rewritten by Christian Schoenebeck in August 2014 to support: | |||
# - 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.) | |||
# - 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 | |||
# copied from http://www.ict.griffith.edu.au/anthony/software/timeout.sh | |||
# @author Anthony Thyssen 6 April 2011 | |||
# | |||
# variables in small chars are read from /etc/config/ddns | |||
# variables in big chars are defined inside these scripts as global vars | |||
# variables in big chars beginning with "__" are local defined inside functions only | |||
#set -vx #script debugger | |||
. /lib/functions.sh | |||
. /lib/functions/network.sh | |||
# 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 | |||
# directory to store run information to. | |||
RUNDIR=$(uci -q get ddns.global.run_dir) || RUNDIR="/var/run/ddns" | |||
# NEW # directory to store log files | |||
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 | |||
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 | |||
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 | |||
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 | |||
# 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" | |||
DATE_PROG="date +'$DATE_FORMAT'" | |||
# regular expression to detect IPv4 / IPv6 | |||
# IPv4 0-9 1-3x "." 0-9 1-3x "." 0-9 1-3x "." 0-9 1-3x | |||
IPV4_REGEX="[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | |||
# IPv6 ( ( 0-9a-f 1-4char ":") min 1x) ( ( 0-9a-f 1-4char )optional) ( (":" 0-9a-f 1-4char ) min 1x) | |||
IPV6_REGEX="\(\([0-9A-Fa-f]\{1,4\}:\)\{1,\}\)\(\([0-9A-Fa-f]\{1,4\}\)\{0,1\}\)\(\(:[0-9A-Fa-f]\{1,4\}\)\{1,\}\)" | |||
#loads all options for a given package and section | |||
#also, sets all_option_variables to a list of the variable names | |||
# loads all options for a given package and section | |||
# also, sets all_option_variables to a list of the variable names | |||
# $1 = ddns, $2 = SECTION_ID | |||
load_all_config_options() | |||
{ | |||
pkg_name="$1" | |||
section_id="$2" | |||
ALL_OPTION_VARIABLES="" | |||
# this callback loads all the variables | |||
# in the section_id section when we do | |||
# config_load. We need to redefine | |||
# the option_cb for different sections | |||
# so that the active one isn't still active | |||
# after we're done with it. For reference | |||
# the $1 variable is the name of the option | |||
# and $2 is the name of the section | |||
local __PKGNAME="$1" | |||
local __SECTIONID="$2" | |||
local __VAR | |||
local __ALL_OPTION_VARIABLES="" | |||
# this callback loads all the variables in the __SECTIONID section when we do | |||
# config_load. We need to redefine the option_cb for different sections | |||
# so that the active one isn't still active after we're done with it. For reference | |||
# the $1 variable is the name of the option and $2 is the name of the section | |||
config_cb() | |||
{ | |||
if [ ."$2" = ."$section_id" ]; then | |||
if [ ."$2" = ."$__SECTIONID" ]; then | |||
option_cb() | |||
{ | |||
ALL_OPTION_VARIABLES="$ALL_OPTION_VARIABLES $1" | |||
__ALL_OPTION_VARIABLES="$__ALL_OPTION_VARIABLES $1" | |||
} | |||
else | |||
option_cb() { return 0; } | |||
fi | |||
} | |||
config_load "$__PKGNAME" | |||
# Given SECTION_ID not found so no data, so return 1 | |||
[ -z "$__ALL_OPTION_VARIABLES" ] && return 1 | |||
config_load "$pkg_name" | |||
for var in $ALL_OPTION_VARIABLES | |||
for __VAR in $__ALL_OPTION_VARIABLES | |||
do | |||
config_get "$var" "$section_id" "$var" | |||
config_get "$__VAR" "$__SECTIONID" "$__VAR" | |||
done | |||
return 0 | |||
} | |||
get_current_ip() | |||
# 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) | |||
start_daemon_for_all_ddns_sections() | |||
{ | |||
local __EVENTIF="$1" | |||
local __SECTIONS="" | |||
local __SECTIONID="" | |||
local __IFACE="" | |||
config_cb() | |||
{ | |||
# only look for section type "service", ignore everything else | |||
[ "$1" == "service" ] && __SECTIONS="$__SECTIONS $2" | |||
} | |||
config_load "ddns" | |||
#if ip source is not defined, assume we want to get ip from wan | |||
if [ "$ip_source" != "interface" ] && [ "$ip_source" != "web" ] && [ "$ip_source" != "script" ] | |||
then | |||
ip_source="network" | |||
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 | |||
} | |||
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 | |||
[ -d $LOGDIR ] || mkdir -p -m 755 $LOGDIR | |||
echo -e " $*" >> $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 | |||
return | |||
} | |||
if [ "$ip_source" = "network" ] | |||
then | |||
if [ -z "$ip_network" ] | |||
then | |||
ip_network="wan" | |||
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 | |||
} | |||
# extract update_url for given DDNS Provider from | |||
# file /usr/lib/ddns/services for IPv4 or from | |||
# file /usr/lib/ddns/services_ipv6 for IPv6 | |||
get_service_url() { | |||
# $1 Name of Variable to store url to | |||
local __LINE __FILE __NAME __URL __SERVICES | |||
local __OLD_IFS=$IFS | |||
local __NEWLINE_IFS=' | |||
' #__NEWLINE_IFS | |||
__FILE="/usr/lib/ddns/services" # IPv4 | |||
[ $use_ipv6 -ne 0 ] && __FILE="/usr/lib/ddns/services_ipv6" # IPv6 | |||
#remove any lines not containing data, and then make sure fields are enclosed in double quotes | |||
__SERVICES=$(cat $__FILE | grep "^[\t ]*[^#]" | \ | |||
awk ' gsub("\x27", "\"") { if ($1~/^[^\"]*$/) $1="\""$1"\"" }; { if ( $NF~/^[^\"]*$/) $NF="\""$NF"\"" }; { print $0 }') | |||
IFS=$__NEWLINE_IFS | |||
for __LINE in $__SERVICES | |||
do | |||
#grep out proper parts of data and use echo to remove quotes | |||
__NAME=$(echo $__LINE | grep -o "^[\t ]*\"[^\"]*\"" | xargs -r -n1 echo) | |||
__URL=$(echo $__LINE | grep -o "\"[^\"]*\"[\t ]*$" | xargs -r -n1 echo) | |||
if [ "$__NAME" = "$service_name" ]; then | |||
break # found so leave for loop | |||
fi | |||
done | |||
IFS=$__OLD_IFS | |||
eval "$1='$__URL'" | |||
return 0 | |||
} | |||
get_seconds() { | |||
# $1 Name of Variable to store result in | |||
# $2 Number and | |||
# $3 Unit of time interval | |||
case "$3" in | |||
"days" ) eval "$1=$(( $2 * 86400 ))";; | |||
"hours" ) eval "$1=$(( $2 * 3600 ))";; | |||
"minutes" ) eval "$1=$(( $2 * 60 ))";; | |||
* ) eval "$1=$2";; | |||
esac | |||
return 0 | |||
} | |||
__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 | |||
# - replace exit by return for usage as function | |||
# - some reformating | |||
# | |||
# 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 | |||
# nicely without messages or leaving any extra processes when finished. | |||
# | |||
# Example use | |||
# timeout 5 countdown | |||
# | |||
### | |||
# | |||
# Based on notes in my "Shell Script Hints", section "Command Timeout" | |||
# http://www.ict.griffith.edu.au/~anthony/info/shell/script.hints | |||
# | |||
# This script uses a lot of tricks to terminate both the background command, | |||
# the timeout script, and even the sleep process. It also includes trap | |||
# commands to prevent sub-shells reporting expected "Termination Errors". | |||
# | |||
# It took years of occasional trials, errors and testing to get a pure bash | |||
# timeout command working as well as this does. | |||
# | |||
### | |||
# | |||
# Anthony Thyssen 6 April 2011 | |||
# | |||
# PROGNAME=$(type $0 | awk '{print $3}') # search for executable on path | |||
# PROGDIR=$(dirname $PROGNAME) # extract directory of program | |||
# PROGNAME=$(basename $PROGNAME) # base name of program | |||
# output the script comments as docs | |||
# Usage() { | |||
# echo >&2 "$PROGNAME:" "$@" | |||
# sed >&2 -n '/^###/q; /^#/!q; s/^#//; s/^ //; 3s/^/Usage: /; 2,$ p' "$PROGDIR/$PROGNAME" | |||
# exit 10; | |||
# } | |||
SIG=-TERM | |||
while [ $# -gt 0 ]; do | |||
case "$1" in | |||
--) | |||
# forced end of user options | |||
shift; | |||
break ;; | |||
# -\?|--help|--doc*) | |||
# Usage ;; | |||
[0-9]*) | |||
TIMEOUT="$1" ;; | |||
-*) | |||
SIG="$1" ;; | |||
*) | |||
# unforced end of user options | |||
break ;; | |||
esac | |||
shift # next option | |||
done | |||
# run main command in backgrouds and get its pid | |||
"$@" & | |||
command_pid=$! | |||
# timeout sub-process abort countdown after ABORT seconds! also backgrounded | |||
sleep_pid=0 | |||
( | |||
# cleanup sleep process | |||
trap 'kill -TERM $sleep_pid; return 1' 1 2 3 15 | |||
# sleep timeout period in background | |||
sleep $TIMEOUT & | |||
sleep_pid=$! | |||
wait $sleep_pid | |||
# Abort the command | |||
kill $SIG $command_pid >/dev/null 2>&1 | |||
return 1 | |||
) & | |||
timeout_pid=$! | |||
# Wait for main command to finished or be timed out | |||
wait $command_pid | |||
status=$? | |||
# Clean up timeout sub-shell - if it is still running! | |||
kill $timeout_pid 2>/dev/null | |||
wait $timeout_pid 2>/dev/null | |||
# Uncomment to check if a LONG sleep still running (no sleep should be) | |||
# sleep 1 | |||
# echo "-----------" | |||
# /bin/ps j # uncomment to show if abort "sleep" is still sleeping | |||
return $status | |||
} | |||
__verify_host_port() { | |||
# $1 Host/IP to verify | |||
# $2 Port to verify | |||
local __HOST=$1 | |||
local __PORT=$2 | |||
local __TMP __IP __IPV4 __IPV6 __RUNPROG __ERRPROG __ERR | |||
# return codes | |||
# 1 system specific error | |||
# 2 nslookup error | |||
# 3 nc (netcat) error | |||
# 4 unmatched IP version | |||
__RUNPROG="nslookup $__HOST 2>/dev/null" | |||
__ERRPROG="nslookup $__HOST 2>&1" | |||
verbose_echo " resolver prog =: '$__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'" | |||
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 '1,2d' | grep -o "Name:\|Address.*" | grep -m 1 -o "$IPV4_REGEX") | |||
__IPV6=$(eval $__RUNPROG | sed '1,2d' | grep -o "Name:\|Address.*" | grep -m 1 -o "$IPV6_REGEX") | |||
} | |||
# check IP version if forced | |||
if [ $force_ipversion -ne 0 ]; then | |||
[ $use_ipv6 -eq 0 -a -z "$__IPV4" ] && return 4 | |||
[ $use_ipv6 -eq 1 -a -z "$__IPV6" ] && return 4 | |||
fi | |||
current_ip=''; | |||
if [ "$ip_source" = "network" ] | |||
then | |||
network_get_ipaddr current_ip "$ip_network" || return | |||
elif [ "$ip_source" = "interface" ] | |||
then | |||
current_ip=$(ifconfig $ip_interface | grep -o 'inet addr:[0-9.]*' | grep -o "$ip_regex") | |||
elif [ "$ip_source" = "script" ] | |||
then | |||
# get ip from script | |||
current_ip=$($ip_script) | |||
else | |||
# get ip from web | |||
# we check each url in order in ip_url variable, and if no ips are found we use dyndns ip checker | |||
# ip is set to FIRST expression in page that matches the ip_regex regular expression | |||
for addr in $ip_url | |||
do | |||
if [ -z "$current_ip" ] | |||
then | |||
current_ip=$(echo $( wget -O - $addr 2>/dev/null) | grep -o "$ip_regex") | |||
fi | |||
done | |||
# 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 with errors" | |||
# busybox nc compiled with extensions | |||
nc --help 2>&1 | grep -q "\-w" && __NCEXT="TRUE" | |||
#here we hard-code the dyndns checkip url in case no url was specified | |||
if [ -z "$current_ip" ] | |||
then | |||
current_ip=$(echo $( wget -O - http://checkip.dyndns.org 2>/dev/null) | grep -o "$ip_regex") | |||
fi | |||
# 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 | |||
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'" | |||
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'" | |||
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'" | |||
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)" | |||
return 3 | |||
fi | |||
} | |||
echo "$current_ip" | |||
verify_dns() { | |||
# $1 DNS server to verify | |||
# we need DNS server to verify otherwise exit with ERROR 1 | |||
[ -z "$1" ] && return 1 | |||
# DNS uses port 53 | |||
__verify_host_port "$1" "53" | |||
} | |||
verify_proxy() { | |||
# $1 Proxy-String to verify | |||
# complete entry user:password@host:port | |||
# host and port only host:port | |||
# host only host unsupported | |||
# IPv4 address instead of host 123.234.234.123 | |||
# IPv6 address instead of host [xxxx:....:xxxx] in square bracket | |||
local __TMP __HOST __PORT | |||
verbose_echo() | |||
{ | |||
if [ "$verbose_mode" = 1 ] | |||
then | |||
echo $1 | |||
# we need Proxy-Sting to verify otherwise exit with ERROR 1 | |||
[ -z "$1" ] && return 1 | |||
# try to split user:password "@" host:port | |||
__TMP=$(echo $1 | awk -F "@" '{print $2}') | |||
# no "@" found - only host:port is given | |||
[ -z "$__TMP" ] && __TMP="$1" | |||
# now lets check for IPv6 address | |||
__HOST=$(echo $__TMP | grep -m 1 -o "$IPV6_REGEX") | |||
# IPv6 host address found read port | |||
if [ -n "$__HOST" ]; then | |||
# IPv6 split at "]:" | |||
__PORT=$(echo $__TMP | awk -F "]:" '{print $2}') | |||
else | |||
__HOST=$(echo $__TMP | awk -F ":" '{print $1}') | |||
__PORT=$(echo $__TMP | awk -F ":" '{print $2}') | |||
fi | |||
# No Port detected ERROR 5 | |||
[ -z "$__PORT" ] && return 5 | |||
__verify_host_port "$__HOST" "$__PORT" | |||
} | |||
syslog_echo() | |||
{ | |||
if [ "$use_syslog" = 1 ] | |||
then | |||
echo $1|logger -t ddns-scripts-$service_id | |||
__do_transfer() { | |||
# $1 # Variable to store Answer of transfer | |||
# $2 # URL to use | |||
local __URL="$2" | |||
local __ERR=0 | |||
local __PROG __RUNPROG __ERRPROG __DATA | |||
# 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 | |||
__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 | |||
[ $use_ipv6 -eq 0 ] && __PROG="$__PROG -4" || __PROG="$__PROG -6" # force IPv4/IPv6 | |||
fi | |||
# set certificate parameters | |||
if [ $use_https -eq 1 ]; then | |||
if [ "$cacert" = "IGNORE" ]; then # idea from Ticket #15327 to ignore server cert | |||
__PROG="$__PROG --no-check-certificate" | |||
elif [ -f "$cacert" ]; then | |||
__PROG="$__PROG --ca-certificate=${cacert}" | |||
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" | |||
fi | |||
fi | |||
# disable proxy if no set (there might be .wgetrc or .curlrc or wrong environment set) | |||
[ -z "$proxy" ] && __PROG="$__PROG --no-proxy" | |||
__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 | |||
} | |||
# 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 | |||
[ $use_ipv6 -eq 0 ] && __PROG="$__PROG -4" || __PROG="$__PROG -6" # force IPv4/IPv6 | |||
fi | |||
# set certificate parameters | |||
if [ $use_https -eq 1 ]; then | |||
if [ "$cacert" = "IGNORE" ]; then # idea from Ticket #15327 to ignore server cert | |||
__PROG="$__PROG --insecure" # but not empty better to use "IGNORE" | |||
elif [ -f "$cacert" ]; then | |||
__PROG="$__PROG --cacert $cacert" | |||
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" | |||
fi | |||
fi | |||
# disable proxy if no set (there might be .wgetrc or .curlrc or wrong environment set) | |||
# or check if libcurl compiled with proxy support | |||
if [ -z "$proxy" ]; then | |||
__PROG="$__PROG --noproxy '*'" | |||
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" | |||
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 | |||
} | |||
# 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" | |||
# https not supported | |||
[ $use_https -eq 1 ] && \ | |||
critical_error "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" | |||
__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'" | |||
return 1 | |||
} | |||
else | |||
critical_error "Program not found - Neither 'Wget' nor 'cURL' installed or executable" | |||
fi | |||
eval "$1='$__DATA'" | |||
return 0 | |||
} | |||
start_daemon_for_all_ddns_sections() | |||
{ | |||
local event_interface="$1" | |||
send_update() { | |||
# $1 # IP to set at DDNS service provider | |||
local __IP __URL __ANSWER __ERR | |||
SECTIONS="" | |||
config_cb() | |||
{ | |||
SECTIONS="$SECTIONS $2" | |||
# verify given IP | |||
[ $use_ipv6 -eq 0 ] && __IP=$(echo $1 | grep -v -E "(^0|^10|^127|^172|^192)") # no private IPv4's | |||
[ $use_ipv6 -eq 1 ] && __IP=$(echo $1 | grep "^[0-9a-eA-E]") # no IPv6 addr starting with fxxx of with ":" | |||
[ -z "$__IP" ] && critical_error "Invalid or no IP '$1' given" | |||
# do replaces in URL | |||
__URL=$(echo $update_url | sed -e "s#\[USERNAME\]#$username#g" -e "s#\[PASSWORD\]#$password#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 | |||
} | |||
config_load "ddns" | |||
for section in $SECTIONS | |||
do | |||
local iface | |||
config_get iface "$section" interface "wan" | |||
[ -z "$event_interface" -o "$iface" = "$event_interface" ] || continue | |||
/usr/lib/ddns/dynamic_dns_updater.sh $section 0 > /dev/null 2>&1 & | |||
done | |||
verbose_echo " update send =: DDNS Provider answered\n$__ANSWER" | |||
return 0 | |||
} | |||
monotonic_time() | |||
{ | |||
local uptime | |||
read uptime < /proc/uptime | |||
echo "${uptime%%.*}" | |||
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 ' | |||
/Bcast.*Mask/ { # 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 | |||
# if NO IP was found | |||
[ -z "$__IP" ] && return 1 | |||
eval "$1='$__IP'" | |||
return 0 | |||
} | |||
get_registered_ip() { | |||
# $1 Name of Variable to store public IP (REGISTERED_IP) | |||
local __IP __REGEX __PROG __RUNPROG __ERRPROG __ERR | |||
# return codes | |||
# 1 no IP detected | |||
# 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 | |||
__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 | |||
[ $use_ipv6 -eq 0 ] && __PROG="$__PROG -4" || __PROG="$__PROG -6" | |||
fi | |||
[ $force_dnstcp -eq 1 ] && __PROG="$__PROG -T" # force TCP | |||
__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 | grep "^$domain" | grep -m 1 -o "$__REGEX") | |||
} | |||
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'" | |||
__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 '1,2d' | grep -o "Name:\|Address.*" | grep -m 1 -o "$__REGEX") | |||
} | |||
else # there must be an error | |||
critical_error "No program found to request public registered IP" | |||
fi | |||
verbose_echo " resolved ip =: '$__IP'" | |||
# if NO IP was found | |||
[ -z "$__IP" ] && return 1 | |||
eval "$1='$__IP'" | |||
return 0 | |||
} | |||
get_uptime() { | |||
# $1 Variable to store result in | |||
local __UPTIME=$(cat /proc/uptime) | |||
eval "$1='${__UPTIME%%.*}'" | |||
} |
@ -1,360 +1,399 @@ | |||
#!/bin/sh | |||
# /usr/lib/dynamic_dns/dynamic_dns_updater.sh | |||
# /usr/lib/ddns/dynamic_dns_updater.sh | |||
# | |||
# Written by Eric Paul Bishop, Janary 2008 | |||
# Original written by Eric Paul Bishop, January 2008 | |||
# Distributed under the terms of the GNU General Public License (GPL) version 2.0 | |||
# | |||
# This script is (loosely) based on the one posted by exobyte in the forums here: | |||
# (Loosely) based on the script on the one posted by exobyte in the forums here: | |||
# http://forum.openwrt.org/viewtopic.php?id=14040 | |||
# | |||
. /usr/lib/ddns/dynamic_dns_functions.sh | |||
service_id=$1 | |||
if [ -z "$service_id" ] | |||
then | |||
echo "ERRROR: You must specify a service id (the section name in the /etc/config/ddns file) to initialize dynamic DNS." | |||
return 1 | |||
fi | |||
#default mode is verbose_mode, but easily turned off with second parameter | |||
verbose_mode="1" | |||
if [ -n "$2" ] | |||
then | |||
verbose_mode="$2" | |||
fi | |||
############################################################### | |||
# Leave this comment here, to clearly document variable names | |||
# that are expected/possible | |||
# extended and partial rewritten by Christian Schoenebeck in August 2014 to support: | |||
# - IPv6 DDNS services | |||
# - DNS Server to retrieve registered IP including TCP transport | |||
# - Proxy Server to send out updates | |||
# - force_interval=0 to run once | |||
# - 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 | |||
# | |||
# Now use load_all_config_options to load config | |||
# options, which is a much more flexible solution. | |||
# variables in small chars are read from /etc/config/ddns | |||
# variables in big chars are defined inside these scripts as global vars | |||
# variables in big chars beginning with "__" are local defined inside functions only | |||
#set -vx #script debugger | |||
[ $# -lt 1 -o -n "${2//[0-3]/}" -o ${#2} -gt 1 ] && { | |||
echo -e "\n USAGE:" | |||
echo -e " $0 [SECTION] [VERBOSE_MODE]\n" | |||
echo " [SECTION] - service section as defined in /etc/config/ddns" | |||
echo " [VERBOSE_MODE] - '0' NO output to console" | |||
echo " '1' output to console" | |||
echo " '2' output to console AND logfile" | |||
echo " + run once WITHOUT retry on error" | |||
echo " '3' output to console AND logfile" | |||
echo " + run once WITHOUT retry on error" | |||
echo -e " + NOT sending update to DDNS service\n" | |||
exit 1 | |||
} | |||
. /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 | |||
# set file names | |||
PIDFILE="$RUNDIR/$SECTION_ID.pid" # Process ID file | |||
UPDFILE="$RUNDIR/$SECTION_ID.update" # last update successful send (system uptime) | |||
LOGFILE="$LOGDIR/$SECTION_ID.log" # log file | |||
# 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 | |||
[ $VERBOSE_MODE -gt 1 -a -f $LOGFILE ] && rm -f $LOGFILE | |||
################################################################################ | |||
# 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_load "ddns" | |||
# defined options (also used as variable): | |||
# | |||
# enable self-explanatory | |||
# interface network interface used by hotplug.d i.e. 'wan' or 'wan6' | |||
# | |||
#config_get enabled $service_id enabled | |||
#config_get service_name $service_id service_name | |||
#config_get update_url $service_id update_url | |||
# service_name Which DDNS service do you use or "custom" | |||
# update_url URL to use to update your "custom" DDNS service | |||
# | |||
# domain Your DNS name / replace [DOMAIN] in update_url | |||
# username Username of your DDNS service account / replace [USERNAME] in update_url | |||
# password Password of your DDNS service account / replace [PASSWORD] in update_url | |||
# | |||
#config_get username $service_id username | |||
#config_get password $service_id password | |||
#config_get domain $service_id domain | |||
# use_https use HTTPS to update DDNS service | |||
# cacert file or directory where HTTPS can find certificates to verify server; 'IGNORE' ignore check of server certificate | |||
# | |||
# use_syslog log activity to syslog | |||
# | |||
#config_get use_https $service_id use_https | |||
#config_get use_syslog $service_id use_syslog | |||
#config_get cacert $service_id cacert | |||
# ip_source source to detect current local IP ('network' or 'web' or 'script' or 'interface') | |||
# ip_network local defined network to read IP from i.e. 'wan' or 'wan6' | |||
# ip_url URL to read local address from i.e. http://checkip.dyndns.com/ or http://checkipv6.dyndns.com/ | |||
# ip_script full path and name of your script to detect local IP | |||
# ip_interface physical interface to use for detecting | |||
# | |||
#config_get ip_source $service_id ip_source | |||
#config_get ip_interface $service_id ip_interface | |||
#config_get ip_network $service_id ip_network | |||
#config_get ip_url $service_id ip_url | |||
# check_interval check for changes every !!! checks below 10 minutes make no sense because the Internet | |||
# check_unit 'days' 'hours' 'minutes' !!! needs about 5-10 minutes to sync an IP-change for an DNS entry | |||
# | |||
#config_get force_interval $service_id force_interval | |||
#config_get force_unit $service_id force_unit | |||
# force_interval force to send an update to your service if no change was detected | |||
# force_unit 'days' 'hours' 'minutes' !!! force_interval="0" runs this script once for use i.e. with cron | |||
# | |||
#config_get check_interval $service_id check_interval | |||
#config_get check_unit $service_id check_unit | |||
######################################################### | |||
load_all_config_options "ddns" "$service_id" | |||
#some defaults | |||
if [ -z "$check_interval" ] | |||
then | |||
check_interval=600 | |||
fi | |||
if [ -z "$retry_interval" ] | |||
then | |||
retry_interval=60 | |||
fi | |||
if [ -z "$check_unit" ] | |||
then | |||
check_unit="seconds" | |||
fi | |||
if [ -z "$force_interval" ] | |||
then | |||
force_interval=72 | |||
fi | |||
if [ -z "$force_unit" ] | |||
then | |||
force_unit="hours" | |||
fi | |||
if [ -z $use_syslog ] | |||
then | |||
use_syslog=0 | |||
fi | |||
if [ -z "$use_https" ] | |||
then | |||
use_https=0 | |||
fi | |||
#some constants | |||
retrieve_prog="/usr/bin/wget -O - "; | |||
if [ "x$use_https" = "x1" ] | |||
then | |||
/usr/bin/wget --version 2>&1 |grep -q "\+ssl" | |||
if [ $? -eq 0 ] | |||
then | |||
if [ -f "$cacert" ] | |||
then | |||
retrieve_prog="${retrieve_prog}--ca-certificate=${cacert} " | |||
elif [ -d "$cacert" ] | |||
then | |||
retrieve_prog="${retrieve_prog}--ca-directory=${cacert} " | |||
fi | |||
else | |||
retrieve_prog="/usr/bin/curl " | |||
if [ -f "$cacert" ] | |||
then | |||
retrieve_prog="${retrieve_prog}--cacert $cacert " | |||
elif [ -d "$cacert" ] | |||
then | |||
retrieve_prog="${retrieve_prog}--capath $cacert " | |||
fi | |||
fi | |||
fi | |||
service_file="/usr/lib/ddns/services" | |||
ip_regex="[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | |||
NEWLINE_IFS=' | |||
' | |||
#determine what update url we're using if the service_name is supplied | |||
if [ -n "$service_name" ] | |||
then | |||
#remove any lines not containing data, and then make sure fields are enclosed in double quotes | |||
quoted_services=$(cat $service_file | grep "^[\t ]*[^#]" | awk ' gsub("\x27", "\"") { if ($1~/^[^\"]*$/) $1="\""$1"\"" }; { if ( $NF~/^[^\"]*$/) $NF="\""$NF"\"" }; { print $0 }' ) | |||
#echo "quoted_services = $quoted_services" | |||
OLD_IFS=$IFS | |||
IFS=$NEWLINE_IFS | |||
for service_line in $quoted_services | |||
do | |||
#grep out proper parts of data and use echo to remove quotes | |||
next_name=$(echo $service_line | grep -o "^[\t ]*\"[^\"]*\"" | xargs -r -n1 echo) | |||
next_url=$(echo $service_line | grep -o "\"[^\"]*\"[\t ]*$" | xargs -r -n1 echo) | |||
if [ "$next_name" = "$service_name" ] | |||
then | |||
update_url=$next_url | |||
fi | |||
done | |||
IFS=$OLD_IFS | |||
fi | |||
if [ "x$use_https" = x1 ] | |||
then | |||
update_url=$(echo $update_url | sed -e 's/^http:/https:/') | |||
fi | |||
verbose_echo "update_url=$update_url" | |||
#if this service isn't enabled then quit | |||
if [ "$enabled" != "1" ] | |||
then | |||
return 0 | |||
fi | |||
#compute update interval in seconds | |||
case "$force_unit" in | |||
"days" ) | |||
force_interval_seconds=$(($force_interval*60*60*24)) | |||
;; | |||
"hours" ) | |||
force_interval_seconds=$(($force_interval*60*60)) | |||
;; | |||
"minutes" ) | |||
force_interval_seconds=$(($force_interval*60)) | |||
;; | |||
"seconds" ) | |||
force_interval_seconds=$force_interval | |||
;; | |||
* ) | |||
#default is hours | |||
force_interval_seconds=$(($force_interval*60*60)) | |||
;; | |||
esac | |||
#compute check interval in seconds | |||
case "$check_unit" in | |||
"days" ) | |||
check_interval_seconds=$(($check_interval*60*60*24)) | |||
;; | |||
"hours" ) | |||
check_interval_seconds=$(($check_interval*60*60)) | |||
;; | |||
"minutes" ) | |||
check_interval_seconds=$(($check_interval*60)) | |||
;; | |||
"seconds" ) | |||
check_interval_seconds=$check_interval | |||
;; | |||
* ) | |||
#default is seconds | |||
check_interval_seconds=$check_interval | |||
;; | |||
esac | |||
#compute retry interval in seconds | |||
case "$retry_unit" in | |||
"days" ) | |||
retry_interval_seconds=$(($retry_interval*60*60*24)) | |||
;; | |||
"hours" ) | |||
retry_interval_seconds=$(($retry_interval*60*60)) | |||
;; | |||
"minutes" ) | |||
retry_interval_seconds=$(($retry_interval*60)) | |||
;; | |||
"seconds" ) | |||
retry_interval_seconds=$retry_interval | |||
;; | |||
* ) | |||
#default is seconds | |||
retry_interval_seconds=$retry_interval | |||
;; | |||
# retry_interval if error was detected retry in | |||
# retry_unit 'days' 'hours' 'minutes' 'seconds' | |||
# retry_count #NEW# number of retries before scripts stops | |||
# | |||
# use_ipv6 #NEW# detecting/sending IPv6 address | |||
# force_ipversion #NEW# force usage of IPv4 or IPv6 for the whole detection and update communication | |||
# dns_server #NEW# using a non default dns server to get Registered IP from Internet | |||
# force_dnstcp #NEW# force communication with DNS server via TCP instead of default UDP | |||
# proxy #NEW# using a proxy for communication !!! ALSO used to detect local IP via web => return proxy's IP !!! | |||
# use_logfile #NEW# self-explanatory "/var/log/ddns/$SECTION_ID.log" | |||
# | |||
# some functionality needs | |||
# - GNU Wget or cURL installed for sending updates to DDNS service | |||
# - BIND host installed to detect Registered IP | |||
# | |||
################################################################################ | |||
# verify and load SECTION_ID is exists | |||
[ "$(uci_get ddns $SECTION_ID)" != "service" ] && { | |||
[ $VERBOSE_MODE -le 1 ] && VERBOSE_MODE=2 # force console out and logfile output | |||
[ -f $LOGFILE ] && rm -f $LOGFILE # clear logfile before first entry | |||
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" | |||
} | |||
load_all_config_options "ddns" "$SECTION_ID" | |||
verbose_echo "\n ************** =: ************** ************** **************" | |||
verbose_echo " STARTED =: PID '$$' at $(eval $DATE_PROG)" | |||
syslog_info "Started" | |||
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'" | |||
esac | |||
verbose_echo " UCI CONFIG =:\n$(uci -q show ddns.$SECTION_ID | sort)" | |||
# set defaults if not defined | |||
[ -z "$enabled" ] && enabled=0 | |||
[ -z "$retry_count" ] && retry_count=5 | |||
[ -z "$use_syslog" ] && use_syslog=0 # not use syslog | |||
[ -z "$use_https" ] && use_https=0 # not use https | |||
[ -z "$use_logfile" ] && use_logfile=1 # NEW - use logfile by default | |||
[ -z "$use_ipv6" ] && use_ipv6=0 # NEW - use IPv4 by default | |||
[ -z "$force_ipversion" ] && force_ipversion=0 # NEW - default let system decide | |||
[ -z "$force_dnstcp" ] && force_dnstcp=0 # NEW - default UDP | |||
[ -z "$ip_source" ] && ip_source="network" | |||
[ "$ip_source" = "network" -a -z "$ip_network" -a $use_ipv6 -eq 0 ] && ip_network="wan" # IPv4: default wan | |||
[ "$ip_source" = "network" -a -z "$ip_network" -a $use_ipv6 -eq 1 ] && ip_network="wan6" # IPv6: default wan6 | |||
[ "$ip_source" = "web" -a -z "$ip_url" -a $use_ipv6 -eq 0 ] && ip_url="http://checkip.dyndns.com" | |||
[ "$ip_source" = "web" -a -z "$ip_url" -a $use_ipv6 -eq 1 ] && ip_url="http://checkipv6.dyndns.com" | |||
[ "$ip_source" = "interface" -a -z "$ip_interface" ] && ip_interface="eth1" | |||
# 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" | |||
# verify 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" | |||
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" | |||
verbose_echo "force seconds = $force_interval_seconds" | |||
verbose_echo "check seconds = $check_interval_seconds" | |||
# determine what update url we're using if a service_name is supplied | |||
# otherwise update_url is set inside configuration (custom service) | |||
[ -n "$service_name" ] && get_service_url update_url | |||
[ -z "$update_url" ] && critical_error "no update url found/defined" | |||
#kill old process if it exists & set new pid file | |||
if [ -d /var/run/dynamic_dns ] | |||
then | |||
if [ -d $RUNDIR ]; then | |||
#if process is already running, stop it | |||
if [ -e "/var/run/dynamic_dns/$service_id.pid" ] | |||
then | |||
old_pid=$(cat /var/run/dynamic_dns/$service_id.pid) | |||
test_match=$(ps | grep "^[\t ]*$old_pid") | |||
verbose_echo "old process id (if it exists) = \"$test_match\"" | |||
if [ -n "$test_match" ] | |||
then | |||
kill $old_pid | |||
fi | |||
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 | |||
else | |||
#make dir since it doesn't exist | |||
mkdir /var/run/dynamic_dns | |||
mkdir -p $RUNDIR | |||
verbose_echo "old process id =: PID 'none'" | |||
fi | |||
echo $$ > /var/run/dynamic_dns/$service_id.pid | |||
#determine when the last update was | |||
current_time=$(monotonic_time) | |||
last_update=$(( $current_time - (2*$force_interval_seconds) )) | |||
if [ -e "/var/run/dynamic_dns/$service_id.update" ] | |||
then | |||
last_update=$(cat /var/run/dynamic_dns/$service_id.update) | |||
echo $$ > $PIDFILE | |||
# determine when the last update was | |||
# the following lines should prevent multiple updates if hotplug fires multiple startups | |||
# as described in Ticket #7820, but did not function if never an update take place | |||
# i.e. after a reboot (/var is linked to /tmp) | |||
# using uptime as reference because date might not be updated via NTP client | |||
get_uptime CURR_TIME | |||
[ -e "$UPDFILE" ] && { | |||
LAST_TIME=$(cat $UPDFILE) | |||
# check also LAST > CURR because link of /var/run to /tmp might be removed | |||
# i.e. boxes with larger filesystems | |||
[ -z "$LAST_TIME" ] && LAST_TIME=0 | |||
[ $LAST_TIME -gt $CURR_TIME ] && LAST_TIME=0 | |||
} | |||
if [ $LAST_TIME -eq 0 ]; then | |||
verbose_echo " 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)" | |||
fi | |||
time_since_update=$(($current_time - $last_update)) | |||
human_time_since_update=$(( $time_since_update / ( 60 * 60 ) )) | |||
verbose_echo "time_since_update = $human_time_since_update hours" | |||
#do update and then loop endlessly, checking ip every check_interval and forcing an updating once every force_interval | |||
while [ true ] | |||
do | |||
registered_ip=$(echo $(nslookup "$domain" 2>/dev/null) | grep -o "Name:.*" | grep -o "$ip_regex") | |||
current_ip=$(get_current_ip) | |||
current_time=$(monotonic_time) | |||
time_since_update=$(($current_time - $last_update)) | |||
syslog_echo "Running IP check ..." | |||
verbose_echo "Running IP check..." | |||
verbose_echo "current system ip = $current_ip" | |||
verbose_echo "registered domain ip = $registered_ip" | |||
if [ "$current_ip" != "$registered_ip" ] || [ $force_interval_seconds -lt $time_since_update ] | |||
then | |||
verbose_echo "update necessary, performing update ..." | |||
#do replacement | |||
final_url=$update_url | |||
for option_var in $ALL_OPTION_VARIABLES | |||
do | |||
if [ "$option_var" != "update_url" ] | |||
then | |||
replace_name=$(echo "\[$option_var\]" | tr 'a-z' 'A-Z') | |||
replace_value=$(eval echo "\$$option_var") | |||
replace_value=$(echo $replace_value | sed -f /usr/lib/ddns/url_escape.sed) | |||
final_url=$(echo $final_url | sed s^"$replace_name"^"$replace_value"^g ) | |||
# 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 | |||
[ -n "$dns_server" ] && { | |||
verbose_echo "******* VERIFY =: DNS server '$dns_server'" | |||
verify_dns "$dns_server" | |||
case $? in | |||
0) ;; # everything OK | |||
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";; | |||
4) critical_error "Invalid DNS server Error: '4' - Forced IP Version don't matched";; | |||
*) critical_error "Invalid DNS server Error: '1' - unspecific error";; | |||
esac | |||
} | |||
# verify Proxy server and set environment | |||
[ -n "$proxy" ] && { | |||
verbose_echo "******* VERIFY =: Proxy server 'http://$proxy'" | |||
verify_proxy "$proxy" | |||
case $? in | |||
0) # everything OK | |||
export HTTP_PROXY="http://$proxy" | |||
export HTTPS_PROXY="http://$proxy" | |||
export http_proxy="http://$proxy" | |||
export https_proxy="http://$proxy" | |||
;; | |||
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";; | |||
4) critical_error "Invalid Proxy server Error: '4' - Forced IP Version don't matched";; | |||
5) critical_error "Invalid Proxy server Error: '5' - proxy port missing";; | |||
*) critical_error "Invalid Proxy server Error: '1' - unspecific error";; | |||
esac | |||
} | |||
# 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 | |||
# 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" | |||
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 | |||
# prepare update | |||
# 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 | |||
if [ $VERBOSE_MODE -gt 2 ]; then | |||
verbose_echo " VERBOSE MODE =: NO UPDATE send to DDNS provider" | |||
elif [ "$LOCAL_IP" != "$REGISTERED_IP" ]; then | |||
verbose_echo "******* UPDATE =: LOCAL: '$LOCAL_IP' <=> REGISTERED: '$REGISTERED_IP'" | |||
else | |||
verbose_echo "******* FORCED =: LOCAL: '$LOCAL_IP' == REGISTERED: '$REGISTERED_IP'" | |||
fi | |||
# only send if VERBOSE_MODE < 3 | |||
ERR_LAST=0 | |||
[ $VERBOSE_MODE -lt 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 | |||
done | |||
final_url=$(echo $final_url | sed s^"\[HTTPAUTH\]"^"${username//^/\\^}${password:+:${password//^/\\^}}"^g ) | |||
final_url=$(echo $final_url | sed s/"\[IP\]"/"$current_ip"/g ) | |||
verbose_echo "updating with url=\"$final_url\"" | |||
#here we actually connect, and perform the update | |||
update_output=$( $retrieve_prog "$final_url" ) | |||
if [ $? -gt 0 ] | |||
then | |||
syslog_echo "update failed, retrying in $retry_interval_seconds seconds" | |||
verbose_echo "update failed" | |||
sleep $retry_interval_seconds | |||
continue | |||
else | |||
# we send data so save "last time" | |||
get_uptime LAST_TIME | |||
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 | |||
syslog_echo "Update successful" | |||
verbose_echo "Update Output:" | |||
verbose_echo "$update_output" | |||
verbose_echo "" | |||
#save the time of the update | |||
current_time=$(monotonic_time) | |||
last_update=$current_time | |||
time_since_update='0' | |||
registered_ip=$current_ip | |||
human_time=$(date) | |||
verbose_echo "update complete, time is: $human_time" | |||
done | |||
echo "$last_update" > "/var/run/dynamic_dns/$service_id.update" | |||
else | |||
human_time=$(date) | |||
human_time_since_update=$(( $time_since_update / ( 60 * 60 ) )) | |||
verbose_echo "update unnecessary" | |||
verbose_echo "time since last update = $human_time_since_update hours" | |||
verbose_echo "the time is now $human_time" | |||
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 | |||
[ $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 | |||
#sleep for 10 minutes, then re-check ip && time since last update | |||
sleep $check_interval_seconds | |||
# 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" | |||
continue # loop to beginning | |||
else | |||
verbose_echo "\n!!!!!!!!! ERROR =: Registered IP <> Local IP - LocalIP: '$LOCAL_IP' - RegisteredIP: '$REGISTERED_IP' - NO retry\n" | |||
fi | |||
fi | |||
# we checked successful the last update | |||
ERR_UPDATE=0 # reset error counter | |||
# 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" | |||
done | |||
#should never get here since we're a daemon, but I'll throw it in anyway | |||
return 0 | |||
verbose_echo "****** STOPPED =: PID '$$' at $(eval $DATE_PROG)\n" | |||
syslog_info "Done" | |||
exit 0 |
@ -0,0 +1,29 @@ | |||
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |||
# !!!!! 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 | |||
# tested with | |||
# Securepoint Dynamic-DNS-Service | |||
"spdns.de" "http://[USERNAME]:[PASSWORD]@update.spdns.de/nic/update?hostname=[DOMAIN]&myip=[IP]" | |||
# 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 # | |||
# # | |||
########################################################################################################### |
@ -1,25 +0,0 @@ | |||
# sed url escaping | |||
s:%:%25:g | |||
s: :%20:g | |||
s:<:%3C:g | |||
s:>:%3E:g | |||
s:#:%23:g | |||
s:{:%7B:g | |||
s:}:%7D:g | |||
s:|:%7C:g | |||
s:\\:%5C:g | |||
s:\^:%5E:g | |||
s:~:%7E:g | |||
s:\[:%5B:g | |||
s:\]:%5D:g | |||
s:`:%60:g | |||
s:;:%3B:g | |||
s:/:%2F:g | |||
s:?:%3F:g | |||
s^:^%3A^g | |||
s:@:%40:g | |||
s:=:%3D:g | |||
s:&:%26:g | |||
s:\$:%24:g | |||
s:\!:%21:g | |||
s:\*:%2A:g |