Merge pull request #3829 from chris5560/for-15.05

[For 15.05] ddns-scripts: Backport of current version 2.7.6-11
This commit is contained in:
Hannu Nyman 2017-01-12 22:34:36 +02:00 committed by GitHub
commit 7f2618d2d5
19 changed files with 4414 additions and 1425 deletions

View File

@ -1,5 +1,5 @@
#
# Copyright (C) 2008-2015 OpenWrt.org
# Copyright (C) 2008-2017 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
#
@ -9,10 +9,10 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=ddns-scripts
# Version == major.minor.patch
# increase on new functionality (minor) or patches (patch)
PKG_VERSION:=2.4.3
PKG_VERSION:=2.7.6
# Release == build
# increase on changes of services files or tld_names.dat
PKG_RELEASE:=2
PKG_RELEASE:=11
PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
@ -29,7 +29,7 @@ define Package/$(PKG_NAME)/Default
PKGARCH:=all
endef
##### **********************************
###### *************************************************************************
define Package/$(PKG_NAME)
$(call Package/$(PKG_NAME)/Default)
TITLE:=Dynamic DNS Client scripts (with IPv6 support)
@ -43,31 +43,47 @@ define Package/$(PKG_NAME)/config
help
A highly configurable set of scripts for doing dynamic dns updates.
- IPv6 support
- force communication to IPv4 or IPv6 only
- DNS server support
- using BIND host if installed
- Glue Record support (require BIND host or KNOT host)
- DNS requests via TCP
- Proxy server support
- log file support
- support to run once
.
Version: $(PKG_VERSION)-$(PKG_RELEASE)
Info : http://wiki.openwrt.org/doc/howto/ddns.client
.
$(PKG_MAINTAINER)
endef
##### **********************************
###### *************************************************************************
define Package/$(PKG_NAME)_cloudflare
$(call Package/$(PKG_NAME)/Default)
TITLE:=DDNS extension for CloudFlare
TITLE:=CloudFlare.com API v1 (deprecated)
DEPENDS:=$(PKG_NAME)
endef
define Package/$(PKG_NAME)_cloudflare/description
Dynamic DNS Client scripts extension for CloudFlare
Dynamic DNS Client scripts extension for CloudFlare.com API-v1 (deprecated)
endef
##### **********************************
###### *************************************************************************
define Package/$(PKG_NAME)_cloudflare.com-v4
$(call Package/$(PKG_NAME)/Default)
TITLE:=CloudFlare.com API v4 (require cURL)
DEPENDS:=$(PKG_NAME) +curl
endef
define Package/$(PKG_NAME)_cloudflare.com-v4/description
Dynamic DNS Client scripts extension for CloudFlare.com API-v4 (require/install cURL)
endef
###### *************************************************************************
define Package/$(PKG_NAME)_godaddy.com-v1
$(call Package/$(PKG_NAME)/Default)
TITLE:=GoDaddy.com (require cURL)
DEPENDS:=$(PKG_NAME) +curl
endef
define Package/$(PKG_NAME)_godaddy.com-v1/description
Dynamic DNS Client scripts extension for GoDaddy.com (require/install cURL)
endef
###### *************************************************************************
define Package/$(PKG_NAME)_no-ip_com
$(call Package/$(PKG_NAME)/Default)
TITLE:=DDNS extension for No-IP.com
@ -77,7 +93,7 @@ define Package/$(PKG_NAME)_no-ip_com/description
Dynamic DNS Client scripts extension for No-IP.com
endef
##### **********************************
###### *************************************************************************
define Package/$(PKG_NAME)_nsupdate
$(call Package/$(PKG_NAME)/Default)
TITLE:=DDNS extension using Bind nsupdate
@ -88,129 +104,293 @@ define Package/$(PKG_NAME)_nsupdate/description
endef
define Package/$(PKG_NAME)_nsupdate/config
help
The script directly updates a PowerDNS (or maybe bind server) via nsupdate
from bind-client package. It requires
The script directly updates a PowerDNS (or maybe bind server) via nsupdate
from bind-client package. It requires
"option dns_server" to be set to the server to be used by nsupdate.
"option username" should be set to the key name and
"option username" should be set to the key name and
"option password" to the base64 encoded shared secret.
endef
##### **********************************
###### *************************************************************************
define Build/Configure
endef
define Build/Compile
$(CP) ./files $(PKG_BUILD_DIR)
# ensure that VERSION inside dynamic_dns_functions.sh reflect PKG_VERSION of Makefile
$(SED) '/^VERSION=*/s/.*/VERSION="$(PKG_VERSION)-$(PKG_RELEASE)"/' $(PKG_BUILD_DIR)/files/dynamic_dns_functions.sh
# remove comments, white spaces and empty lines
for FILE in `find $(PKG_BUILD_DIR)/files -type f`; do \
$(SED) 's/^\s*#/#/' \
-e '/^#\s\|^#$$$$/d' \
-e 's/\s#\s.*$$$$//' \
-e 's/\s*$$$$//' \
-e '/^\/\/\s/d' \
-e '/^\s*$$$$/d' $$$$FILE; \
$(SED) 's/^[[:space:]]*//' \
-e '/^#[[:space:]]\|^#$$$$/d' \
-e 's/[[:space:]]#[[:space:]].*$$$$//' \
-e 's/[[:space:]]*$$$$//' \
-e '/^\/\/[[:space:]]/d' \
-e '/^[[:space:]]*$$$$/d' $$$$FILE; \
done
gzip -f9 $(PKG_BUILD_DIR)/files/tld_names.dat
# compress public_suffix_list.dat
gzip -f9 $(PKG_BUILD_DIR)/files/public_suffix_list.dat
endef
define Package/$(PKG_NAME)/conffiles
/etc/config/ddns
endef
##### **********************************
###### *************************************************************************
define Package/$(PKG_NAME)/preinst
#!/bin/sh
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.hotplug $(1)/etc/hotplug.d/iface/95-ddns
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.init $(1)/etc/init.d/ddns
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.defaults $(1)/etc/uci-defaults/ddns
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.hotplug $(1)/etc/hotplug.d/iface/95-ddns
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.init $(1)/etc/init.d/ddns
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(PKG_BUILD_DIR)/files/ddns.config $(1)/etc/config/ddns
$(INSTALL_DIR) $(1)/usr/lib/ddns
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/services* $(1)/usr/lib/ddns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/dynamic_*.sh $(1)/usr/lib/ddns
$(INSTALL_DIR) $(1)/etc/ddns
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/services* $(1)/etc/ddns
$(INSTALL_DIR) $(1)/usr/lib/ddns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/dynamic_dns_*.sh $(1)/usr/lib/ddns
endef
define Package/$(PKG_NAME)/postinst
#!/bin/sh
# if run within buildroot exit
[ -n "$${IPKG_INSTROOT}" ] && exit 0
# add new section "ddns" "global" if not exists
uci -q get ddns.global > /dev/null || uci -q set ddns.global='ddns'
uci -q get ddns.global.date_format > /dev/null || uci -q set ddns.global.date_format='%F %R'
uci -q get ddns.global.log_lines > /dev/null || uci -q set ddns.global.log_lines='250'
uci -q get ddns.global.allow_local_ip > /dev/null || uci -q set ddns.global.allow_local_ip='0'
uci -q commit ddns
# clear LuCI indexcache
rm -f /tmp/luci-indexcache >/dev/null 2>&1
exit 0
# if NOT run buildroot and PKG_UPGRADE then (re)start service if enabled
[ -z "$${IPKG_INSTROOT}" -a "$${PKG_UPGRADE}" = "1" ] && {
[ -x /etc/uci-defaults/ddns ] && \
/etc/uci-defaults/ddns && \
rm -f /etc/uci-defaults/ddns >/dev/null 2>&1
/etc/init.d/ddns enabled && \
/etc/init.d/ddns start >/dev/null 2>&1
}
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)/prerm
#!/bin/sh
# if run within buildroot exit
[ -n "$${IPKG_INSTROOT}" ] && exit 0
# stop running scripts
/etc/init.d/ddns disable
/etc/init.d/ddns stop
/etc/init.d/ddns disable
# clear LuCI indexcache
rm -f /tmp/luci-indexcache >/dev/null 2>&1
exit 0
exit 0 # suppress errors
endef
##### **********************************
###### *************************************************************************
define Package/$(PKG_NAME)_cloudflare/preinst
#!/bin/sh
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)_cloudflare/install
$(INSTALL_DIR) $(1)/usr/lib/ddns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/update_CloudFlare.sh $(1)/usr/lib/ddns
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/tld_names.dat.gz $(1)/usr/lib/ddns
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.defaults $(1)/etc/uci-defaults/ddns_cloudflare
$(INSTALL_DIR) $(1)/usr/share
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/public_suffix_list.dat.gz $(1)/usr/share
$(INSTALL_DIR) $(1)/usr/lib/ddns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/update_cloudflare_com_v1.sh $(1)/usr/lib/ddns
endef
define Package/$(PKG_NAME)_cloudflare/postinst
#!/bin/sh
echo -e '"CloudFlare"\t"update_CloudFlare.sh"' >> $${IPKG_INSTROOT}/usr/lib/ddns/services
echo -e '"CloudFlare"\t"update_CloudFlare.sh"' >> $${IPKG_INSTROOT}/usr/lib/ddns/services_ipv6
# remove old services file entries
/bin/sed -i '/cloudflare\.com-v1/d' $${IPKG_INSTROOT}/etc/ddns/services >/dev/null 2>&1
/bin/sed -i '/cloudflare\.com-v1/d' $${IPKG_INSTROOT}/etc/ddns/services_ipv6 >/dev/null 2>&1
# and create new
printf "%s\\t%s\\n" '"cloudflare.com-v1"' '"update_cloudflare_com_v1.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services
printf "%s\\t%s\\n" '"cloudflare.com-v1"' '"update_cloudflare_com_v1.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services_ipv6
# on real system restart service if enabled
[ -z "$${IPKG_INSTROOT}" ] && {
[ -x /etc/uci-defaults/ddns_cloudflare ] && \
/etc/uci-defaults/ddns_cloudflare && \
rm -f /etc/uci-defaults/ddns_cloudflare >/dev/null 2>&1
/etc/init.d/ddns enabled && \
/etc/init.d/ddns start >/dev/null 2>&1
}
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)_cloudflare/prerm
#!/bin/sh
/bin/sed -i '/update_CloudFlare\.sh/ d' $${IPKG_INSTROOT}/usr/lib/ddns/services
/bin/sed -i '/update_CloudFlare\.sh/ d' $${IPKG_INSTROOT}/usr/lib/ddns/services_ipv6
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
# remove services file entries
/bin/sed -i '/cloudflare\.com-v1/d' $${IPKG_INSTROOT}/etc/ddns/services >/dev/null 2>&1
/bin/sed -i '/cloudflare\.com-v1/d' $${IPKG_INSTROOT}/etc/ddns/services_ipv6 >/dev/null 2>&1
exit 0 # suppress errors
endef
##### **********************************
define Package/$(PKG_NAME)_no-ip_com/install
###### *************************************************************************
define Package/$(PKG_NAME)_cloudflare.com-v4/preinst
#!/bin/sh
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)_cloudflare.com-v4/install
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.defaults $(1)/etc/uci-defaults/ddns_cloudflare.com-v4
$(INSTALL_DIR) $(1)/usr/lib/ddns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/update_No-IP.com.sh $(1)/usr/lib/ddns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/update_cloudflare_com_v4.sh $(1)/usr/lib/ddns
endef
define Package/$(PKG_NAME)_cloudflare.com-v4/postinst
#!/bin/sh
# remove old services file entries
/bin/sed -i '/cloudflare\.com-v4/d' $${IPKG_INSTROOT}/etc/ddns/services >/dev/null 2>&1
/bin/sed -i '/cloudflare\.com-v4/d' $${IPKG_INSTROOT}/etc/ddns/services_ipv6 >/dev/null 2>&1
# and create new
printf "%s\\t%s\\n" '"cloudflare.com-v4"' '"update_cloudflare_com_v4.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services
printf "%s\\t%s\\n" '"cloudflare.com-v4"' '"update_cloudflare_com_v4.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services_ipv6
# on real system restart service if enabled
[ -z "$${IPKG_INSTROOT}" ] && {
[ -x /etc/uci-defaults/ddns_cloudflare.com-v4 ] && \
/etc/uci-defaults/ddns_cloudflare.com-v4 && \
rm -f /etc/uci-defaults/ddns_cloudflare.com-v4 >/dev/null 2>&1
/etc/init.d/ddns enabled && \
/etc/init.d/ddns start >/dev/null 2>&1
}
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)_cloudflare.com-v4/prerm
#!/bin/sh
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
# remove services file entries
/bin/sed -i '/cloudflare\.com-v4/d' $${IPKG_INSTROOT}/etc/ddns/services >/dev/null 2>&1
/bin/sed -i '/cloudflare\.com-v4/d' $${IPKG_INSTROOT}/etc/ddns/services_ipv6 >/dev/null 2>&1
exit 0 # suppress errors
endef
###### *************************************************************************
define Package/$(PKG_NAME)_godaddy.com-v1/preinst
#!/bin/sh
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)_godaddy.com-v1/install
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.defaults $(1)/etc/uci-defaults/ddns_godaddy.com-v1
$(INSTALL_DIR) $(1)/usr/lib/ddns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/update_godaddy_com_v1.sh $(1)/usr/lib/ddns
endef
define Package/$(PKG_NAME)_godaddy.com-v1/postinst
#!/bin/sh
# remove old services file entries
/bin/sed -i '/godaddy\.com-v1/d' $${IPKG_INSTROOT}/etc/ddns/services >/dev/null 2>&1
/bin/sed -i '/godaddy\.com-v1/d' $${IPKG_INSTROOT}/etc/ddns/services_ipv6 >/dev/null 2>&1
# and create new
printf "%s\\t%s\\n" '"godaddy.com-v1"' '"update_godaddy_com_v1.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services
printf "%s\\t%s\\n" '"godaddy.com-v1"' '"update_godaddy_com_v1.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services_ipv6
# on real system restart service if enabled
[ -z "$${IPKG_INSTROOT}" ] && {
[ -x /etc/uci-defaults/ddns_godaddy.com-v1 ] && \
/etc/uci-defaults/ddns_godaddy.com-v1 && \
rm -f /etc/uci-defaults/ddns_godaddy.com-v1 >/dev/null 2>&1
/etc/init.d/ddns enabled \
&& /etc/init.d/ddns start >/dev/null 2>&1
}
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)_godaddy.com-v1/prerm
#!/bin/sh
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
# remove services file entries
/bin/sed -i '/godaddy\.com-v1/d' $${IPKG_INSTROOT}/etc/ddns/services >/dev/null 2>&1
/bin/sed -i '/godaddy\.com-v1/d' $${IPKG_INSTROOT}/etc/ddns/services_ipv6 >/dev/null 2>&1
exit 0 # suppress errors
endef
###### *************************************************************************
define Package/$(PKG_NAME)_no-ip_com/preinst
#!/bin/sh
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)_no-ip_com/install
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.defaults $(1)/etc/uci-defaults/ddns_no-ip_com
$(INSTALL_DIR) $(1)/usr/lib/ddns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/update_no-ip_com.sh $(1)/usr/lib/ddns
endef
define Package/$(PKG_NAME)_no-ip_com/postinst
#!/bin/sh
echo -e '"No-IP.com"\t"update_No-IP.com.sh"' >> $${IPKG_INSTROOT}/usr/lib/ddns/services
echo -e '"NoIP.com"\t"update_No-IP.com.sh"' >> $${IPKG_INSTROOT}/usr/lib/ddns/services
# remove old services file entries
/bin/sed -i '/no-ip\.com/d' $${IPKG_INSTROOT}/etc/ddns/services >/dev/null 2>&1
# and create new
printf "%s\\t%s\\n" '"no-ip.com"' '"update_no-ip_com.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services
# on real system restart service if enabled
[ -z "$${IPKG_INSTROOT}" ] && {
[ -x /etc/uci-defaults/ddns_no-ip_com ] && \
/etc/uci-defaults/ddns_no-ip_com && \
rm -f /etc/uci-defaults/ddns_no-ip_com >/dev/null 2>&1
/etc/init.d/ddns enabled && \
/etc/init.d/ddns start >/dev/null 2>&1
}
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)_no-ip_com/prerm
#!/bin/sh
/bin/sed -i '/update_No-IP\.com\.sh/ d' $${IPKG_INSTROOT}/usr/lib/ddns/services
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
# remove services file entries
/bin/sed -i '/no-ip\.com/d' $${IPKG_INSTROOT}/etc/ddns/services >/dev/null 2>&1
exit 0 # suppress errors
endef
##### **********************************
###### *************************************************************************
define Package/$(PKG_NAME)_nsupdate/preinst
#!/bin/sh
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)_nsupdate/install
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.defaults $(1)/etc/uci-defaults/ddns_nsupdate
$(INSTALL_DIR) $(1)/usr/lib/ddns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/update_nsupdate.sh $(1)/usr/lib/ddns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/files/update_nsupdate.sh $(1)/usr/lib/ddns
endef
define Package/$(PKG_NAME)_nsupdate/postinst
#!/bin/sh
echo -e '"Bind-nsupdate"\t"update_nsupdate.sh"' >> $${IPKG_INSTROOT}/usr/lib/ddns/services
echo -e '"Bind-nsupdate"\t"update_nsupdate.sh"' >> $${IPKG_INSTROOT}/usr/lib/ddns/services_ipv6
# remove old services file entries
/bin/sed -i '/bind-nsupdate/d' $${IPKG_INSTROOT}/etc/ddns/services >/dev/null 2>&1
/bin/sed -i '/bind-nsupdate/d' $${IPKG_INSTROOT}/etc/ddns/services_ipv6 >/dev/null 2>&1
# and create new
printf "%s\\t%s\\n" '"bind-nsupdate"' '"update_nsupdate.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services
printf "%s\\t%s\\n" '"bind-nsupdate"' '"update_nsupdate.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services_ipv6
# on real system restart service if enabled
[ -z "$${IPKG_INSTROOT}" ] && {
[ -x /etc/uci-defaults/ddns_nsupdate ] && \
/etc/uci-defaults/ddns_nsupdate && \
rm -f /etc/uci-defaults/ddns_nsupdate >/dev/null 2>&1
/etc/init.d/ddns enabled && \
/etc/init.d/ddns start >/dev/null 2>&1
}
exit 0 # suppress errors
endef
define Package/$(PKG_NAME)_nsupdate/prerm
#!/bin/sh
/bin/sed -i '/update_nsupdate\.sh/ d' $${IPKG_INSTROOT}/usr/lib/ddns/services
/bin/sed -i '/update_nsupdate\.sh/ d' $${IPKG_INSTROOT}/usr/lib/ddns/services_ipv6
# if NOT run buildroot then stop service
[ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
# remove services file entries
/bin/sed -i '/bind-nsupdate/d' $${IPKG_INSTROOT}/etc/ddns/services >/dev/null 2>&1
/bin/sed -i '/bind-nsupdate/d' $${IPKG_INSTROOT}/etc/ddns/services_ipv6 >/dev/null 2>&1
exit 0 # suppress errors
endef
##### **********************************
###### *************************************************************************
$(eval $(call BuildPackage,$(PKG_NAME)))
$(eval $(call BuildPackage,$(PKG_NAME)_cloudflare))
$(eval $(call BuildPackage,$(PKG_NAME)_cloudflare.com-v4))
$(eval $(call BuildPackage,$(PKG_NAME)_godaddy.com-v1))
$(eval $(call BuildPackage,$(PKG_NAME)_no-ip_com))
$(eval $(call BuildPackage,$(PKG_NAME)_nsupdate))

View File

@ -1,17 +1,17 @@
#
# Please read ddns.sample
# or http://wiki.openwrt.org/doc/uci/ddns
# Please read http://wiki.openwrt.org/doc/uci/ddns
#
config ddns "global"
option date_format "%F %R"
# option run_dir "/var/run/ddns"
# option log_dir "/var/log/ddns"
option log_lines "250"
option allow_local_ip "0"
option ddns_dateformat "%F %R"
# option ddns_rundir "/var/run/ddns"
# option ddns_logdir "/var/log/ddns"
option ddns_loglines "250"
option upd_privateip "0"
config service "myddns_ipv4"
option service_name "dyndns.com"
option service_name "dyndns.org"
option lookup_host "yourhost.example.com"
option domain "yourhost.example.com"
option username "your_username"
option password "your_password"
@ -21,6 +21,7 @@ config service "myddns_ipv4"
config service "myddns_ipv6"
option update_url "http://[USERNAME]:[PASSWORD]@your.provider.net/nic/update?hostname=[DOMAIN]&myip=[IP]"
option lookup_host "yourhost.example.com"
option domain "yourhost.example.com"
option username "your_username"
option password "your_password"

View File

@ -0,0 +1,309 @@
#!/bin/sh
g_pslfile=/usr/share/public_suffix_list.dat.gz
[ -f "$g_pslfile" ] || g_pslfile="$(dirname $0)/public_suffix_list.dat.gz"
g_pslerr=0
g_cfgfile="ddns"
# modify "cloudflare.com-v1" domain to new syntax
# returns "host[.subdom]@domain.TLD" of given FQDN #############################
mod_cloudflare_v1_domain() {
# $1 entry to validate/split
[ -f "$g_pslfile" ] || return 1
[ $# -ne 1 -o -z "$1" ] && \
{ printf "%s\\n" "mod_cloudflare_v1_domain() - Invalid number of parameters" >&2; return 1; }
local mcd_fqdn=$1
local mcd_fsub=""
local mcd_fdom=""
local mcd_ctld=""
local mcd_ftld=""
# check if already new syntax, "@" inside string
if [ $( printf "%s" "$mcd_fqdn" | grep -cF "@" 2>/dev/null ) -gt 0 ]; then
# already done
printf "%s" "$mcd_fqdn"
return 0
fi
# we need to do in one line because otherwise sh doesn't work correctly
# to lower | replace "." to " " | awk invert word order
set -- $(printf %s "$mcd_fqdn" | tr [A-Z] [a-z] | tr "." " " \
| awk '{do printf "%s"(NF>1?OFS:ORS),$NF;while (--NF)}' )
while [ -n "${1:-}" ] ; do # as long we have parameters
if [ -z "$mcd_ctld" ]; then # first loop
mcd_ctld="$1" # CURRENT TLD to look at
shift
else
mcd_ctld="$1.$mcd_ctld" # Next TLD to look at
shift
fi
# check if TLD exact match in public_suffix_name.dat, save TLD
zcat $g_pslfile | grep -E "^$mcd_ctld$" >/dev/null 2>&1 && {
mcd_ftld="$mcd_ctld" # save found
mcd_fdom="${1:-}" # save domain next step might be invalid
continue
}
# check if match any "*" in public_suffix_name.dat,
zcat $g_pslfile | grep -E "^\*.$mcd_ctld$" >/dev/null 2>&1 && {
[ -z "${1:-}" ] && break # no more data break
# check if next level TLD match excludes "!" in tld_names.dat
if zcat $g_pslfile | grep -E "^!$1.$mcd_ctld$" >/dev/null 2>&1 ; then
mcd_ftld="$mcd_ctld" # Yes
else
mcd_ftld="$1.$mcd_ctld"
shift
fi
mcd_fdom="$1"; shift
}
[ -n "$mcd_ftld" ] && break # we have something valid, break
done
# the leftover parameters are the HOST/SUBDOMAIN
while [ -n "${1:-}" ]; do
mcd_fsub="${1}${mcd_fsub:+.$mcd_fsub}" # remember we need to invert
shift # and insert dot if mcd_fsub not empty
done
# now validate found data
[ -z "$mcd_ftld" ] && { printf "%s\\n" "mod_cloudflare_v1_domain() - no TLD not found in '$mcd_fqdn'" >&1; return 1; }
[ -z "$mcd_fdom" ] && { printf "%s\\n" "mod_cloudflare_v1_domain() - no registrable Domain not found in '$mcd_fqdn'" >&1; return 1; }
# return data
printf "%s" "${mcd_fsub:+${mcd_fsub}@}${mcd_fdom}.${mcd_ftld}"
return 0
}
# modify timer settings from interval and unit to dhms format
timer2dhms() {
# $1 Number and
# $2 Unit of time interval
local t=0
case $2 in
days) t=$(( $1 * 86400 ));;
hours) t=$(( $1 * 3600 ));;
minutes) t=$(( $1 * 60 ));;
*) t=$1;;
esac
local d=$(( $t / 86400 ))
local h=$(( $t % 86400 / 3600 ))
local m=$(( $t % 3600 / 60 ))
local s=$(( $t % 60 ))
if [ $d -gt 0 ]; then printf "%dd %02dh %02dm %02ds" "$d" "$h" "$m" "$s"
elif [ $h -gt 0 ]; then printf "%dh %02dm %02ds" "$h" "$m" "$s"
elif [ $m -gt 0 ]; then printf "%dm %02ds" "$m" "$s"
else printf "%ds" "$s"; fi
unset d h m s t
return 0
}
# using function to not confuse function calls with existing ones inside /lib/functions.sh
update_config() {
uc_uci="$(which uci) -q" # ignore errors
uc_cfg=""
uc_name=""
uc_var=""
uc_val=""
package() { return 0; }
config () {
uc_cfg="$1"
uc_name="$2"
# Type = ddns Name = global
if [ "$uc_cfg" = "$g_cfgfile" -a "$uc_name" = "global" ]; then
option() {
uc_var="$1"; shift
uc_val="$*"
case "$uc_var" in
allow_local_ip) $uc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_privateip";;
date_format) $uc_uci rename $g_cfgfile.$uc_name.$uc_var="ddns_dateformat";;
log_lines) $uc_uci rename $g_cfgfile.$uc_name.$uc_var="ddns_loglines";;
log_dir) $uc_uci rename $g_cfgfile.$uc_name.$uc_var="ddns_logdir";;
run_dir) $uc_uci rename $g_cfgfile.$uc_name.$uc_var="ddns_rundir";;
# leave all other options currently unchanged
*) ;;
esac
}
# Type = service Name = ???
elif [ "$uc_cfg" = "service" ]; then
option() {
uc_var="$1"; shift
uc_val="$*"
case "$uc_var" in
# fix some option service_name values
# and some settings for specific providers
service_name|upd_provider)
case "$uc_val" in
freedns\.afraid\.org|afraid\.org)
$uc_uci set $g_cfgfile.$uc_name.$uc_var="afraid.org-keyauth";;
Bind-nsupdate)
$uc_uci set $g_cfgfile.$uc_name.$uc_var="bind-nsupdate";;
CloudFlare|cloudflare\.com|cloudflare\.com-v1)
# verify if lookup_host is set
$uc_uci get $g_cfgfile.$uc_name.lookup_host >/dev/null 2>&1 || {
ucv_domain=$($uc_uci get $g_cfgfile.$uc_name.domain 2>/dev/null)
$uc_uci set $g_cfgfile.$uc_name.lookup_host="$ucv_domain"
}
if [ -f "$g_pslfile" ]; then
# change value of domain/upd_object to new syntax
# there is no sort order inside uci data so we need multiple checks
ucv_domain=$($uc_uci get $g_cfgfile.$uc_name.domain 2>/dev/null)
ucv_object=$($uc_uci get $g_cfgfile.$uc_name.upd_object 2>/dev/null)
# still old option domain
if [ -n "$ucv_domain" ]; then
ucv_new=$(mod_cloudflare_v1_domain "$ucv_domain") || g_pslerr=1
# no error save data save data
[ $g_pslerr -eq 0 ] && \
$uc_uci set $g_cfgfile.$uc_name.domain="$ucv_new"
fi
# already new option upd_object
if [ -n "$ucv_object" ]; then
ucv_new=$(mod_cloudflare_v1_domain "$ucv_object") || g_pslerr=1
# no error save data save data
[ $g_pslerr -eq 0 ] && \
$uc_uci set $g_cfgfile.$uc_name.upd_object="$ucv_new"
fi
fi
unset ucv_domain ucv_object ucv_new
# set new option value
$uc_uci set $g_cfgfile.$uc_name.$uc_var="cloudflare.com-v1"
;;
dyndns\.org|dyndns\.com)
$uc_uci set $g_cfgfile.$uc_name.$uc_var="dyn.com";;
free\.editdns\.net)
$uc_uci set $g_cfgfile.$uc_name.$uc_var="editdns.net";;
domains\.google\.com)
$uc_uci set $g_cfgfile.$uc_name.$uc_var="google.com";;
loopia\.com)
$uc_uci set $g_cfgfile.$uc_name.$uc_var="loopia.se";;
NoIP\.com|No-IP\.com)
$uc_uci set $g_cfgfile.$uc_name.$uc_var="no-ip.com";;
spdns\.de)
$uc_uci set $g_cfgfile.$uc_name.$uc_var="spdyn.de";;
strato\.de)
$uc_uci set $g_cfgfile.$uc_name.$uc_var="strato.com";;
*)
# all others leave unchanged
;;
esac
# rename option service_name to option upd_provider
# $uc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_provider"
;;
domain|upd_object)
# verify if lookup_host is set
$uc_uci get $g_cfgfile.$uc_name.lookup_host >/dev/null 2>&1 || \
$uc_uci set $g_cfgfile.$uc_name.lookup_host="$uc_val"
if [ -f "$g_pslfile" ]; then
# if service_name/upd_provider cloudflare_v1 then change domain/upd_object to new syntax
# there is no sort order inside uci data so we need multiple checks
uco_provider=$($uc_uci get $g_cfgfile.$uc_name.upd_provider 2>/dev/null) || \
uco_provider=$($uc_uci get $g_cfgfile.$uc_name.service_name 2>/dev/null)
if [ "$uco_provider" = "CloudFlare" \
-o "$uco_provider" = "cloudflare.com" \
-o "$uco_provider" = "cloudflare.com-v1" ]; then
ucv_new=$(mod_cloudflare_v1_domain "$uc_val") || g_pslerr=1
# no error save data save data
[ $g_pslerr -eq 0 ] && \
$uc_uci set $g_cfgfile.$uc_name.$uc_var="$ucv_new"
unset ucv_new
fi
unset uco_provider
fi
# rename option domain to option upd_object
# $uc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_object"
;;
# dns_server)
# # if bind-nsupdate takeover old "dns_server" value as new "upd_nsupd_server" value
# uco_provider=$($uc_uci get $g_cfgfile.$uc_name.upd_provider 2>/dev/null) || \
# uco_provider=$($uc_uci get $g_cfgfile.$uc_name.service_name 2>/dev/null)
# [ "$uco_provider" = "Bind-nsupdate" -o \
# "$uco_provider" = "bind-nsupdate" ] && \
# $uc_uci set $g_cfgfile.$uc_name.upd_nsupd_server="$uc_val"
# # rename option dns_server to new option global_dnssvr
# $udc_uci rename $g_cfgfile.$uc_name.$uc_var="global_dnssvr"
# ;;
# bind_network)
# $udc_uci set $g_cfgfile.$uc_name.upd_url_bindnet="$uc_val"
# $udc_uci rename $g_cfgfile.$uc_name.$uc_var="lip_url_bindnet"
# ;;
# proxy)
# # proxy value must include protocoll
# $udc_uci set $g_cfgfile.$uc_name.$uc_var="http://$uc_val"
# $udc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_url_proxy"
# ;;
# use_ipv6)
# $udc_uci set $g_cfgfile.$uc_name.$uc_var="$(( 4 + ( 2 * $uc_val ) ))"
# $udc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_ipversion"
# TODO update_url)
# TODO update_script)
# other renames
# TODO lookup_host) -> rip_host
# enabled) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_enabled";;
# force_dnstcp) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="rip_host_dnstcp";;
# is_glue) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="rip_host_isglue";;
# ip_interface) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="lip_iface";;
# ip_network) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="lip_net";;
# use_https) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_url_secure";;
# cacert) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_url_cacert";;
# username) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_username";;
# password) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_password";;
# param_opt) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_paramopt";;
# param_enc) $udc_uci rename $g_cfgfile.$uc_name.$uc_var="upd_paramenc";;
# leave all other options currently unchanged
*) ;;
esac
return 0
}
return 0
# ignore unknown
else
return 0
fi
}
# read config file
uc_data=$($uc_uci -S -n export "$g_cfgfile")
uc_ret="$?"
# Error then create config file
[ $uc_ret -ne 0 ] && {
touch /etc/config/$uc_cfgfile
chmod 644 /etc/config/$uc_cfgfile
}
# No error and uc_data then execute (eval)
# this will call functions defined above
[ $uc_ret -eq 0 -a -n "$uc_data" ] && eval "$uc_data"
# add config ddns "global" (ignore error if exists)
$uc_uci set ddns.global="$g_cfgfile"
# write changes to config file
$uc_uci commit "$g_cfgfile"
unset uc_uci uc_cfg uc_name uc_var uc_val uc_ret uc_data
return 0
}
# clear LuCI indexcache
rm -f /tmp/luci-indexcache >/dev/null 2>&1
# do config update
update_config
#cleanup
[ $g_pslerr -ne 0 ] && {
unset g_pslfile g_pslerr g_cfgfile
return 1
}
[ -f "$g_pslfile" ] && rm -f "$g_pslfile"
unset g_pslfile g_pslerr g_cfgfile
return 0

View File

@ -1,14 +1,11 @@
#!/bin/sh
# there are other ACTIONs like ifupdate we don't need
# so parse dynamic_dns_functions.sh only when needed
case "$ACTION" in
ifup)
. /usr/lib/ddns/dynamic_dns_functions.sh
/etc/init.d/ddns enabled && start_daemon_for_all_ddns_sections "$INTERFACE"
ifup) # OpenWrt is giving a network not phys. Interface
/etc/init.d/ddns enabled && /usr/lib/ddns/dynamic_dns_updater.sh -n "$INTERFACE" -- start
;;
ifdown)
. /usr/lib/ddns/dynamic_dns_functions.sh
stop_daemon_for_all_ddns_sections "$INTERFACE"
/usr/lib/ddns/dynamic_dns_updater.sh -n "$INTERFACE" -- stop
;;
esac

View File

@ -7,22 +7,21 @@ boot() {
}
reload() {
killall -1 dynamic_dns_updater.sh 2>/dev/null # send SIGHUP
/usr/lib/ddns/dynamic_dns_updater.sh -- reload
return 0
}
restart() {
stop
/usr/lib/ddns/dynamic_dns_updater.sh -- stop
sleep 1 # give time to shutdown
start
/usr/lib/ddns/dynamic_dns_updater.sh -- start
}
start() {
. /usr/lib/ddns/dynamic_dns_functions.sh
start_daemon_for_all_ddns_sections
/usr/lib/ddns/dynamic_dns_updater.sh -- start
}
stop() {
killall dynamic_dns_updater.sh 2>/dev/null
return 0 # if killall fails, ignore
/usr/lib/ddns/dynamic_dns_updater.sh -- stop
return 0
}

View File

@ -1,20 +1,12 @@
#!/bin/sh
# /usr/lib/ddns/dynamic_dns_functions.sh
#
# Original written by Eric Paul Bishop, January 2008
#.Distributed under the terms of the GNU General Public License (GPL) version 2.0
# Original written by Eric Paul Bishop, January 2008
# (Loosely) based on the script on the one posted by exobyte in the forums here:
# http://forum.openwrt.org/viewtopic.php?id=14040
#
# extended and partial rewritten in August 2014 by
#.Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
# to support:
# - IPv6 DDNS services
# - 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 (useful for cron jobs etc.)
# - the usage of BIND's host instead of BusyBox's nslookup if installed (DNS via TCP)
# - extended Verbose Mode and log file support for better error detection
# extended and partial rewritten
#.2014-2017 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
#
# function timeout
# copied from http://www.ict.griffith.edu.au/anthony/software/timeout.sh
@ -29,15 +21,17 @@
. /lib/functions/network.sh
# GLOBAL VARIABLES #
VERSION="2.7.6"
SECTION_ID="" # hold config's section name
VERBOSE_MODE=1 # default mode is log to console, but easily changed with parameter
VERBOSE=0 # default mode is log to console, but easily changed with parameter
MYPROG=$(basename $0) # my program call name
LOGFILE="" # logfile - all files are set in dynamic_dns_updater.sh
PIDFILE="" # pid file
UPDFILE="" # store UPTIME of last update
DATFILE="" # save stdout data of WGet and other external programs called
ERRFILE="" # save stderr output of WGet and other external programs called
TLDFILE=/usr/lib/ddns/tld_names.dat.gz # TLD file used by split_FQDN
TLDFILE=/usr/share/public_suffix_list.dat.gz # TLD file used by split_FQDN
CHECK_SECONDS=0 # calculated seconds out of given
FORCE_SECONDS=0 # interval and unit
@ -53,44 +47,70 @@ LOCAL_IP="" # holds the local IP read from the box
URL_USER="" # url encoded $username from config file
URL_PASS="" # url encoded $password from config file
URL_PENC="" # url encoded $param_enc from config file
UPD_ANSWER="" # Answer given by service on success
ERR_LAST=0 # used to save $? return code of program and function calls
ERR_UPDATE=0 # error counter on different local and registered ip
PID_SLEEP=0 # ProcessID of current background "sleep"
# allow NON-public IP's
ALLOW_LOCAL_IP=$(uci -q get ddns.global.allow_local_ip) || ALLOW_LOCAL_IP=0
# directory to store run information to.
RUNDIR=$(uci -q get ddns.global.run_dir) || RUNDIR="/var/run/ddns"
[ -d $RUNDIR ] || mkdir -p -m755 $RUNDIR
# directory to store log files
LOGDIR=$(uci -q get ddns.global.log_dir) || LOGDIR="/var/log/ddns"
[ -d $LOGDIR ] || mkdir -p -m755 $LOGDIR
# number of lines to before rotate logfile
LOGLINES=$(uci -q get ddns.global.log_lines) || LOGLINES=250
LOGLINES=$((LOGLINES + 1)) # correct sed handling
# 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,\}\)"
# detect if called by dynamic_dns_lucihelper.sh script, disable retrys (empty variable == false)
[ "$(basename $0)" = "dynamic_dns_lucihelper.sh" ] && LUCI_HELPER="TRUE" || LUCI_HELPER=""
# detect if called by ddns-lucihelper.sh script, disable retrys (empty variable == false)
LUCI_HELPER=$(printf %s "$MYPROG" | grep -i "luci")
# Name Server Lookup Programs
BIND_HOST=$(which host)
KNOT_HOST=$(which khost)
DRILL=$(which drill)
HOSTIP=$(which hostip)
NSLOOKUP=$(which nslookup)
NSLOOKUP_MUSL=$($(which nslookup) localhost 2>&1 | grep -F "(null)") # not empty busybox compiled with musl
# Transfer Programs
WGET=$(which wget)
WGET_SSL=$(which wget-ssl)
CURL=$(which curl)
# CURL_SSL not empty then SSL support available
CURL_SSL=$($(which curl) -V 2>/dev/null | grep "Protocols:" | grep -F "https")
# CURL_PROXY not empty then Proxy support available
CURL_PROXY=$(find /lib /usr/lib -name libcurl.so* -exec grep -i "all_proxy" {} 2>/dev/null \;)
UCLIENT_FETCH=$(which uclient-fetch)
# UCLIENT_FETCH_SSL not empty then SSL support available
UCLIENT_FETCH_SSL=$(find /lib /usr/lib -name libustream-ssl.so* 2>/dev/null)
# Global configuration settings
# allow NON-public IP's
upd_privateip=$(uci -q get ddns.global.upd_privateip) || upd_privateip=0
# directory to store run information to.
ddns_rundir=$(uci -q get ddns.global.ddns_rundir) || ddns_rundir="/var/run/ddns"
[ -d $ddns_rundir ] || mkdir -p -m755 $ddns_rundir
# directory to store log files
ddns_logdir=$(uci -q get ddns.global.ddns_logdir) || ddns_logdir="/var/log/ddns"
[ -d $ddns_logdir ] || mkdir -p -m755 $ddns_logdir
# number of lines to before rotate logfile
ddns_loglines=$(uci -q get ddns.global.ddns_loglines) || ddns_loglines=250
ddns_loglines=$((ddns_loglines + 1)) # correct sed handling
# format to show date information in log and luci-app-ddns default ISO 8601 format
ddns_dateformat=$(uci -q get ddns.global.ddns_dateformat) || ddns_dateformat="%F %R"
DATE_PROG="date +'$ddns_dateformat'"
# USE_CURL if GNU Wget and cURL installed normally Wget is used by do_transfer()
# to change this use global option use_curl '1'
USE_CURL=$(uci -q get ddns.global.use_curl) || USE_CURL=0 # read config
[ -x /usr/bin/curl ] || USE_CURL=0 # check for cURL
[ -n "$CURL" ] || USE_CURL=0 # check for cURL
# loads all options for a given package and section
# also, sets all_option_variables to a list of the variable names
@ -148,7 +168,7 @@ load_all_service_sections() {
# starts updater script for all given sections or only for the one given
# $1 = interface (Optional: when given only scripts are started
# configured for that interface)
# used by /etc/hotplug.d/iface/25-ddns on IFUP
# used by /etc/hotplug.d/iface/95-ddns on IFUP
# and by /etc/init.d/ddns start
start_daemon_for_all_ddns_sections()
{
@ -161,7 +181,11 @@ start_daemon_for_all_ddns_sections()
for __SECTIONID in $__SECTIONS; do
config_get __IFACE "$__SECTIONID" interface "wan"
[ -z "$__EVENTIF" -o "$__IFACE" = "$__EVENTIF" ] || continue
/usr/lib/ddns/dynamic_dns_updater.sh $__SECTIONID 0 >/dev/null 2>&1 &
if [ $VERBOSE -eq 0 ]; then # start in background
/usr/lib/ddns/dynamic_dns_updater.sh -v 0 -S "$__SECTIONID" -- start &
else
/usr/lib/ddns/dynamic_dns_updater.sh -v "$VERBOSE" -S "$__SECTIONID" -- start
fi
done
}
@ -169,7 +193,7 @@ start_daemon_for_all_ddns_sections()
# $1 = section
stop_section_processes() {
local __PID=0
local __PIDFILE="$RUNDIR/$1.pid"
local __PIDFILE="$ddns_rundir/$1.pid"
[ $# -ne 1 ] && write_log 12 "Error calling 'stop_section_processes()' - wrong number of parameters"
[ -e "$__PIDFILE" ] && {
@ -181,7 +205,7 @@ stop_section_processes() {
# stop updater script for all defines sections or only for one given
# $1 = interface (optional)
# used by /etc/hotplug.d/iface/25-ddns on 'ifdown'
# used by /etc/hotplug.d/iface/95-ddns on 'ifdown'
# and by /etc/init.d/ddns stop
# needed because we also need to kill "sleep" child processes
stop_daemon_for_all_ddns_sections() {
@ -234,14 +258,14 @@ write_log() {
esac
# verbose echo
[ $VERBOSE_MODE -gt 0 -o $__EXIT -gt 0 ] && echo -e "$__MSG"
[ $VERBOSE -gt 0 -o $__EXIT -gt 0 ] && echo -e "$__MSG"
# write to logfile
if [ ${use_logfile:-1} -eq 1 -o $VERBOSE_MODE -gt 1 ]; then
if [ ${use_logfile:-1} -eq 1 -o $VERBOSE -gt 1 ]; then
echo -e "$__MSG" >> $LOGFILE
# VERBOSE_MODE > 1 then NO loop so NO truncate log to $LOGLINES lines
[ $VERBOSE_MODE -gt 1 ] || sed -i -e :a -e '$q;N;'$LOGLINES',$D;ba' $LOGFILE
# VERBOSE > 1 then NO loop so NO truncate log to $ddns_loglines lines
[ $VERBOSE -gt 1 ] || sed -i -e :a -e '$q;N;'$ddns_loglines',$D;ba' $LOGFILE
fi
[ $LUCI_HELPER ] && return # nothing else todo when running LuCI helper script
[ -n "$LUCI_HELPER" ] && return # nothing else todo when running LuCI helper script
[ $__LEVEL -eq 7 ] && return # no syslog for debug messages
__CMD=$(echo -e "$__CMD" | tr -d '\n' | tr '\t' ' ') # remove \n \t chars
[ $__EXIT -eq 1 ] && {
@ -250,6 +274,7 @@ write_log() {
}
[ $use_syslog -eq 0 ] && return
[ $((use_syslog + __LEVEL)) -le 7 ] && $__CMD
return
}
@ -295,44 +320,42 @@ urlencode() {
}
# extract url or script for given DDNS Provider from
# file /usr/lib/ddns/services for IPv4 or from
# file /usr/lib/ddns/services_ipv6 for IPv6
# file /etc/ddns/services for IPv4 or from
# file /etc/ddns/services_ipv6 for IPv6
# $1 Name of Variable to store url to
# $2 Name of Variable to store script to
# $3 Name of Variable to store service answer to
get_service_data() {
local __LINE __FILE __NAME __URL __SERVICES __DATA
local __SCRIPT=""
local __OLD_IFS=$IFS
local __NEWLINE_IFS='
' # __NEWLINE_IFS
[ $# -ne 2 ] && write_log 12 "Error calling 'get_service_data()' - wrong number of parameters"
[ $# -ne 3 ] && write_log 12 "Error calling 'get_service_data()' - wrong number of parameters"
__FILE="/usr/lib/ddns/services" # IPv4
[ $use_ipv6 -ne 0 ] && __FILE="/usr/lib/ddns/services_ipv6" # IPv6
__FILE="/etc/ddns/services" # IPv4
[ $use_ipv6 -ne 0 ] && __FILE="/etc/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 }')
# workaround with variables; pipe create subshell with no give back of variable content
mkfifo pipe_$$
# only grep without # or whitespace at linestart | remove "
# grep -v -E "(^#|^[[:space:]]*$)" $__FILE | sed -e s/\"//g > pipe_$$ &
sed '/^#/d; /^[ \t]*$/d; s/\"//g' $__FILE > pipe_$$ &
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)
__DATA=$(echo $__LINE | grep -o "\"[^\"]*\"[\t ]*$" | xargs -r -n1 echo)
while read __SERVICE __DATA __ANSWER; do
if [ "$__SERVICE" = "$service_name" ]; then
# check if URL or SCRIPT is given
__URL=$(echo "$__DATA" | grep "^http")
[ -z "$__URL" ] && __SCRIPT="/usr/lib/ddns/$__DATA"
if [ "$__NAME" = "$service_name" ]; then
break # found so leave for loop
eval "$1=\"$__URL\""
eval "$2=\"$__SCRIPT\""
eval "$3=\"$__ANSWER\""
rm pipe_$$
return 0
fi
done
IFS=$__OLD_IFS
done < pipe_$$
rm pipe_$$
# check if URL or SCRIPT is given
__URL=$(echo "$__DATA" | grep "^http")
[ -z "$__URL" ] && __SCRIPT="/usr/lib/ddns/$__DATA"
eval "$1=\"$__URL\""
eval "$2=\"$__SCRIPT\""
return 0
eval "$1=\"\"" # no service match clear variables
eval "$2=\"\""
eval "$3=\"\""
return 1
}
# Calculate seconds from interval and unit
@ -451,6 +474,8 @@ timeout() {
verify_host_port() {
local __HOST=$1
local __PORT=$2
local __NC=$(which nc)
local __NCEXT=$($(which nc) --help 2>&1 | grep "\-w" 2>/dev/null) # busybox nc compiled with extensions
local __IP __IPV4 __IPV6 __RUNPROG __PROG __ERR
# return codes
# 1 system specific error
@ -465,12 +490,23 @@ verify_host_port() {
__IPV6=$(echo $__HOST | grep -m 1 -o "$IPV6_REGEX")
# if FQDN given get IP address
[ -z "$__IPV4" -a -z "$__IPV6" ] && {
if [ -x /usr/bin/host ]; then # use BIND host if installed
if [ -n "$BIND_HOST" ]; then # use BIND host if installed
__PROG="BIND host"
__RUNPROG="/usr/bin/host -t ANY $__HOST >$DATFILE 2>$ERRFILE"
__RUNPROG="$BIND_HOST $__HOST >$DATFILE 2>$ERRFILE"
elif [ -n "$KNOT_HOST" ]; then # use Knot host if installed
__PROG="Knot host"
__RUNPROG="$KNOT_HOST $__HOST >$DATFILE 2>$ERRFILE"
elif [ -n "$DRILL" ]; then # use drill if installed
__PROG="drill"
__RUNPROG="$DRILL -V0 $__HOST A >$DATFILE 2>$ERRFILE" # IPv4
__RUNPROG="$__RUNPROG; $DRILL -V0 $__HOST AAAA >>$DATFILE 2>>$ERRFILE" # IPv6
elif [ -n "$HOSTIP" ]; then # use hostip if installed
__PROG="hostip"
__RUNPROG="$HOSTIP $__HOST >$DATFILE 2>$ERRFILE" # IPv4
__RUNPROG="$__RUNPROG; $HOSTIP -6 $__HOST >>$DATFILE 2>>$ERRFILE" # IPv6
else # use BusyBox nslookup
__PROG="BusyBox nslookup"
__RUNPROG="/usr/bin/nslookup $__HOST >$DATFILE 2>$ERRFILE"
__RUNPROG="$NSLOOKUP $__HOST >$DATFILE 2>$ERRFILE"
fi
write_log 7 "#> $__RUNPROG"
eval $__RUNPROG
@ -482,9 +518,15 @@ verify_host_port() {
return 2
}
# extract IP address
if [ -x /usr/bin/host ]; then # use BIND host if installed
if [ -n "$BIND_HOST" -o -n "$KNOT_HOST" ]; then # use BIND host or Knot host if installed
__IPV4=$(cat $DATFILE | awk -F "address " '/has address/ {print $2; exit}' )
__IPV6=$(cat $DATFILE | awk -F "address " '/has IPv6/ {print $2; exit}' )
elif [ -n "$DRILL" ]; then # use drill if installed
__IPV4=$(cat $DATFILE | awk '/^'"$lookup_host"'/ {print $5}' | grep -m 1 -o "$IPV4_REGEX")
__IPV6=$(cat $DATFILE | awk '/^'"$lookup_host"'/ {print $5}' | grep -m 1 -o "$IPV6_REGEX")
elif [ -n "$HOSTIP" ]; then # use hostip if installed
__IPV4=$(cat $DATFILE | grep -m 1 -o "$IPV4_REGEX")
__IPV6=$(cat $DATFILE | grep -m 1 -o "$IPV6_REGEX")
else # use BusyBox nslookup
__IPV4=$(cat $DATFILE | sed -ne "/^Name:/,\$ { s/^Address[0-9 ]\{0,\}: \($IPV4_REGEX\).*$/\\1/p }")
__IPV6=$(cat $DATFILE | sed -ne "/^Name:/,\$ { s/^Address[0-9 ]\{0,\}: \($IPV6_REGEX\).*$/\\1/p }")
@ -497,17 +539,17 @@ verify_host_port() {
[ $use_ipv6 -eq 0 -a -z "$__IPV4" ] && __ERR=4
[ $use_ipv6 -eq 1 -a -z "$__IPV6" ] && __ERR=6
[ $__ERR -gt 0 ] && {
[ $LUCI_HELPER ] && return 4
[ -n "$LUCI_HELPER" ] && return 4
write_log 14 "Verify host Error '4' - Forced IP Version IPv$__ERR don't match"
}
fi
# verify nc command
# busybox nc compiled without -l option "NO OPT l!" -> critical error
/usr/bin/nc --help 2>&1 | grep -i "NO OPT l!" >/dev/null 2>&1 && \
$__NC --help 2>&1 | grep -i "NO OPT l!" >/dev/null 2>&1 && \
write_log 12 "Busybox nc (netcat) compiled without '-l' option, error 'NO OPT l!'"
# busybox nc compiled with extensions
/usr/bin/nc --help 2>&1 | grep "\-w" >/dev/null 2>&1 && __NCEXT="TRUE"
$__NC --help 2>&1 | grep "\-w" >/dev/null 2>&1 && __NCEXT="TRUE"
# connectivity test
# run busybox nc to HOST PORT
@ -518,7 +560,7 @@ verify_host_port() {
[ $force_ipversion -ne 0 -a $use_ipv6 -ne 0 -o -z "$__IPV4" ] && __IP=$__IPV6 || __IP=$__IPV4
if [ -n "$__NCEXT" ]; then # BusyBox nc compiled with extensions (timeout support)
__RUNPROG="/usr/bin/nc -w 1 $__IP $__PORT </dev/null >$DATFILE 2>$ERRFILE"
__RUNPROG="$__NC -w 1 $__IP $__PORT </dev/null >$DATFILE 2>$ERRFILE"
write_log 7 "#> $__RUNPROG"
eval $__RUNPROG
__ERR=$?
@ -527,7 +569,7 @@ verify_host_port() {
write_log 7 "$(cat $ERRFILE)"
return 3
else # nc compiled without extensions (no timeout support)
__RUNPROG="timeout 2 -- /usr/bin/nc $__IP $__PORT </dev/null >$DATFILE 2>$ERRFILE"
__RUNPROG="timeout 2 -- $__NC $__IP $__PORT </dev/null >$DATFILE 2>$ERRFILE"
write_log 7 "#> $__RUNPROG"
eval $__RUNPROG
__ERR=$?
@ -550,10 +592,10 @@ verify_dns() {
# DNS uses port 53
verify_host_port "$1" "53"
__ERR=$?
if [ $LUCI_HELPER ]; then # no retry if called by LuCI helper script
if [ -n "$LUCI_HELPER" ]; then # no retry if called by LuCI helper script
return $__ERR
elif [ $__ERR -ne 0 -a $VERBOSE_MODE -gt 1 ]; then # VERBOSE_MODE > 1 then NO retry
write_log 4 "Verify DNS server '$1' failed - Verbose Mode: $VERBOSE_MODE - NO retry on error"
elif [ $__ERR -ne 0 -a $VERBOSE -gt 1 ]; then # VERBOSE > 1 then NO retry
write_log 4 "Verify DNS server '$1' failed - Verbose Mode: $VERBOSE - NO retry on error"
return $__ERR
elif [ $__ERR -ne 0 ]; then
__CNT=$(( $__CNT + 1 )) # increment error counter
@ -603,17 +645,17 @@ verify_proxy() {
fi
# No Port detected - EXITING
[ -z "$__PORT" ] && {
[ $LUCI_HELPER ] && return 5
[ -n "$LUCI_HELPER" ] && return 5
write_log 14 "Invalid Proxy server Error '5' - proxy port missing"
}
while [ $__ERR -gt 0 ]; do
verify_host_port "$__HOST" "$__PORT"
__ERR=$?
if [ $LUCI_HELPER ]; then # no retry if called by LuCI helper script
if [ -n "$LUCI_HELPER" ]; then # no retry if called by LuCI helper script
return $__ERR
elif [ $__ERR -gt 0 -a $VERBOSE_MODE -gt 1 ]; then # VERBOSE_MODE > 1 then NO retry
write_log 4 "Verify Proxy server '$1' failed - Verbose Mode: $VERBOSE_MODE - NO retry on error"
elif [ $__ERR -gt 0 -a $VERBOSE -gt 1 ]; then # VERBOSE > 1 then NO retry
write_log 4 "Verify Proxy server '$1' failed - Verbose Mode: $VERBOSE - NO retry on error"
return $__ERR
elif [ $__ERR -gt 0 ]; then
__CNT=$(( $__CNT + 1 )) # increment error counter
@ -641,9 +683,8 @@ do_transfer() {
[ $# -ne 1 ] && write_log 12 "Error in 'do_transfer()' - wrong number of parameters"
# lets prefer GNU Wget because it does all for us - IPv4/IPv6/HTTPS/PROXY/force IP version
grep -i "\+ssl" /usr/bin/wget >/dev/null 2>&1 # check for Wget with SSL support
if [ $? -eq 0 -a $USE_CURL -eq 0 ]; then # except global option use_curl is set to "1"
__PROG="/usr/bin/wget -nv -t 1 -O $DATFILE -o $ERRFILE" # non_verbose no_retry outfile errfile
if [ -n "$WGET_SSL" -a $USE_CURL -eq 0 ]; then # except global option use_curl is set to "1"
__PROG="$WGET_SSL -nv -t 1 -O $DATFILE -o $ERRFILE" # non_verbose no_retry outfile errfile
# force network/ip to use for communication
if [ -n "$bind_network" ]; then
local __BINDIP
@ -666,7 +707,7 @@ do_transfer() {
__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
elif [ -n "$cacert" ]; then # it's not a file and not a directory but given
write_log 14 "No valid certificate(s) found at '$cacert' for HTTPS communication"
fi
fi
@ -677,9 +718,12 @@ do_transfer() {
__PROG="GNU Wget" # reuse for error logging
# 2nd choice is cURL IPv4/IPv6/HTTPS
# libcurl might be compiled without Proxy Support (default in trunk)
elif [ -x /usr/bin/curl ]; then
__PROG="/usr/bin/curl -RsS -o $DATFILE --stderr $ERRFILE"
# libcurl might be compiled without Proxy or HTTPS Support
elif [ -n "$CURL" ]; then
__PROG="$CURL -RsS -o $DATFILE --stderr $ERRFILE"
# check HTTPS support
[ -z "$CURL_SSL" -a $use_https -eq 1 ] && \
write_log 13 "cURL: libcurl compiled without https support"
# force network/interface-device to use for communication
if [ -n "$bind_network" ]; then
local __DEVICE
@ -700,7 +744,7 @@ do_transfer() {
__PROG="$__PROG --cacert $cacert"
elif [ -d "$cacert" ]; then
__PROG="$__PROG --capath $cacert"
else # exit here because it makes no sense to start loop
elif [ -n "$cacert" ]; then # it's not a file and not a directory but given
write_log 14 "No valid certificate(s) found at '$cacert' for HTTPS communication"
fi
fi
@ -708,19 +752,45 @@ do_transfer() {
# or check if libcurl compiled with proxy support
if [ -z "$proxy" ]; then
__PROG="$__PROG --noproxy '*'"
else
elif [ -z "$CURL_PROXY" ]; then
# if libcurl has no proxy support and proxy should be used then force ERROR
# libcurl currently no proxy support by default
grep -i "all_proxy" /usr/lib/libcurl.so* >/dev/null 2>&1 || \
write_log 13 "cURL: libcurl compiled without Proxy support"
write_log 13 "cURL: libcurl compiled without Proxy support"
fi
__RUNPROG="$__PROG '$__URL'" # build final command
__PROG="cURL" # reuse for error logging
# busybox Wget (did not support neither IPv6 nor HTTPS)
elif [ -x /usr/bin/wget ]; then
__PROG="/usr/bin/wget -q -O $DATFILE"
# uclient-fetch possibly with ssl support if /lib/libustream-ssl.so installed
elif [ -n "$UCLIENT_FETCH" ]; then
__PROG="$UCLIENT_FETCH -q -O $DATFILE"
# force network/ip not supported
[ -n "$__BINDIP" ] && \
write_log 14 "uclient-fetch: FORCE binding to specific address not supported"
# 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
# https possibly not supported
[ $use_https -eq 1 -a -z "$UCLIENT_FETCH_SSL" ] && \
write_log 14 "uclient-fetch: no HTTPS support! Additional install one of ustream-ssl packages"
# proxy support
[ -z "$proxy" ] && __PROG="$__PROG -Y off" || __PROG="$__PROG -Y on"
# https & certificates
if [ $use_https -eq 1 ]; then
if [ "$cacert" = "IGNORE" ]; then
__PROG="$__PROG --no-check-certificate"
elif [ -f "$cacert" ]; then
__PROG="$__PROG --ca-certificate=$cacert"
elif [ -n "$cacert" ]; then # it's not a file; nothing else supported
write_log 14 "No valid certificate file '$cacert' for HTTPS communication"
fi
fi
__RUNPROG="$__PROG '$__URL' 2>$ERRFILE" # build final command
__PROG="uclient-fetch" # reuse for error logging
# Busybox Wget or any other wget in search $PATH (did not support neither IPv6 nor HTTPS)
elif [ -n "$WGET" ]; then
__PROG="$WGET -q -O $DATFILE"
# force network/ip not supported
[ -n "$__BINDIP" ] && \
write_log 14 "BusyBox Wget: FORCE binding to specific address not supported"
@ -737,7 +807,7 @@ do_transfer() {
__PROG="Busybox Wget" # reuse for error logging
else
write_log 13 "Neither 'Wget' nor 'cURL' installed or executable"
write_log 13 "Neither 'Wget' nor 'cURL' nor 'uclient-fetch' installed or executable"
fi
while : ; do
@ -745,14 +815,14 @@ do_transfer() {
eval $__RUNPROG # DO transfer
__ERR=$? # save error code
[ $__ERR -eq 0 ] && return 0 # no error leave
[ $LUCI_HELPER ] && return 1 # no retry if called by LuCI helper script
[ -n "$LUCI_HELPER" ] && return 1 # no retry if called by LuCI helper script
write_log 3 "$__PROG Error: '$__ERR'"
write_log 7 "$(cat $ERRFILE)" # report error
[ $VERBOSE_MODE -gt 1 ] && {
# VERBOSE_MODE > 1 then NO retry
write_log 4 "Transfer failed - Verbose Mode: $VERBOSE_MODE - NO retry on error"
[ $VERBOSE -gt 1 ] && {
# VERBOSE > 1 then NO retry
write_log 4 "Transfer failed - Verbose Mode: $VERBOSE - NO retry on error"
return 1
}
@ -777,14 +847,18 @@ send_update() {
[ $# -ne 1 ] && write_log 12 "Error calling 'send_update()' - wrong number of parameters"
if [ $ALLOW_LOCAL_IP -eq 0 ]; then
if [ $upd_privateip -eq 0 ]; then
# verify given IP / no private IPv4's / no IPv6 addr starting with fxxx of with ":"
[ $use_ipv6 -eq 0 ] && __IP=$(echo $1 | grep -v -E "(^0|^10\.|^100\.6[4-9]\.|^100\.[7-9][0-9]\.|^100\.1[0-1][0-9]\.|^100\.12[0-7]\.|^127|^169\.254|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-1]\.|^192\.168)")
[ $use_ipv6 -eq 1 ] && __IP=$(echo $1 | grep "^[0-9a-eA-E]")
[ -z "$__IP" ] && write_log 14 "Private or invalid or no IP '$1' given! Please check your configuration"
else
__IP="$1"
__IP=$(echo $1 | grep -m 1 -o "$IPV4_REGEX") # valid IPv4 or
[ -z "$__IP" ] && __IP=$(echo $1 | grep -m 1 -o "$IPV6_REGEX") # IPv6
fi
[ -z "$__IP" ] && {
write_log 3 "No or private or invalid IP '$1' given! Please check your configuration"
return 127
}
if [ -n "$update_script" ]; then
write_log 7 "parsing script '$update_script'"
@ -793,19 +867,19 @@ send_update() {
local __URL __ERR
# do replaces in URL
__URL=$(echo $update_url | sed -e "s#\[USERNAME\]#$URL_USER#g" -e "s#\[PASSWORD\]#$URL_PASS#g" \
-e "s#\[DOMAIN\]#$domain#g" -e "s#\[IP\]#$__IP#g")
__URL=$(echo $update_url | sed -e "s#\[USERNAME\]#$URL_USER#g" -e "s#\[PASSWORD\]#$URL_PASS#g" \
-e "s#\[PARAMENC\]#$URL_PENC#g" -e "s#\[PARAMOPT\]#$param_opt#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 "$__URL" || return 1
write_log 7 "DDNS Provider answered:\n$(cat $DATFILE)"
return 0
# TODO analyze providers answer
# "good" or "nochg" = dyndns.com compatible API
# grep -i -E "good|nochg" $DATFILE >/dev/null 2>&1
# return $? # "0" if found
[ -z "$UPD_ANSWER" ] && return 0 # not set then ignore
grep -i -E "$UPD_ANSWER" $DATFILE >/dev/null 2>&1
return $? # "0" if found
fi
}
@ -818,91 +892,123 @@ get_local_ip () {
write_log 7 "Detect local IP on '$ip_source'"
while : ; do
case $ip_source in
network)
# set correct program
[ $use_ipv6 -eq 0 ] && __RUNPROG="network_get_ipaddr" \
|| __RUNPROG="network_get_ipaddr6"
eval "$__RUNPROG __DATA $ip_network" || \
write_log 13 "Can not detect local IP using $__RUNPROG '$ip_network' - Error: '$?'"
[ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected on network '$ip_network'"
;;
interface)
if [ -n "$ip_network" ]; then
# set correct program
[ $use_ipv6 -eq 0 ] && __RUNPROG="network_get_ipaddr" \
|| __RUNPROG="network_get_ipaddr6"
eval "$__RUNPROG __DATA $ip_network" || \
write_log 13 "Can not detect local IP using $__RUNPROG '$ip_network' - Error: '$?'"
[ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected on network '$ip_network'"
elif [ -n "$ip_interface" ]; then
local __DATA4=""; local __DATA6=""
if [ -n "$(which ip)" ]; then # ip program installed
write_log 7 "#> ip -o addr show dev $ip_interface scope global >$DATFILE 2>$ERRFILE"
ip -o addr show dev $ip_interface scope global >$DATFILE 2>$ERRFILE
__ERR=$?
if [ $__ERR -eq 0 ]; then
# DATFILE (sample)
# 5: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP qlen 1000\ link/ether 08:00:27:d0:10:32 brd ff:ff:ff:ff:ff:ff
# 5: eth1 inet 172.27.10.128/24 brd 172.27.10.255 scope global eth1\ valid_lft forever preferred_lft forever
# 5: eth1 inet 172.55.55.155/24 brd 172.27.10.255 scope global eth1\ valid_lft 12345sec preferred_lft 12345sec
# 5: eth1 inet6 2002:b0c7:f326::806b:c629:b8b9:433/128 scope global dynamic \ valid_lft 8026sec preferred_lft 8026sec
# 5: eth1 inet6 fd43:5368:6f6d:6500:806b:c629:b8b9:433/128 scope global dynamic \ valid_lft 8026sec preferred_lft 8026sec
# 5: eth1 inet6 fd43:5368:6f6d:6500:a00:27ff:fed0:1032/64 scope global dynamic \ valid_lft 14352sec preferred_lft 14352sec
# 5: eth1 inet6 2002:b0c7:f326::a00:27ff:fed0:1032/64 scope global dynamic \ valid_lft 14352sec preferred_lft 14352sec
# remove remove remove replace remove remove
# BROADCAST inet6 fxxx sec forever=>-1 between / and pref.. linestart to inet
sed -i "/BROADCAST/d; /inet6 f/d; s/sec//g; s/forever/-1/g; s/\/.*preferred_lft//g; s/^.*$ip_interface *//g" $DATFILE
local __TIME4=0; local __TIME6=0
local __TYP __ADR __TIME
while read __TYP __ADR __TIME; do
__TIME=${__TIME:-0} # supress shell errors on last (empty) line of DATFILE
# IPversion no "-1" record stored - now "-1" record or new time > oldtime
[ "$__TYP" = "inet6" -a $__TIME6 -ge 0 -a \( $__TIME -lt 0 -o $__TIME -gt $__TIME6 \) ] && {
__DATA6="$__ADR"
__TIME6="$__TIME"
}
[ "$__TYP" = "inet" -a $__TIME4 -ge 0 -a \( $__TIME -lt 0 -o $__TIME -gt $__TIME4 \) ] && {
__DATA4="$__ADR"
__TIME4="$__TIME"
}
done < $DATFILE
else
write_log 3 "ip Error: '$__ERR'"
write_log 7 "$(cat $ERRFILE)" # report error
fi
else # use deprecated ifconfig
write_log 7 "#> ifconfig $ip_interface >$DATFILE 2>$ERRFILE"
ifconfig $ip_interface >$DATFILE 2>$ERRFILE
__ERR=$?
if [ $__ERR -eq 0 ]; then
if [ $use_ipv6 -eq 0 ]; then
__DATA=$(awk '
/inet addr:/ { # Filter IPv4
# inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255.0
$1=""; # remove inet
$3=""; # remove Bcast: ...
$4=""; # remove Mask: ...
FS=":"; # separator ":"
$0=$0; # reread to activate separator
$1=""; # remove addr
FS=" "; # set back separator to default " "
$0=$0; # reread to activate separator (remove whitespaces)
print $1; # print IPv4 addr
}' $DATFILE
)
else
__DATA=$(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
}' $DATFILE
)
fi
[ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected on interface '$ip_interface'"
__DATA4=$(awk '
/inet addr:/ { # Filter IPv4
# inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255.0
$1=""; # remove inet
$3=""; # remove Bcast: ...
$4=""; # remove Mask: ...
FS=":"; # separator ":"
$0=$0; # reread to activate separator
$1=""; # remove addr
FS=" "; # set back separator to default " "
$0=$0; # reread to activate separator (remove whitespaces)
print $1; # print IPv4 addr
}' $DATFILE
)
__DATA6=$(awk '
/inet6/ && /: [0-9a-eA-E]/ { # Filter IPv6 exclude fxxx
# 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
}' $DATFILE
)
else
write_log 3 "ifconfig Error: '$__ERR'"
write_log 7 "$(cat $ERRFILE)" # report error
fi
;;
script)
write_log 7 "#> $ip_script >$DATFILE 2>$ERRFILE"
eval $ip_script >$DATFILE 2>$ERRFILE
__ERR=$?
if [ $__ERR -eq 0 ]; then
__DATA=$(cat $DATFILE)
[ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected via script '$ip_script'"
else
write_log 3 "$ip_script Error: '$__ERR'"
write_log 7 "$(cat $ERRFILE)" # report error
fi
;;
web)
do_transfer "$ip_url"
# use correct regular expression
[ $use_ipv6 -eq 0 ] \
&& __DATA=$(grep -m 1 -o "$IPV4_REGEX" $DATFILE) \
|| __DATA=$(grep -m 1 -o "$IPV6_REGEX" $DATFILE)
[ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected on web at '$ip_url'"
;;
*)
write_log 12 "Error in 'get_local_ip()' - unhandled ip_source '$ip_source'"
;;
esac
fi
[ $use_ipv6 -eq 0 ] && __DATA="$__DATA4" || __DATA="$__DATA6"
[ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected on interface '$ip_interface'"
elif [ -n "$ip_script" ]; then
write_log 7 "#> $ip_script >$DATFILE 2>$ERRFILE"
eval $ip_script >$DATFILE 2>$ERRFILE
__ERR=$?
if [ $__ERR -eq 0 ]; then
__DATA=$(cat $DATFILE)
[ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected via script '$ip_script'"
else
write_log 3 "$ip_script Error: '$__ERR'"
write_log 7 "$(cat $ERRFILE)" # report error
fi
elif [ -n "$ip_url" ]; then
do_transfer "$ip_url"
# use correct regular expression
[ $use_ipv6 -eq 0 ] \
&& __DATA=$(grep -m 1 -o "$IPV4_REGEX" $DATFILE) \
|| __DATA=$(grep -m 1 -o "$IPV6_REGEX" $DATFILE)
[ -n "$__DATA" ] && write_log 7 "Local IP '$__DATA' detected on web at '$ip_url'"
else
write_log 12 "Error in 'get_local_ip()' - unhandled ip_source '$ip_source'"
fi
# valid data found return here
[ -n "$__DATA" ] && {
eval "$1=\"$__DATA\""
return 0
}
[ $LUCI_HELPER ] && return 1 # no retry if called by LuCI helper script
[ -n "$LUCI_HELPER" ] && return 1 # no retry if called by LuCI helper script
write_log 7 "Data detected:\n$(cat $DATFILE)"
write_log 7 "Data detected:"
write_log 7 "$(cat $DATFILE)"
[ $VERBOSE_MODE -gt 1 ] && {
# VERBOSE_MODE > 1 then NO retry
write_log 4 "Get local IP via '$ip_source' failed - Verbose Mode: $VERBOSE_MODE - NO retry on error"
[ $VERBOSE -gt 1 ] && {
# VERBOSE > 1 then NO retry
write_log 4 "Get local IP via '$ip_source' failed - Verbose Mode: $VERBOSE - NO retry on error"
return 1
}
@ -925,31 +1031,83 @@ get_registered_ip() {
# $2 (optional) if set, do not retry on error
local __CNT=0 # error counter
local __ERR=255
local __REGEX __PROG __RUNPROG __DATA
local __REGEX __PROG __RUNPROG __DATA __IP
# return codes
# 1 no IP detected
[ $# -lt 1 -o $# -gt 2 ] && write_log 12 "Error calling 'get_registered_ip()' - wrong number of parameters"
[ $is_glue -eq 1 -a -z "$BIND_HOST" ] && write_log 14 "Lookup of glue records is only supported using BIND host"
write_log 7 "Detect registered/public IP"
# set correct regular expression
[ $use_ipv6 -eq 0 ] && __REGEX="$IPV4_REGEX" || __REGEX="$IPV6_REGEX"
if [ -x /usr/bin/host ]; then
__PROG="/usr/bin/host"
if [ -n "$BIND_HOST" ]; then
__PROG="$BIND_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
[ $is_glue -eq 1 ] && __PROG="$__PROG -v" # use verbose output to get additional section
__RUNPROG="$__PROG $lookup_host $dns_server >$DATFILE 2>$ERRFILE"
__PROG="BIND host"
elif [ -n "$KNOT_HOST" ]; then
__PROG="$KNOT_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 >$DATFILE 2>$ERRFILE"
__PROG="BIND host"
elif [ -x /usr/bin/nslookup ]; then # last use BusyBox nslookup
[ $force_ipversion -ne 0 -o $force_dnstcp -ne 0 ] && \
write_log 14 "Busybox nslookup - no support to 'force IP Version' or 'DNS over TCP'"
__RUNPROG="$__PROG $lookup_host $dns_server >$DATFILE 2>$ERRFILE"
__PROG="Knot host"
elif [ -n "$DRILL" ]; then
__PROG="$DRILL -V0" # drill options name @server type
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" || __PROG="$__PROG -u" # force TCP
__PROG="$__PROG $lookup_host"
[ -n "$dns_server" ] && __PROG="$__PROG @$dns_server"
[ $use_ipv6 -eq 0 ] && __PROG="$__PROG A" || __PROG="$__PROG AAAA"
__RUNPROG="/usr/bin/nslookup $domain $dns_server >$DATFILE 2>$ERRFILE"
__RUNPROG="$__PROG >$DATFILE 2>$ERRFILE"
__PROG="drill"
elif [ -n "$HOSTIP" ]; then # hostip package installed
__PROG="$HOSTIP"
[ $force_dnstcp -ne 0 ] && \
write_log 14 "hostip - no support for 'DNS over TCP'"
# is IP given as dns_server ?
__IP=$(echo $dns_server | grep -m 1 -o "$IPV4_REGEX")
[ -z "$__IP" ] && __IP=$(echo $dns_server | grep -m 1 -o "$IPV6_REGEX")
# we got NO ip for dns_server, so build command
[ -z "$__IP" -a -n "$dns_server" ] && {
__IP="\`$HOSTIP"
[ $use_ipv6 -eq 1 -a $force_ipversion -eq 1 ] && __IP="$__IP -6"
__IP="$__IP $dns_server | grep -m 1 -o"
[ $use_ipv6 -eq 1 -a $force_ipversion -eq 1 ] \
&& __IP="$__IP '$IPV6_REGEX'" \
|| __IP="$__IP '$IPV4_REGEX'"
__IP="$__IP \`"
}
[ $use_ipv6 -eq 1 ] && __PROG="$__PROG -6"
[ -n "$dns_server" ] && __PROG="$__PROG -r $__IP"
__RUNPROG="$__PROG $lookup_host >$DATFILE 2>$ERRFILE"
__PROG="hostip"
elif [ -n "$NSLOOKUP" ]; then # last use BusyBox nslookup
[ $force_dnstcp -ne 0 ] && \
write_log 14 "Busybox nslookup - no support for 'DNS over TCP'"
[ -n "$NSLOOKUP_MUSL" -a -n "$dns_server" ] && \
write_log 14 "Busybox compiled with musl - nslookup don't support the use of DNS Server"
[ $force_ipversion -ne 0 ] && \
write_log 5 "Busybox nslookup - no support to 'force IP Version' (ignored)"
__RUNPROG="$NSLOOKUP $lookup_host $dns_server >$DATFILE 2>$ERRFILE"
__PROG="BusyBox nslookup"
else # there must be an error
write_log 12 "Error in 'get_registered_ip()' - no supported Name Server lookup software accessible"
@ -963,9 +1121,17 @@ get_registered_ip() {
write_log 3 "$__PROG error: '$__ERR'"
write_log 7 "$(cat $ERRFILE)"
else
if [ "$__PROG" = "BIND host" ]; then
__DATA=$(cat $DATFILE | awk -F "address " '/has/ {print $2; exit}' )
else
if [ -n "$BIND_HOST" -o -n "$KNOT_HOST" ]; then
if [ $is_glue -eq 1 ]; then
__DATA=$(cat $DATFILE | grep "^$lookup_host" | grep -om1 "$__REGEX" )
else
__DATA=$(cat $DATFILE | awk -F "address " '/has/ {print $2; exit}' )
fi
elif [ -n "$DRILL" ]; then
__DATA=$(cat $DATFILE | awk '/^'"$lookup_host"'/ {print $5; exit}' )
elif [ -n "$HOSTIP" ]; then
__DATA=$(cat $DATFILE | grep -om1 "$__REGEX")
elif [ -n "$NSLOOKUP" ]; then
__DATA=$(cat $DATFILE | sed -ne "/^Name:/,\$ { s/^Address[0-9 ]\{0,\}: \($__REGEX\).*$/\\1/p }" )
fi
[ -n "$__DATA" ] && {
@ -977,20 +1143,20 @@ get_registered_ip() {
__ERR=127
fi
[ $LUCI_HELPER ] && return $__ERR # no retry if called by LuCI helper script
[ -n "$LUCI_HELPER" ] && return $__ERR # no retry if called by LuCI helper script
[ -n "$2" ] && return $__ERR # $2 is given -> no retry
[ $VERBOSE_MODE -gt 1 ] && {
# VERBOSE_MODE > 1 then NO retry
write_log 4 "Get registered/public IP for '$domain' failed - Verbose Mode: $VERBOSE_MODE - NO retry on error"
[ $VERBOSE -gt 1 ] && {
# VERBOSE > 1 then NO retry
write_log 4 "Get registered/public IP for '$lookup_host' failed - Verbose Mode: $VERBOSE - NO retry on error"
return $__ERR
}
__CNT=$(( $__CNT + 1 )) # increment error counter
# if error count > retry_count leave here
[ $retry_count -gt 0 -a $__CNT -gt $retry_count ] && \
write_log 14 "Get registered/public IP for '$domain' failed after $retry_count retries"
write_log 14 "Get registered/public IP for '$lookup_host' failed after $retry_count retries"
write_log 4 "Get registered/public IP for '$domain' failed - retry $__CNT/$retry_count in $RETRY_SECONDS seconds"
write_log 4 "Get registered/public IP for '$lookup_host' failed - retry $__CNT/$retry_count in $RETRY_SECONDS seconds"
sleep $RETRY_SECONDS &
PID_SLEEP=$!
wait $PID_SLEEP # enable trap-handler
@ -1026,7 +1192,7 @@ trap_handler() {
fi ;;
1) write_log 6 "PID '$$' received 'SIGHUP' at $(eval $DATE_PROG)"
# reload config via starting the script again
eval "/usr/lib/ddns/dynamic_dns_updater.sh $SECTION_ID $VERBOSE_MODE &"
/usr/lib/ddns/dynamic_dns_updater.sh -v "0" -S "$__SECTIONID" -- start || true
exit 0 ;; # and leave this one
2) write_log 5 "PID '$$' terminated by 'SIGINT' at $(eval $DATE_PROG)\n";;
3) write_log 5 "PID '$$' terminated by 'SIGQUIT' at $(eval $DATE_PROG)\n";;
@ -1105,7 +1271,7 @@ split_FQDN() {
# the leftover parameters are the HOST/SUBDOMAIN
while [ -n "$1" ]; do
_HOST="$1 $HOST" # remember we need to invert
_HOST="$1 $_HOST" # remember we need to invert
shift
done
_HOST=$(echo $_HOST | tr " " ".") # insert DOT
@ -1122,3 +1288,68 @@ split_FQDN() {
eval "$4=''" # clear HOST/SUBDOMAIN
return 1
}
expand_ipv6() {
# Original written for bash by
#.Author: Florian Streibelt <florian@f-streibelt.de>
# Date: 08.04.2012
# License: Public Domain, but please be fair and
# attribute the original author(s) and provide
# a link to the original source for corrections:
#. https://github.com/mutax/IPv6-Address-checks
# $1 IPv6 to expand
# $2 name of variable to store expanded IPv6
[ $# -ne 2 ] && write_log 12 "Error calling 'expand_ipv6()' - wrong number of parameters"
INPUT="$(echo "$1" | tr 'A-F' 'a-f')"
[ "$INPUT" = "::" ] && INPUT="::0" # special case ::
O=""
while [ "$O" != "$INPUT" ]; do
O="$INPUT"
# fill all words with zeroes
INPUT=$( echo "$INPUT" | sed -e 's|:\([0-9a-f]\{3\}\):|:0\1:|g' \
-e 's|:\([0-9a-f]\{3\}\)$|:0\1|g' \
-e 's|^\([0-9a-f]\{3\}\):|0\1:|g' \
-e 's|:\([0-9a-f]\{2\}\):|:00\1:|g' \
-e 's|:\([0-9a-f]\{2\}\)$|:00\1|g' \
-e 's|^\([0-9a-f]\{2\}\):|00\1:|g' \
-e 's|:\([0-9a-f]\):|:000\1:|g' \
-e 's|:\([0-9a-f]\)$|:000\1|g' \
-e 's|^\([0-9a-f]\):|000\1:|g' )
done
# now expand the ::
ZEROES=""
echo "$INPUT" | grep -qs "::"
if [ "$?" -eq 0 ]; then
GRPS="$( echo "$INPUT" | sed 's|[0-9a-f]||g' | wc -m )"
GRPS=$(( GRPS-1 )) # remove carriage return
MISSING=$(( 8-GRPS ))
while [ $MISSING -gt 0 ]; do
ZEROES="$ZEROES:0000"
MISSING=$(( MISSING-1 ))
done
# be careful where to place the :
INPUT=$( echo "$INPUT" | sed -e 's|\(.\)::\(.\)|\1'$ZEROES':\2|g' \
-e 's|\(.\)::$|\1'$ZEROES':0000|g' \
-e 's|^::\(.\)|'$ZEROES':0000:\1|g;s|^:||g' )
fi
# an expanded address has 39 chars + CR
if [ $(echo $INPUT | wc -m) != 40 ]; then
write_log 4 "Error in 'expand_ipv6()' - invalid IPv6 found: '$1' expanded: '$INPUT'"
eval "$2='invalid'"
return 1
fi
# echo the fully expanded version of the address
eval "$2=$INPUT"
return 0
}

View File

@ -1,77 +1,129 @@
#!/bin/sh
# /usr/lib/ddns/luci_dns_helper.sh
# /usr/lib/ddns/dynamic_dns_lucihelper.sh
#
#.Distributed under the terms of the GNU General Public License (GPL) version 2.0
#
# Written in August 2014 by
#.Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
#.2014-2017 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
# This script is used by luci-app-ddns
# - getting registered IP
# - check if possible to get local IP
# - verifing given DNS- or Proxy-Server
#
# variables in small chars are read from /etc/config/ddns as parameter given here
# variables in big chars are defined inside these scripts as gloval vars
# variables in big chars beginning with "__" are local defined inside functions only
# set -vx #script debugger
[ $# -lt 2 ] && exit 1
. /usr/lib/ddns/dynamic_dns_functions.sh # global vars are also defined here
# preset some variables, wrong or not set in dynamic_dns_functions.sh
usage() {
cat << EOF
Usage:
$MYPROG [options] -- command
Commands:
get_local_ip using given INTERFACE or NETWORK or SCRIPT or URL
get_registered_ip for given FQDN
verify_dns given DNS-SERVER
verify_proxy given PROXY
start start given SECTION
reload force running ddns processes to reload changed configuration
restart restart all ddns processes
Parameters:
-6 => use_ipv6=1 (default 0)
-d DNS-SERVER => dns_server=SERVER[:PORT]
-f => force_ipversion=1 (default 0)
-g => is_glue=1 (default 0)
-i INTERFACE => ip_interface=INTERFACE; ip_source="interface"
-l FQDN => lookup_host=FQDN
-n NETWORK => ip_network=NETWORK; ip_source="network"
-p PROXY => proxy=[USER:PASS@]PROXY:PORT
-s SCRIPT => ip_script=SCRIPT; ip_source="script"
-t => force_dnstcp=1 (default 0)
-u URL => ip_url=URL; ip_source="web"
-S SECTION SECTION to start
-h => show this help and exit
-L => use_logfile=1 (default 0)
-v LEVEL => VERBOSE=LEVEL (default 0)
-V => show version and exit
EOF
}
usage_err() {
printf %s\\n "$MYPROG: $@" >&2
usage >&2
exit 255
}
# preset some variables, wrong or not set in ddns-functions.sh
SECTION_ID="lucihelper"
LOGFILE="$LOGDIR/$SECTION_ID.log"
DATFILE="$RUNDIR/$SECTION_ID.$$.dat" # save stdout data of WGet and other extern programs called
ERRFILE="$RUNDIR/$SECTION_ID.$$.err" # save stderr output of WGet and other extern programs called
VERBOSE_MODE=0 # no console logging
LOGFILE="$ddns_logdir/$SECTION_ID.log"
DATFILE="$ddns_rundir/$SECTION_ID.$$.dat" # save stdout data of WGet and other extern programs called
ERRFILE="$ddns_rundir/$SECTION_ID.$$.err" # save stderr output of WGet and other extern programs called
DDNSPRG="/usr/lib/ddns/dynamic_dns_updater.sh"
VERBOSE=0 # no console logging
# global variables normally set by reading DDNS UCI configuration
use_syslog=0 # no syslog
use_logfile=0 # by default no logfile, can be changed here
use_logfile=0 # no logfile
use_ipv6=0 # Use IPv6 - default IPv4
force_ipversion=0 # Force IP Version - default 0 - No
force_dnstcp=0 # Force TCP on DNS - default 0 - No
is_glue=0 # Is glue record - default 0 - No
use_https=0 # not needed but must be set
while getopts ":6d:fghi:l:n:p:s:S:tu:Lv:V" OPT; do
case "$OPT" in
6) use_ipv6=1;;
d) dns_server="$OPTARG";;
f) force_ipversion=1;;
g) is_glue=1;;
i) ip_interface="$OPTARG"; ip_source="interface";;
l) lookup_host="$OPTARG";;
n) ip_network="$OPTARG"; ip_source="network";;
p) proxy="$OPTARG";;
s) ip_script="$OPTARG"; ip_source="script";;
t) force_dnstcp=1;;
u) ip_url="$OPTARG"; ip_source="web";;
h) usage; exit 255;;
L) use_logfile=1;;
v) VERBOSE=$OPTARG;;
S) SECTION=$OPTARG;;
V) printf %s\\n "ddns-scripts $VERSION"; exit 255;;
:) usage_err "option -$OPTARG missing argument";;
\?) usage_err "invalid option -$OPTARG";;
*) usage_err "unhandled option -$OPT $OPTARG";;
esac
done
shift $((OPTIND - 1 )) # OPTIND is 1 based
[ $# -eq 0 ] && usage_err "missing command"
__RET=0
case "$1" in
get_registered_ip)
local IP
domain=$2 # Hostname/Domain
use_ipv6=${3:-"0"} # Use IPv6 - default IPv4
force_ipversion=${4:-"0"} # Force IP Version - default 0 - No
force_dnstcp=${5:-"0"} # Force TCP on DNS - default 0 - No
dns_server=${6:-""} # DNS server - default No DNS
[ -z "$lookup_host" ] && usage_err "command 'get_registered_ip': 'lookup_host' not set"
write_log 7 "-----> get_registered_ip IP"
IP=""
get_registered_ip IP
__RET=$?
[ $__RET -ne 0 ] && IP=""
echo -n "$IP" # suppress LF
printf "%s" "$IP"
;;
verify_dns)
# $2 : dns-server to verify # no need for force_dnstcp because
# verify with nc (netcat) uses tcp anyway
use_ipv6=${3:-"0"} # Use IPv6 - default IPv4
force_ipversion=${4:-"0"} # Force IP Version - default 0 - No
write_log 7 "-----> verify_dns '$2'"
verify_dns "$2"
[ -z "$dns_server" ] && usage_err "command 'verify_dns': 'dns_server' not set"
write_log 7 "-----> verify_dns '$dns_server'"
verify_dns "$dns_server"
__RET=$?
;;
verify_proxy)
# $2 : proxy string to verify
use_ipv6=${3:-"0"} # Use IPv6 - default IPv4
force_ipversion=${4:-"0"} # Force IP Version - default 0 - No
write_log 7 "-----> verify_proxy '$2'"
verify_proxy "$2"
[ -z "$proxy" ] && usage_err "command 'verify_proxy': 'proxy' not set"
write_log 7 "-----> verify_proxy '$proxy'"
verify_proxy "$proxy"
__RET=$?
;;
get_local_ip)
local IP
use_ipv6="$2" # Use IPv6
ip_source="$3" # IP source
ip_network="$4" # set if source = "network" otherwise "-"
ip_url="$5" # set if source = "web" otherwise "-"
ip_interface="$6" # set if source = "interface" itherwiase "-"
ip_script="$7" # set if source = "script" otherwise "-"
proxy="$8" # proxy if set
force_ipversion="0" # not needed but must be set
use_https="0" # not needed but must be set
[ -z "$ip_source" ] && usage_err "command 'get_local_ip': 'ip_source' not set"
[ -n "$proxy" -a "$ip_source" = "web" ] && {
# proxy defined, used for ip_source=web
export HTTP_PROXY="http://$proxy"
@ -80,17 +132,34 @@ case "$1" in
export https_proxy="http://$proxy"
}
# don't need IP only the return code
[ "$ip_source" = "web" -o "$ip_source" = "script" ] && {
IP=""
if [ "$ip_source" = "web" -o "$ip_source" = "script" ]; then
# we wait only 3 seconds for an
# answer from "web" or "script"
write_log 7 "-----> timeout 3 -- get_local_ip IP"
timeout 3 -- get_local_ip IP
} || {
else
write_log 7 "-----> get_local_ip IP"
get_local_ip IP
}
fi
__RET=$?
;;
start)
[ -z "$SECTION" ] && usage_err "command 'start': 'SECTION' not set"
if [ $VERBOSE -eq 0 ]; then # start in background
$DDNSPRG -v 0 -S $SECTION -- start &
else
$DDNSPRG -v $VERBOSE -S $SECTION -- start
fi
;;
reload)
$DDNSPRG -- reload
;;
restart)
$DDNSPRG -- stop
sleep 1
$DDNSPRG -- start
;;
*)
__RET=255
;;
@ -99,4 +168,4 @@ esac
# remove out and err file
[ -f $DATFILE ] && rm -f $DATFILE
[ -f $ERRFILE ] && rm -f $ERRFILE
return $__RET
return $__RET

205
net/ddns-scripts/files/dynamic_dns_updater.sh Normal file → Executable file
View File

@ -1,57 +1,112 @@
#!/bin/sh
# /usr/lib/ddns/dynamic_dns_updater.sh
#
# Original written by Eric Paul Bishop, January 2008
#.Distributed under the terms of the GNU General Public License (GPL) version 2.0
# Original written by Eric Paul Bishop, January 2008
# (Loosely) based on the script on the one posted by exobyte in the forums here:
# http://forum.openwrt.org/viewtopic.php?id=14040
#
# extended and partial rewritten in August 2014 by
#.Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
# to support:
# - IPv6 DDNS services
# - DNS Server to retrieve registered IP including TCP transport (Ticket 7820)
# - Proxy Server to send out updates
# - force_interval=0 to run once (Luci Ticket 538)
# - the usage of BIND's host command instead of BusyBox's nslookup if installed
# - extended Verbose Mode and log file support for better error detection
# - wait for interface to fully come up, before the first update is done
# extended and partial rewritten
#.2014-2017 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
#
# variables in small chars are read from /etc/config/ddns
# variables in big chars are defined inside these scripts as global vars
# variables in big chars beginning with "__" are local defined inside functions only
# set -vx #script debugger
[ $# -lt 1 -o -n "${2//[0-3]/}" -o ${#2} -gt 1 ] && {
echo -e "\n USAGE:"
echo -e " $0 [SECTION] [VERBOSE_MODE]\n"
echo " [SECTION] - service section as defined in /etc/config/ddns"
echo " [VERBOSE_MODE] - '0' NO output to console"
echo " '1' output to console"
echo " '2' output to console AND logfile"
echo " + run once WITHOUT retry on error"
echo " '3' output to console AND logfile"
echo " + run once WITHOUT retry on error"
echo -e " + NOT sending update to DDNS service\n"
. $(dirname $0)/dynamic_dns_functions.sh # global vars are also defined here
usage() {
cat << EOF
Usage:
$MYPROG [options] -- command
Commands:
start Start SECTION or NETWORK or all
stop Stop NETWORK or all
Parameters:
-n NETWORK Start/Stop sections in background monitoring NETWORK, force VERBOSE=0
-S SECTION SECTION to start
use either -N NETWORK or -S SECTION
-h show this help and exit
-V show version and exit
-v LEVEL VERBOSE=LEVEL (default 1)
'0' NO output to console
'1' output to console
'2' output to console AND logfile
+ run once WITHOUT retry on error
'3' output to console AND logfile
+ run once WITHOUT retry on error
+ NOT sending update to DDNS service
EOF
}
usage_err() {
printf %s\\n "$MYPROG: $@" >&2
usage >&2
exit 1
}
. /usr/lib/ddns/dynamic_dns_functions.sh # global vars are also defined here
while getopts ":hv:n:S:V" OPT; do
case "$OPT" in
h) usage; exit 0;;
v) VERBOSE=$OPTARG;;
n) NETWORK=$OPTARG;;
S) SECTION_ID=$OPTARG;;
V) printf %s\\n "ddns-scripts $VERSION"; exit 0;;
:) usage_err "option -$OPTARG missing argument";;
\?) usage_err "invalid option -$OPTARG";;
*) usage_err "unhandled option -$OPT $OPTARG";;
esac
done
shift $((OPTIND - 1 )) # OPTIND is 1 based
SECTION_ID="$1"
VERBOSE_MODE=${2:-1} # default mode is log to console
[ -n "$NETWORK" -a -n "$SECTION_ID" ] && usage_err "use either option '-N' or '-S' not both"
[ $# -eq 0 ] && usage_err "missing command"
[ $# -gt 1 ] && usage_err "to much commands"
case "$1" in
start)
if [ -n "$NETWORK" ]; then
start_daemon_for_all_ddns_sections "$NETWORK"
exit 0
fi
if [ -z "$SECTION_ID" ]; then
start_daemon_for_all_ddns_sections
exit 0
fi
;;
stop)
if [ -n "$INTERFACE" ]; then
stop_daemon_for_all_ddns_sections "$NETWORK"
exit 0
else
stop_daemon_for_all_ddns_sections
exit 0
fi
exit 1
;;
reload)
killall -1 dynamic_dns_updater.sh 2>/dev/null
exit $?
;;
*) usage_err "unknown command - $1";;
esac
# set file names
PIDFILE="$RUNDIR/$SECTION_ID.pid" # Process ID file
UPDFILE="$RUNDIR/$SECTION_ID.update" # last update successful send (system uptime)
DATFILE="$RUNDIR/$SECTION_ID.dat" # save stdout data of WGet and other extern programs called
ERRFILE="$RUNDIR/$SECTION_ID.err" # save stderr output of WGet and other extern programs called
LOGFILE="$LOGDIR/$SECTION_ID.log" # log file
PIDFILE="$ddns_rundir/$SECTION_ID.pid" # Process ID file
UPDFILE="$ddns_rundir/$SECTION_ID.update" # last update successful send (system uptime)
DATFILE="$ddns_rundir/$SECTION_ID.dat" # save stdout data of WGet and other extern programs called
ERRFILE="$ddns_rundir/$SECTION_ID.err" # save stderr output of WGet and other extern programs called
LOGFILE="$ddns_logdir/$SECTION_ID.log" # log file
# VERBOSE_MODE > 1 delete logfile if exist to create an empty one
# VERBOSE > 1 delete logfile if exist to create an empty one
# only with this data of this run for easier diagnostic
# new one created by write_log function
[ $VERBOSE_MODE -gt 1 -a -f $LOGFILE ] && rm -f $LOGFILE
[ $VERBOSE -gt 1 -a -f $LOGFILE ] && rm -f $LOGFILE
# TRAP handler
trap "trap_handler 0 \$?" 0 # handle script exit with exit status
@ -70,16 +125,19 @@ trap "trap_handler 15" 15 # SIGTERM Termination
#
# defined options (also used as variable):
#
# enable self-explanatory
# enabled self-explanatory
# interface network interface used by hotplug.d i.e. 'wan' or 'wan6'
#
# service_name Which DDNS service do you use or "custom"
# update_url URL to use to update your "custom" DDNS service
# update_script SCRIPT to use to update your "custom" DDNS service
#
# domain Your DNS name / replace [DOMAIN] in update_url
# username Username of your DDNS service account / replace [USERNAME] in update_url
# password Password of your DDNS service account / replace [PASSWORD] in update_url
# lookup_host FQDN of ONE of your at DDNS service defined host / required to validate if IP update happen/necessary
# domain Nomally your DDNS hostname / replace [DOMAIN] in update_url
# username Username of your DDNS service account / urlenceded and replace [USERNAME] in update_url
# password Password of your DDNS service account / urlencoded and replace [PASSWORD] in update_url
# param_enc Optional parameter for (later) usage / urlencoded and replace [PARAMENC] in update_url
# param_opt Optional parameter for (later) usage / replace [PARAMOPT] in update_url
#
# use_https use HTTPS to update DDNS service
# cacert file or directory where HTTPS can find certificates to verify server; 'IGNORE' ignore check of server certificate
@ -108,6 +166,7 @@ trap "trap_handler 15" 15 # SIGTERM Termination
# force_dnstcp force communication with DNS server via TCP instead of default UDP
# proxy using a proxy for communication !!! ALSO used to detect local IP via web => return proxy's IP !!!
# use_logfile self-explanatory "/var/log/ddns/$SECTION_ID.log"
# is_glue the record that should be updated is a glue record
#
# some functionality needs
# - GNU Wget or cURL installed for sending updates to DDNS service
@ -128,6 +187,7 @@ ERR_LAST=$? # save return code - equal 0 if SECTION_ID found
[ -z "$force_ipversion" ] && force_ipversion=0 # default let system decide
[ -z "$force_dnstcp" ] && force_dnstcp=0 # default UDP
[ -z "$ip_source" ] && ip_source="network"
[ -z "$is_glue" ] && is_glue=0 # default the ddns record is not a glue record
[ "$ip_source" = "network" -a -z "$ip_network" -a $use_ipv6 -eq 0 ] && ip_network="wan" # IPv4: default wan
[ "$ip_source" = "network" -a -z "$ip_network" -a $use_ipv6 -eq 1 ] && ip_network="wan6" # IPv6: default wan6
[ "$ip_source" = "web" -a -z "$ip_url" -a $use_ipv6 -eq 0 ] && ip_url="http://checkip.dyndns.com"
@ -136,24 +196,26 @@ ERR_LAST=$? # save return code - equal 0 if SECTION_ID found
# SECTION_ID does not exists
[ $ERR_LAST -ne 0 ] && {
[ $VERBOSE_MODE -le 1 ] && VERBOSE_MODE=2 # force console out and logfile output
[ -f $LOGFILE ] && rm -f $LOGFILE # clear logfile before first entry
[ $VERBOSE -le 1 ] && VERBOSE=2 # force console out and logfile output
[ -f $LOGFILE ] && rm -f $LOGFILE # clear logfile before first entry
write_log 7 "************ ************** ************** **************"
write_log 5 "PID '$$' started at $(eval $DATE_PROG)"
write_log 7 "ddns version : $VERSION"
write_log 7 "uci configuration:\n$(uci -q show ddns | grep '=service' | sort)"
write_log 14 "Service section '$SECTION_ID' not defined"
}
write_log 7 "************ ************** ************** **************"
write_log 5 "PID '$$' started at $(eval $DATE_PROG)"
write_log 7 "ddns version : $VERSION"
write_log 7 "uci configuration:\n$(uci -q show ddns.$SECTION_ID | sort)"
write_log 7 "ddns version : $(opkg list-installed ddns-scripts | cut -d ' ' -f 3)"
case $VERBOSE_MODE in
# write_log 7 "ddns version : $(opkg list-installed ddns-scripts | cut -d ' ' -f 3)"
case $VERBOSE in
0) write_log 7 "verbose mode : 0 - run normal, NO console output";;
1) write_log 7 "verbose mode : 1 - run normal, console mode";;
2) write_log 7 "verbose mode : 2 - run once, NO retry on error";;
3) write_log 7 "verbose mode : 3 - run once, NO retry on error, NOT sending update";;
*) write_log 14 "error detecting VERBOSE_MODE '$VERBOSE_MODE'";;
*) write_log 14 "error detecting VERBOSE '$VERBOSE'";;
esac
# check enabled state otherwise we don't need to continue
@ -162,24 +224,41 @@ esac
# determine what update url we're using if a service_name is supplied
# otherwise update_url is set inside configuration (custom update url)
# or update_script is set inside configuration (custom update script)
[ -n "$service_name" ] && get_service_data update_url update_script
[ -n "$service_name" ] && get_service_data update_url update_script UPD_ANSWER
[ -z "$update_url" -a -z "$update_script" ] && write_log 14 "No update_url found/defined or no update_script found/defined!"
[ -n "$update_script" -a ! -f "$update_script" ] && write_log 14 "Custom update_script not found!"
# without domain and possibly username and password we can do nothing for you
[ -z "$domain" ] && write_log 14 "Service section not configured correctly! Missing 'domain'"
# temporary needed to convert existing uci settings
[ -z "$lookup_host" ] && {
uci -q set ddns.$SECTION_ID.lookup_host="$domain"
uci -q commit ddns
lookup_host="$domain"
}
# later versions only check if configured correctly
# without lookup host and possibly other required options we can do nothing for you
[ -z "$lookup_host" ] && write_log 14 "Service section not configured correctly! Missing 'lookup_host'"
[ -n "$update_url" ] && {
# only check if update_url is given, update_scripts have to check themselves
[ -z "$domain" ] && $(echo "$update_url" | grep "\[DOMAIN\]" >/dev/null 2>&1) && \
write_log 14 "Service section not configured correctly! Missing 'domain'"
[ -z "$username" ] && $(echo "$update_url" | grep "\[USERNAME\]" >/dev/null 2>&1) && \
write_log 14 "Service section not configured correctly! Missing 'username'"
[ -z "$password" ] && $(echo "$update_url" | grep "\[PASSWORD\]" >/dev/null 2>&1) && \
write_log 14 "Service section not configured correctly! Missing 'password'"
[ -z "$param_enc" ] && $(echo "$update_url" | grep "\[PARAMENC\]" >/dev/null 2>&1) && \
write_log 14 "Service section not configured correctly! Missing 'param_enc'"
[ -z "$param_opt" ] && $(echo "$update_url" | grep "\[PARAMOPT\]" >/dev/null 2>&1) && \
write_log 14 "Service section not configured correctly! Missing 'param_opt'"
}
# url encode username (might be email or something like this)
# and password (might have special chars for security reason)
# and optional parameter "param_enc"
[ -n "$username" ] && urlencode URL_USER "$username"
[ -n "$password" ] && urlencode URL_PASS "$password"
[ -n "$param_enc" ] && urlencode URL_PENC "$param_enc"
# verify ip_source 'script' if script is configured and executable
if [ "$ip_source" = "script" ]; then
@ -220,8 +299,8 @@ get_uptime CURR_TIME
if [ $LAST_TIME -eq 0 ]; then
write_log 7 "last update: never"
else
EPOCH_TIME=$(( $(date +%s) - CURR_TIME + LAST_TIME ))
EPOCH_TIME="date -d @$EPOCH_TIME +'$DATE_FORMAT'"
EPOCH_TIME=$(( $(date +%s) - $CURR_TIME + $LAST_TIME ))
EPOCH_TIME="date -d @$EPOCH_TIME +'$ddns_dateformat'"
write_log 7 "last update: $(eval $EPOCH_TIME)"
fi
@ -244,12 +323,15 @@ get_registered_ip REGISTERED_IP "NO_RETRY"
ERR_LAST=$?
# No error or No IP set otherwise retry
[ $ERR_LAST -eq 0 -o $ERR_LAST -eq 127 ] || get_registered_ip REGISTERED_IP
# on IPv6 we use expanded version to be shure when comparing
[ $use_ipv6 -eq 1 ] && expand_ipv6 "$REGISTERED_IP" REGISTERED_IP
# loop endlessly, checking ip every check_interval and forcing an updating once every force_interval
write_log 6 "Starting main loop at $(eval $DATE_PROG)"
while : ; do
get_local_ip LOCAL_IP # read local IP
[ $use_ipv6 -eq 1 ] && expand_ipv6 "$LOCAL_IP" LOCAL_IP # on IPv6 we use expanded version
# prepare update
# never updated or forced immediate then NEXT_TIME = 0
@ -261,8 +343,8 @@ while : ; do
# send update when current time > next time or local ip different from registered ip
if [ $CURR_TIME -ge $NEXT_TIME -o "$LOCAL_IP" != "$REGISTERED_IP" ]; then
if [ $VERBOSE_MODE -gt 2 ]; then
write_log 7 "Verbose Mode: $VERBOSE_MODE - NO UPDATE send"
if [ $VERBOSE -gt 2 ]; then
write_log 7 "Verbose Mode: $VERBOSE - NO UPDATE send"
elif [ "$LOCAL_IP" != "$REGISTERED_IP" ]; then
write_log 7 "Update needed - L: '$LOCAL_IP' <> R: '$REGISTERED_IP'"
else
@ -270,8 +352,8 @@ while : ; do
fi
ERR_LAST=0
[ $VERBOSE_MODE -lt 3 ] && {
# only send if VERBOSE_MODE < 3
[ $VERBOSE -lt 3 ] && {
# only send if VERBOSE < 3
send_update "$LOCAL_IP"
ERR_LAST=$? # save return value
}
@ -288,27 +370,30 @@ while : ; do
[ "$LOCAL_IP" != "$REGISTERED_IP" ] \
&& write_log 6 "Update successful - IP '$LOCAL_IP' send" \
|| write_log 6 "Forced update successful - IP: '$LOCAL_IP' send"
elif [ $ERR_LAST -eq 127 ]; then
write_log 3 "No update send to DDNS Provider"
else
write_log 3 "Can not update IP at DDNS Provider"
write_log 3 "IP update not accepted by DDNS Provider"
fi
fi
# now we wait for check interval before testing if update was recognized
# only sleep if VERBOSE_MODE <= 2 because otherwise nothing was send
[ $VERBOSE_MODE -le 2 ] && {
# only sleep if VERBOSE <= 2 because otherwise nothing was send
[ $VERBOSE -le 2 ] && {
write_log 7 "Waiting $CHECK_SECONDS seconds (Check Interval)"
sleep $CHECK_SECONDS &
PID_SLEEP=$!
wait $PID_SLEEP # enable trap-handler
PID_SLEEP=0
} || write_log 7 "Verbose Mode: $VERBOSE_MODE - NO Check Interval waiting"
} || write_log 7 "Verbose Mode: $VERBOSE - NO Check Interval waiting"
REGISTERED_IP="" # clear variable
get_registered_ip REGISTERED_IP # get registered/public IP
[ $use_ipv6 -eq 1 ] && expand_ipv6 "$REGISTERED_IP" REGISTERED_IP # on IPv6 we use expanded version
# IP's are still different
if [ "$LOCAL_IP" != "$REGISTERED_IP" ]; then
if [ $VERBOSE_MODE -le 1 ]; then # VERBOSE_MODE <=1 then retry
if [ $VERBOSE -le 1 ]; then # VERBOSE <=1 then retry
ERR_UPDATE=$(( $ERR_UPDATE + 1 ))
[ $retry_count -gt 0 -a $ERR_UPDATE -gt $retry_count ] && \
write_log 14 "Updating IP at DDNS provider failed after $retry_count retries"
@ -316,17 +401,17 @@ while : ; do
continue # loop to beginning
else
write_log 4 "Updating IP at DDNS provider failed"
write_log 7 "Verbose Mode: $VERBOSE_MODE - NO retry"; exit 1
write_log 7 "Verbose Mode: $VERBOSE - NO retry"; exit 1
fi
else
# we checked successful the last update
ERR_UPDATE=0 # reset error counter
fi
# force_update=0 or VERBOSE_MODE > 1 - leave here
[ $VERBOSE_MODE -gt 1 ] && write_log 7 "Verbose Mode: $VERBOSE_MODE - NO reloop"
# force_update=0 or VERBOSE > 1 - leave here
[ $VERBOSE -gt 1 ] && write_log 7 "Verbose Mode: $VERBOSE - NO reloop"
[ $FORCE_SECONDS -eq 0 ] && write_log 6 "Configured to run once"
[ $VERBOSE_MODE -gt 1 -o $FORCE_SECONDS -eq 0 ] && exit 0
[ $VERBOSE -gt 1 -o $FORCE_SECONDS -eq 0 ] && exit 0
write_log 6 "Rerun IP check at $(eval $DATE_PROG)"
done

View File

@ -22,72 +22,152 @@
# !!! Use only the script name (without path). Sample:
# !!! "example.com" "update_sample.sh"
#
# !!! Since ddns-scripts Version 2.5.x additional parameters are supported
# !!! and a given answer on success is checked (ignored by earlier versions)
# !!! Additional parameters: [PARAMOPT] and [PARAMENC]; [PARAMENC] is send urlencoded
#
# Line syntax: "service" [TAB] "update_url" [TAB] "answer"
# "service" name used as "option service_name" inside /etc/config/ddns
# "update_url" update url as given by the provider; custom urls should not saved here
# "answer" single words inside providers answer string; use "|" to combine "or"
#
# 44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
#
#.cloudflare.com-v1 !!! Please install additional package "ddns-scripts_cloudflare"
#.cloudflare.com-v4 !!! Please install additional package "ddns-scripts_cloudflare.com-v4"
#.godaddy.com-v1 !!! Please install additional package "ddns-scripts_godaddy.com-v1"
#.no-ip.com / noip.com !!! Please install additional package "ddns-scripts_no-ip_com"
"3322.org" "http://[USERNAME]:[PASSWORD]@members.3322.org/dyndns/update?system=dyndns&hostname=[DOMAIN]&myip=[IP]"
"able.or.kr" "http://able.or.kr/ddns/src/update.php?hostname=[DOMAIN]&myip=[IP]&ddnsuser=[USERNAME]&pwd=[PASSWORD]"
"afraid.org-basicauth" "http://[USERNAME]:[PASSWORD]@freedns.afraid.org/nic/update?hostname=[DOMAIN]&myip=[IP]
"afraid.org-keyauth" "http://freedns.afraid.org/dynamic/update.php?[PASSWORD]&address=[IP]"
"all-inkl.com" "http://[USERNAME]:[PASSWORD]@dyndns.kasserver.com/?myip=[IP]"
"changeip.com" "http://[USERNAME]:[PASSWORD]@nic.changeip.com/nic/update?u=[USERNAME]&p=[PASSWORD]&cmd=update&hostname=[DOMAIN]&ip=[IP]" "Successful"
"core-networks.de" "http://[USERNAME]:[PASSWORD]@dyndns.core-networks.de/?hostname=[DOMAIN]&myip=[IP]&keepipv6=1" "good"
"ddns.com.br" "http://[DOMAIN]:[PASSWORD]@members.ddns.com.br/nic/update?hostname=[DOMAIN]&myip=[IP]"
# "ddnss.de" "http://[USERNAME]:[PASSWORD]@ip4.ddnss.de/upd.php?host=[DOMAIN]&ip=[IP]" "good|nochg"
"ddnss.de" "http://ip4.ddnss.de/upd.php?user=[USERNAME]&pwd=[PASSWORD]&host=[DOMAIN]&ip=[IP]" "good|nochg"
"ddo.jp" "http://free.ddo.jp/dnsupdate.php?dn=[DOMAIN]&pw=[PASSWORD]&ip=[IP]"
"desec.io" "http://[USERNAME]:[PASSWORD]@update.dedyn.io/?hostname=[DOMAIN]&myipv4=[IP]" "good|nochg"
"dhis.org" "http://[USERNAME]:[PASSWORD]@is.dhis.org/"
"dnsdynamic.org" "http://[USERNAME]:[PASSWORD]@www.dnsdynamic.org/api/?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"dnsexit.com" "http://www.dnsexit.com/RemoteUpdate.sv?login=[USERNAME]&password=[PASSWORD]&host=[DOMAIN]&myip=[IP]" "0=|1="
"dnshome.de" "http://[USERNAME]:[PASSWORD]@www.dnshome.de/dyndns.php?hostname=[DOMAIN]&ip=[IP]"
"dnsmadeeasy.com" "http://www.dnsmadeeasy.com/servlet/updateip?username=[USERNAME]&password=[PASSWORD}&id=[DOMAIN]&ip=[IP]" "success|ip-same"
"dnsmax.com" "http://update.dnsmax.com/update/?username=[USERNAME]&password=[PASSWORD]&resellerid=1&clientname=openwrt&clientversion=8.09&protocolversion=2.0&updatehostname=[DOMAIN]&ip=[IP]"
"dnsomatic.com" "http://[USERNAME]:[PASSWORD]@updates.dnsomatic.com/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"dnspark.com" "http://[USERNAME]:[PASSWORD]@control.dnspark.com/api/dynamic/update.php?hostname=[DOMAIN]&ip=[IP]" "ok|nochange"
"do.de" "http://ddns.do.de/?myip=[IP]&hostname=[DOMAIN]&username=[USERNAME]&password=[PASSWORD]" "good|nochg"
"domopoli.de" "http://[USERNAME]:[PASSWORD]@http://dyndns.domopoli.de/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"dtdns.com" "http://www.dtdns.com/api/autodns.cfm?id=[DOMAIN]&pw=[PASSWORD]&ip=[IP]"
"duckdns.org" "http://www.duckdns.org/update?domains=[USERNAME]&token=[PASSWORD]&ip=[IP]" "OK"
"duiadns.net" "http://[USERNAME]:[PASSWORD]@ipv4.duia.ro/dynamic.duia?host=[DOMAIN]&ip4=[IP]"
"dy.fi" "http://[USERNAME]:[PASSWORD]@www.dy.fi/nic/update?hostname=[DOMAIN]" "good|nochg"
"dyndns.it" "http://[USERNAME]:[PASSWORD]@update.dyndns.it/nic/update?system=dyndns&hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"dyn.com" "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"dyndns.org" "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"dyndnss.net" "http://www.dyndnss.net/?user=[USERNAME]&pass=[PASSWORD]&domain=[DOMAIN]&updater=other"
"dynsip.org" "http://[USERNAME]:[PASSWORD]@dynsip.org/nic/update?hostname=[DOMAIN]&myip=[IP]"
"dyns.net" "http://www.dyns.net/postscript011.php?username=[USERNAME]&password=[PASSWORD]&host=[DOMAIN]&ip=[IP]" "200"
"dynu.com" "http://api.dynu.com/nic/update?hostname=[DOMAIN]&myip=[IP]&username=[USERNAME]&password=[PASSWORD]"
"dynv6.com" "http://dynv6.com/api/update?hostname=[DOMAIN]&token=[PASSWORD]&ipv4=[IP]" "updated"
"easydns.com" "http://[USERNAME]:[PASSWORD]@api.cp.easydns.com/dyn/generic.php?hostname=[DOMAIN]&myip=[IP]" "NOERROR"
"editdns.net" "http://dyndns-free.editdns.net/api/dynLinux.php?p=[PASSWORD]&r=[DOMAIN]"
"goip.de" "http://www.goip.de/setip?username=[USERNAME]&password=[PASSWORD]&subdomain=[DOMAIN]&ip4=[IP]"
"google.com" "http://[USERNAME]:[PASSWORD]@domains.google.com/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"he.net" "http://[DOMAIN]:[PASSWORD]@dyn.dns.he.net/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"joker.com" "http://svc.joker.com/nic/update?username=[USERNAME]&password=[PASSWORD]&myip=[IP]&hostname=[DOMAIN]" "good|nochg"
"loopia.se" "http://[USERNAME]:[PASSWORD]@dns.loopia.se/XDynDNSServer/XDynDNS.php?system=custom&hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"mydns.jp" "http://www.mydns.jp/directip.html?MID=[USERNAME]&PWD=[PASSWORD]&IPV4ADDR=[IP]"
"myonlineportal.net" "http://[USERNAME]:[PASSWORD]@myonlineportal.net/updateddns?hostname=[DOMAIN]&ip=[IP]" "good|nochg"
"mythic-beasts.com" "http://dnsapi4.mythic-beasts.com/?domain=[USERNAME]&password=[PASSWORD]&command=REPLACE%20[DOMAIN]%2060%20A%20DYNAMIC_IP&origin=."
"namecheap.com" "http://dynamicdns.park-your-domain.com/update?host=[USERNAME]&domain=[DOMAIN]&password=[PASSWORD]&ip=[IP]"
"nettica.com" "http://www.nettica.com/Domain/Update.aspx?U=[USERNAME]&PC=[PASSWORD]&FQDN=[DOMAIN]&N=[IP]"
"no-ip.pl" "http://[USERNAME]:[PASSWORD]@update.no-ip.pl/?hostname=[DOMAIN]"
"now-dns.com" "http://[USERNAME]:[PASSWORD]@now-dns.com/update?hostname=[DOMAIN]"
"nsupdate.info" "http://[USERNAME]:[PASSWORD]@ipv4.nsupdate.info/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"nubem.com" "http://[USERNAME]:[PASSWORD]@nubem.com/nic/update?hostname=[DOMAIN]&myip=[IP]"
"opendns.com" "http://[USERNAME]:[PASSWORD]@updates.opendns.com/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"oray.com" "http://[USERNAME]:[PASSWORD]@ddns.oray.com/ph/update?hostname=[DOMAIN]&myip=[IP]"
"ovh.com" "http://[USERNAME]:[PASSWORD]@www.ovh.com/nic/update?system=dyndns&hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"regfish.de" "http://dyndns.regfish.de/?fqdn=[DOMAIN]&forcehost=1&authtype=secure&token=[PASSWORD]&ipv4=[IP]" "success|100|101"
"schokokeks.org" "http://[USERNAME]:[PASSWORD]@dyndns.schokokeks.org/nic/update?myip=[IP]" "good|nochg"
"selfhost.de" "http://carol.selfhost.de/update?username=[USERNAME]&password=[PASSWORD]&myip=[IP]&hostname=1" "good|nochg|200|204"
"sitelutions.com" "http://www.sitelutions.com/dnsup?user=[USERNAME]&pass=[PASSWORD]&id=[DOMAIN]&ip=[IP]" "success"
"spdyn.de" "http://[USERNAME]:[PASSWORD]@update.spdyn.de/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"strato.com" "http://[USERNAME]:[PASSWORD]@dyndns.strato.com/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"system-ns.com" "http://system-ns.com/api?type=dynamic&command=set&domain=[DOMAIN]&token=[PASSWORD]&ip=[IP]" "0"
"thatip.com" "http://update.dnsmax.com/update/?username=[USERNAME]&password=[PASSWORD]&resellerid=2&clientname=openwrt&clientversion=8.09&protocolversion=2.0&updatehostname=[DOMAIN]&ip=[IP]"
"twodns.de" "http://[USERNAME]:[PASSWORD]@update.twodns.de/update?hostname=[DOMAIN]&ip=[IP]"
"udmedia.de" "http://[USERNAME]:[PASSWORD]@www.udmedia.de/nic/update?myip=[IP]"
"variomedia.de" "http://[USERNAME]:[PASSWORD]@dyndns.variomedia.de/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"xlhost.de" "http://[USERNAME]:[PASSWORD]@nsupdate.xlhost.de/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"zerigo.com" "http://update.zerigo.com/dynamic?user=[USERNAME]&password=[PASSWORD]&host=[DOMAIN]&ip=[IP]" "ok"
"dyndns.org" "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]"
"changeip.com" "http://[USERNAME]:[PASSWORD]@nic.changeip.com/nic/update?u=[USERNAME]&p=[PASSWORD]&cmd=update&hostname=[DOMAIN]&ip=[IP]"
"zoneedit.com" "http://[USERNAME]:[PASSWORD]@dynamic.zoneedit.com/auth/dynamic.html?host=[DOMAIN]&dnsto=[IP]"
"free.editdns.net" "http://dyndns-free.editdns.net/api/dynLinux.php?p=[PASSWORD]&r=[DOMAIN]"
# freedns.afraid.org is weird, you just need an update code, for which we use the password variable
"freedns.afraid.org" "http://freedns.afraid.org/dynamic/update.php?[PASSWORD]&address=[IP]"
"zzzz.io" "http://zzzz.io/api/v1/update/[DOMAIN]/?token=[PASSWORD]&ip=[IP]" "Updated|No change"
# DNS Max and resellers' update urls
"dnsmax.com" "http://update.dnsmax.com/update/?username=[USERNAME]&password=[PASSWORD]&resellerid=1&clientname=openwrt&clientversion=8.09&protocolversion=2.0&updatehostname=[DOMAIN]&ip=[IP]"
"thatip.com" "http://update.dnsmax.com/update/?username=[USERNAME]&password=[PASSWORD]&resellerid=2&clientname=openwrt&clientversion=8.09&protocolversion=2.0&updatehostname=[DOMAIN]&ip=[IP]"
# Hurricane Electric Dynamic DNS
"he.net" "http://[DOMAIN]:[PASSWORD]@dyn.dns.he.net/nic/update?hostname=[DOMAIN]&myip=[IP]"
# DNSdynamic.org
"dnsdynamic.org" "http://[USERNAME]:[PASSWORD]@www.dnsdynamic.org/api/?hostname=[DOMAIN]&myip=[IP]"
# dnsExit.com free dynamic DNS update url
"dnsexit.com" "http://www.dnsexit.com/RemoteUpdate.sv?login=[USERNAME]&password=[PASSWORD]&host=[DOMAIN]&myip=[IP]"
# OVH
"ovh.com" "http://[USERNAME]:[PASSWORD]@www.ovh.com/nic/update?system=dyndns&hostname=[DOMAIN]&myip=[IP]"
# dns-o-matic is a free service by opendns.com for updating multiple hosts and
# dynamic dns services in one api call. To update all your configured services
# at once, use "all.dnsomatic.com as the hostname.
"dnsomatic.com" "http://[USERNAME]:[PASSWORD]@updates.dnsomatic.com/nic/update?hostname=[DOMAIN]&myip=[IP]"
# 3322.org
"3322.org" "http://[USERNAME]:[PASSWORD]@members.3322.org/dyndns/update?system=dyndns&hostname=[DOMAIN]&myip=[IP]"
# namecheap.com
"namecheap.com" "http://dynamicdns.park-your-domain.com/update?host=[USERNAME]&domain=[DOMAIN]&password=[PASSWORD]&ip=[IP]"
# easydns.com dynamic DNS
"easydns.com" "http://[USERNAME]:[PASSWORD]@api.cp.easydns.com/dyn/tomato.php?hostname=[DOMAIN]&myip=[IP]"
# Winco DDNS
"ddns.com.br" "http://[DOMAIN]:[PASSWORD]@members.ddns.com.br/nic/update?hostname=[DOMAIN]&myip=[IP]"
# Mythic Beasts (https://www.mythic-beasts.com) Dynamic DNS
"mythic-beasts.com" "http://dnsapi4.mythic-beasts.com/?domain=[USERNAME]&password=[PASSWORD]&command=REPLACE%20[DOMAIN]%2060%20A%20DYNAMIC_IP"
# Securepoint Dynamic-DNS-Service (http://www.spdns.de)
"spdns.de" "http://[USERNAME]:[PASSWORD]@update.spdns.de/nic/update?hostname=[DOMAIN]&myip=[IP]"
# duiadns.net - free dynamic DNS
"duiadns.net" "http://ipv4.duia.ro/dynamic.duia?host=[DOMAIN]&password=[PASSWORD]&ip4=[IP]"
# Two-DNS - Simply. Connected. Everywhere.
"twodns.de" "http://[USERNAME]:[PASSWORD]@update.twodns.de/update?hostname=[DOMAIN]&ip=[IP]"
# MyDNS.JP
"mydns.jp" "http://www.mydns.jp/directip.html?MID=[USERNAME]&PWD=[PASSWORD]&IPV4ADDR=[IP]"
# LoopiaDNS
"loopia.se" "http://[USERNAME]:[PASSWORD]@dns.loopia.se/XDynDNSServer/XDynDNS.php?system=custom&hostname=[DOMAIN]&myip=[IP]"
# SelfHost.de
"selfhost.de" "http://carol.selfhost.de/update?username=[USERNAME]&password=[PASSWORD]&myip=[IP]&hostname=1"
# no-ip.pl nothing to do with no-ip.com (domain registered to www.domeny.tv) (IP autodetected by provider)
"no-ip.pl" "http://[USERNAME]:[PASSWORD]@update.no-ip.pl/?hostname=[DOMAIN]"
# domains.google.com non free service - require HTTPS communication
"domains.google.com" "https://[USERNAME]:[PASSWORD]@domains.google.com/nic/update?hostname=[DOMAIN]&myip=[IP]"

View File

@ -22,22 +22,78 @@
# !!! Use only the script name (without path). Sample:
# !!! "example.com" "update_sample.sh"
#
# !!! Since ddns-scripts Version 2.5.x additional parameters are supported
# !!! and a given answer on success is checked (ignored by earlier versions)
# !!! Additional parameters: [PARAMOPT] and [PARAMENC]; [PARAMENC] is send urlencoded
#
# Line syntax: "service" [TAB] "update_url" [TAB] "answer"
# "service" name used as "option service_name" inside /etc/config/ddns
# "update_url" update url as given by the provider; custom urls should not saved here
# "answer" words inside providers answer string; use "|" to combine "or"
#
# 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
#
#.cloudflare.com-v1 !!! Please install additional package "ddns-scripts_cloudflare"
#.cloudflare.com-v4 !!! Please install additional package "ddns-scripts_cloudflare.com-v4"
#.godaddy.com-v1 !!! Please install additional package "ddns-scripts_godaddy.com-v1"
#.no-ip.com / noip.com !!! Please install additional package "ddns-scripts_no-ip_com"
# IPv6 @ Securepoint Dynamic-DNS-Service
"spdns.de" "http://[USERNAME]:[PASSWORD]@update.spdns.de/nic/update?hostname=[DOMAIN]&myip=[IP]"
"afraid.org-basicauth" "http://[USERNAME]:[PASSWORD]@freedns.afraid.org/nic/update?hostname=[DOMAIN]&myip=[IP]
"afraid.org-keyauth" "http://freedns.afraid.org/dynamic/update.php?[PASSWORD]&address=[IP]"
# IPv6 @ Hurricane Electric Dynamic DNS
"he.net" "http://[DOMAIN]:[PASSWORD]@dyn.dns.he.net/nic/update?hostname=[DOMAIN]&myip=[IP]"
"all-inkl.com" "http://[USERNAME]:[PASSWORD]@dyndns.kasserver.com/?myip=[IP]"
# IPv6 @ MyDNS.JP
"mydns.jp" "http://www.mydns.jp/directip.html?MID=[USERNAME]&PWD=[PASSWORD]&IPV6ADDR=[IP]"
"core-networks.de" "http://[USERNAME]:[PASSWORD]@dyndns.core-networks.de/?hostname=[DOMAIN]&myip=[IP]&keepipv4=1" "good"
# IPv6 @ no-ip.pl nothing to do with no-ip.com (domain registered to www.domeny.tv) (IP autodetected by provider)
"no-ip.pl" "http://[USERNAME]:[PASSWORD]@update.no-ip.pl/?hostname=[DOMAIN]"
# "ddnss.de" "http://[USERNAME]:[PASSWORD]@ip6.ddnss.de/upd.php?host=[DOMAIN]&ip6=[IP]" "good|nochg"
"ddnss.de" "http://ip6.ddnss.de/upd.php?user=[USERNAME]&pwd=[PASSWORD]&host=[DOMAIN]&ip6=[IP]" "good|nochg"
# IPv6 @ freedns.afraid.org
"freedns.afraid.org" "http://freedns.afraid.org/dynamic/update.php?[PASSWORD]&address=[IP]"
"desec.io" "http://[USERNAME]:[PASSWORD]@update.dedyn.io/?hostname=[DOMAIN]&myipv6=[IP]" "good|nochg"
"dhis.org" "http://[USERNAME]:[PASSWORD]@is.dhis.org/"
"dnshome.de" "http://[USERNAME]:[PASSWORD]@www.dnshome.de/dyndns.php?hostname=[DOMAIN]&ip6=[IP]"
"do.de" "http://ddns.do.de/?myip=[IP]&hostname=[DOMAIN]&username=[USERNAME]&password=[PASSWORD]" "good|nochg"
"duckdns.org" "http://www.duckdns.org/update?domains=[DOMAIN]&token=[PASSWORD]&ipv6=[IP]" "OK"
"duiadns.net" "http://[USERNAME]:[PASSWORD]@ipv6.duia.ro/dynamic.duia?host=[DOMAIN]&ip6=[IP]"
"dyn.com" "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"dyndns.org" "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"dynv6.com" "http://dynv6.com/api/update?hostname=[DOMAIN]&token=[PASSWORD]&ipv6=[IP]" "updated"
"goip.de" "http://www.goip.de/setip?username=[USERNAME]&password=[PASSWORD]&subdomain=[DOMAIN]&ip6=[IP]"
"google.com" "http://[USERNAME]:[PASSWORD]@domains.google.com/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"he.net" "http://[DOMAIN]:[PASSWORD]@dyn.dns.he.net/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"loopia.se" "http://[USERNAME]:[PASSWORD]@dns.loopia.se/XDynDNSServer/XDynDNS.php?system=custom&hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"mydns.jp" "http://www.mydns.jp/directip.html?MID=[USERNAME]&PWD=[PASSWORD]&IPV6ADDR=[IP]"
"myonlineportal.net" "http://[USERNAME]:[PASSWORD]@myonlineportal.net/updateddns?hostname=[DOMAIN]&ip6=[IP]" "good|nochg"
"mythic-beasts.com" "http://dnsapi6.mythic-beasts.com/?domain=[USERNAME]&password=[PASSWORD]&command=REPLACE%20[DOMAIN]%2060%20AAAA%20DYNAMIC_IP&origin=."
"no-ip.pl" "http://[USERNAME]:[PASSWORD]@update.no-ip.pl/?hostname=[DOMAIN]"
"now-dns.com" "http://[USERNAME]:[PASSWORD]@now-dns.com/update?hostname=[DOMAIN]"
"nsupdate.info" "http://[USERNAME]:[PASSWORD]@ipv6.nsupdate.info/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"regfish.de" "http://dyndns.regfish.de/?fqdn=[DOMAIN]&forcehost=1&authtype=secure&token=[PASSWORD]&ipv6=[IP]" "success|100|101"
"spdyn.de" "http://[USERNAME]:[PASSWORD]@update.spdyn.de/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"udmedia.de" "http://[USERNAME]:[PASSWORD]@www.udmedia.de/nic/update?myip=[IP]"
"variomedia.de" "http://[USERNAME]:[PASSWORD]@dyndns.variomedia.de/nic/update?hostname=[DOMAIN]&myip=[IP]" "good|nochg"
"zerigo.com" "http://update.zerigo.com/dynamic?user=[USERNAME]&password=[PASSWORD]&host=[DOMAIN]&ip=[IP]" "ok"
"zzzz.io" "http://zzzz.io/api/v1/update/[DOMAIN]/?token=[PASSWORD]&type=aaaa&ip=[IP]" "Updated|No change"
# IPv6 @ LoopiaDNS
"loopia.se" "http://[USERNAME]:[PASSWORD]@dns.loopia.se/XDynDNSServer/XDynDNS.php?system=custom&hostname=[DOMAIN]&myip=[IP]"

View File

@ -2,7 +2,7 @@
#.Distributed under the terms of the GNU General Public License (GPL) version 2.0
#
# script for sending updates to cloudflare.com
#.2014-2015 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
#.2014-2017 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
# many thanks to Paul for testing and feedback during development
#
# This script is parsed by dynamic_dns_functions.sh inside send_update() function
@ -19,15 +19,26 @@
[ -z "$username" ] && write_log 14 "Service section not configured correctly! Missing 'username'"
[ -z "$password" ] && write_log 14 "Service section not configured correctly! Missing 'password'"
local __RECID __URL __KEY __KEYS __FOUND __SUBDOM __DOMAIN __TLD
local __RECID __URL __KEY __KEYS __FOUND __SUBDOM __DOMAIN __FQDN
# split given Host/Domain into TLD, registrable domain, and subdomain
split_FQDN $domain __TLD __DOMAIN __SUBDOM
[ $? -ne 0 -o -z "$__DOMAIN" ] && \
write_log 14 "Wrong Host/Domain configuration ($domain). Please correct configuration!"
# split __SUBDOM __DOMAIN from $domain
# given data:
# @example.com for "domain record"
# host.sub@example.com for a "host record"
__SUBDOM=$(printf %s "$domain" | cut -d@ -f1)
__DOMAIN=$(printf %s "$domain" | cut -d@ -f2)
# put together what we need
__DOMAIN="$__DOMAIN.$__TLD"
# Cloudflare v1 needs:
# __DOMAIN = the base domain i.e. example.com
# __SUBDOM = the host.sub to change if a "host record" or blank if domain record
# __FQDN = the FQDN to detect record_id to change
# i.e. example.com for the "domain record" or host.sub.example.com for "host record"
if [ -z "$__SUBDOM" -o "$__SUBDOM" = "$__DOMAIN" ]; then
__SUBDOM=""
__FQDN="$__DOMAIN"
else
__FQDN="${__SUBDOM}.${__DOMAIN}"
fi
# parse OpenWrt script with
# functions for parsing and generating json
@ -35,7 +46,7 @@ __DOMAIN="$__DOMAIN.$__TLD"
# function copied from /usr/share/libubox/jshn.sh
# from BB14.09 for backward compatibility to AA12.09
grep -i "json_get_keys" /usr/share/libubox/jshn.sh >/dev/null 2>&1 || json_get_keys() {
type "json_get_keys" >/dev/null 2>&1 || json_get_keys() {
local __dest="$1"
local _tbl_cur
@ -90,7 +101,7 @@ cleanup() {
# json_get_var __DISPLAY "display_name" # for debugging
json_get_var __NAME "name"
json_get_var __TYPE "type"
if [ "$__NAME" = "$domain" ]; then
if [ "$__NAME" = "$__FQDN" ]; then
# we must verify IPv4 and IPv6 because there might be both for the same host
[ \( $use_ipv6 -eq 0 -a "$__TYPE" = "A" \) -o \( $use_ipv6 -eq 1 -a "$__TYPE" = "AAAA" \) ] && {
__FOUND=1 # mark found
@ -106,7 +117,7 @@ cleanup() {
}
json_get_var __RECID "rec_id" # last thing to do get rec_id
json_cleanup # cleanup
write_log 7 "rec_id '$__RECID' detected for host/domain '$domain'"
write_log 7 "rec_id '$__RECID' detected for host/domain '$__FQDN'"
}
# build url according to cloudflare client api at https://www.cloudflare.com/docs/client-api.html

View File

@ -0,0 +1,188 @@
#!/bin/sh
#
#.Distributed under the terms of the GNU General Public License (GPL) version 2.0
#
# script for sending updates to cloudflare.com
#.based on Ben Kulbertis cloudflare-update-record.sh found at http://gist.github.com/benkulbertis
#.and on George Johnson's cf-ddns.sh found at https://github.com/gstuartj/cf-ddns.sh
#.2016-2017 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
# CloudFlare API documentation at https://api.cloudflare.com/
#
# This script is parsed by dynamic_dns_functions.sh inside send_update() function
#
# using following options from /etc/config/ddns
# option username - your cloudflare e-mail
# option password - cloudflare api key, you can get it from cloudflare.com/my-account/
# option domain - "hostname@yourdomain.TLD" # syntax changed to remove split_FQDN() function and tld_names.dat.gz
#
# variable __IP already defined with the ip-address to use for update
#
# check parameters
[ -z "$CURL_SSL" ] && write_log 14 "Cloudflare communication require cURL with SSL support. Please install"
[ -z "$username" ] && write_log 14 "Service section not configured correctly! Missing key as 'username'"
[ -z "$password" ] && write_log 14 "Service section not configured correctly! Missing secret as 'password'"
[ $use_https -eq 0 ] && use_https=1 # force HTTPS
# used variables
local __HOST __DOMAIN __TYPE __URLBASE __PRGBASE __RUNPROG __DATA __IPV6 __ZONEID __RECID
local __URLBASE="https://api.cloudflare.com/client/v4"
# split __HOST __DOMAIN from $domain
# given data:
# @example.com for "domain record"
# host.sub@example.com for a "host record"
__HOST=$(printf %s "$domain" | cut -d@ -f1)
__DOMAIN=$(printf %s "$domain" | cut -d@ -f2)
# Cloudflare v4 needs:
# __DOMAIN = the base domain i.e. example.com
# __HOST = the FQDN of record to modify
# i.e. example.com for the "domain record" or host.sub.example.com for "host record"
# handling domain record then set __HOST = __DOMAIN
[ -z "$__HOST" ] && __HOST=$__DOMAIN
# handling host record then rebuild fqdn host@domain.tld => host.domain.tld
[ "$__HOST" != "$__DOMAIN" ] && __HOST="${__HOST}.${__DOMAIN}"
# set record type
[ $use_ipv6 -eq 0 ] && __TYPE="A" || __TYPE="AAAA"
# transfer function to use for godaddy
# all needed variables are set global here
# so we can use them directly
cloudflare_transfer() {
local __CNT=0
local __ERR
while : ; do
write_log 7 "#> $__RUNPROG"
eval "$__RUNPROG"
__ERR=$? # save communication error
[ $__ERR -eq 0 ] && break # no error break while
write_log 3 "cURL Error: '$__ERR'"
write_log 7 "$(cat $ERRFILE)" # report error
[ $VERBOSE_MODE -gt 1 ] && {
# VERBOSE_MODE > 1 then NO retry
write_log 4 "Transfer failed - Verbose Mode: $VERBOSE_MODE - NO retry on error"
break
}
__CNT=$(( $__CNT + 1 )) # increment error counter
# if error count > retry_count leave here
[ $retry_count -gt 0 -a $__CNT -gt $retry_count ] && \
write_log 14 "Transfer failed after $retry_count retries"
write_log 4 "Transfer failed - retry $__CNT/$retry_count in $RETRY_SECONDS seconds"
sleep $RETRY_SECONDS &
PID_SLEEP=$!
wait $PID_SLEEP # enable trap-handler
PID_SLEEP=0
done
# check for error
grep -q '"success":true' $DATFILE || {
write_log 4 "CloudFlare reported an error:"
write_log 7 "$(cat $DATFILE)" # report error
return 1 # HTTP-Fehler
}
}
# Build base command to use
__PRGBASE="$CURL -RsS -o $DATFILE --stderr $ERRFILE"
# force network/interface-device to use for communication
if [ -n "$bind_network" ]; then
local __DEVICE
network_get_physdev __DEVICE $bind_network || \
write_log 13 "Can not detect local device using 'network_get_physdev $bind_network' - Error: '$?'"
write_log 7 "Force communication via device '$__DEVICE'"
__PRGBASE="$__PRGBASE --interface $__DEVICE"
fi
# force ip version to use
if [ $force_ipversion -eq 1 ]; then
[ $use_ipv6 -eq 0 ] && __PRGBASE="$__PRGBASE -4" || __PRGBASE="$__PRGBASE -6" # force IPv4/IPv6
fi
# set certificate parameters
if [ "$cacert" = "IGNORE" ]; then # idea from Ticket #15327 to ignore server cert
__PRGBASE="$__PRGBASE --insecure" # but not empty better to use "IGNORE"
elif [ -f "$cacert" ]; then
__PRGBASE="$__PRGBASE --cacert $cacert"
elif [ -d "$cacert" ]; then
__PRGBASE="$__PRGBASE --capath $cacert"
elif [ -n "$cacert" ]; then # it's not a file and not a directory but given
write_log 14 "No valid certificate(s) found at '$cacert' for HTTPS communication"
fi
# disable proxy if not set (there might be .wgetrc or .curlrc or wrong environment set)
# or check if libcurl compiled with proxy support
if [ -z "$proxy" ]; then
__PRGBASE="$__PRGBASE --noproxy '*'"
elif [ -z "$CURL_PROXY" ]; then
# if libcurl has no proxy support and proxy should be used then force ERROR
write_log 13 "cURL: libcurl compiled without Proxy support"
fi
# set headers
__PRGBASE="$__PRGBASE --header 'X-Auth-Email: $username' "
__PRGBASE="$__PRGBASE --header 'X-Auth-Key: $password' "
__PRGBASE="$__PRGBASE --header 'Content-Type: application/json' "
# __PRGBASE="$__PRGBASE --header 'Accept: application/json' "
# read zone id for registered domain.TLD
__RUNPROG="$__PRGBASE --request GET '$__URLBASE/zones?name=$__DOMAIN'"
cloudflare_transfer || return 1
# extract zone id
__ZONEID=$(grep -o '"id":"[^"]*' $DATFILE | grep -o '[^"]*$' | head -1)
[ -z "$__ZONEID" ] && {
write_log 4 "Could not detect 'zone id' for domain.tld: '$__DOMAIN'"
return 127
}
# read record id for A or AAAA record of host.domain.TLD
__RUNPROG="$__PRGBASE --request GET '$__URLBASE/zones/$__ZONEID/dns_records?name=$__HOST&type=$__TYPE'"
cloudflare_transfer || return 1
# extract record id
__RECID=$(grep -o '"id":"[^"]*' $DATFILE | grep -o '[^"]*$' | head -1)
[ -z "$__RECID" ] && {
write_log 4 "Could not detect 'record id' for host.domain.tld: '$__HOST'"
return 127
}
# extract current stored IP
__DATA=$(grep -o '"content":"[^"]*' $DATFILE | grep -o '[^"]*$' | head -1)
# check data
[ $use_ipv6 -eq 0 ] \
&& __DATA=$(printf "%s" "$__DATA" | grep -m 1 -o "$IPV4_REGEX") \
|| __DATA=$(printf "%s" "$__DATA" | grep -m 1 -o "$IPV6_REGEX")
# we got data so verify
[ -n "$__DATA" ] && {
# expand IPv6 for compare
if [ $use_ipv6 -eq 1 ]; then
expand_ipv6 $__IP __IPV6
expand_ipv6 $__DATA __DATA
[ "$__DATA" = "$__IPV6" ] && { # IPv6 no update needed
write_log 7 "IPv6 at CloudFlare.com already up to date"
return 0
}
else
[ "$__DATA" = "$__IP" ] && { # IPv4 no update needed
write_log 7 "IPv4 at CloudFlare.com already up to date"
return 0
}
fi
}
# update is needed
# let's build data to send,
# use file to work around " needed for json
cat > $DATFILE << EOF
{"id":"$__ZONEID","type":"$__TYPE","name":"$__HOST","content":"$__IP"}
EOF
# let's complete transfer command
__RUNPROG="$__PRGBASE --request PUT --data @$DATFILE '$__URLBASE/zones/$__ZONEID/dns_records/$__RECID'"
cloudflare_transfer || return 1
return 0

View File

@ -0,0 +1,171 @@
#!/bin/sh
#
#.Distributed under the terms of the GNU General Public License (GPL) version 2.0
#
# script for sending updates to godaddy.com
#.based on GoDaddy.sh v1.0 by Nazar78 @ TeaNazaR.com
#.2017 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
# GoDaddy Documentation at https://developer.godaddy.com/doc
#
# This script is parsed by dynamic_dns_functions.sh inside send_update() function
#
# using following options from /etc/config/ddns
# option username - "key" as generated at https://developer.godaddy.com/keys/
# option password - "secret" as generated at https://developer.godaddy.com/keys/
# option domain - "yourdomain.TLD" to update or "hostname@yourdomain.TLD"
#
# variable __IP already defined with the ip-address to use for update
#
# check parameters
[ -z "$CURL_SSL" ] && write_log 14 "GoDaddy communication require cURL with SSL support. Please install"
[ -z "$username" ] && write_log 14 "Service section not configured correctly! Missing key as 'username'"
[ -z "$password" ] && write_log 14 "Service section not configured correctly! Missing secret as 'password'"
[ $use_https -eq 0 ] && use_https=1 # force HTTPS
# used variables
local __HOST __DOMAIN __TYPE __URL __PRGBASE __RUNPROG __DATA __IPV6
# split __HOST __DOMAIN from $domain
# given data:
# @example.com for "domain record"
# host.sub@example.com for a "host record"
__HOST=$(printf %s "$domain" | cut -d@ -f1)
__DOMAIN=$(printf %s "$domain" | cut -d@ -f2)
# GoDaddy needs:
# __DOMAIN = the base domain i.e. example.com
# __HOST = host.sub if updating a host record or
# __HOST = "@" urlencoded "%40" for a domain record
[ -z "$__HOST" -o "$__HOST" = "$__DOMAIN" ] && __HOST="%40"
# set record type
[ $use_ipv6 -eq 0 ] && __TYPE="A" || __TYPE="AAAA"
# now we know the url to use
# __URL="https://api.ote-godaddy.com/v1/domains/$__DOMAIN/records/$__TYPE/$__HOST" # api test server
__URL="https://api.godaddy.com/v1/domains/$__DOMAIN/records/$__TYPE/$__HOST" # production server
# transfer function to use for godaddy
# all needed variables are set global here
# so we can use them directly
godaddy_transfer() {
local __CNT=0
local __STATUS __ERR __DEVICE
while : ; do
write_log 7 "#> $__RUNPROG"
__STATUS=$(eval "$__RUNPROG")
__ERR=$? # save communication error
[ $__ERR -eq 0 ] && break # no error break while
write_log 4 "cURL error: '$__ERR'"
write_log 7 "$(cat $ERRFILE)" # report error
[ $VERBOSE_MODE -gt 1 ] && {
# VERBOSE_MODE > 1 then NO retry
write_log 4 "Transfer failed - Verbose Mode: $VERBOSE_MODE - NO retry on error"
break
}
__CNT=$(( $__CNT + 1 )) # increment error counter
# if error count > retry_count leave here
[ $retry_count -gt 0 -a $__CNT -gt $retry_count ] && \
write_log 14 "Transfer failed after $retry_count retries"
write_log 4 "Transfer failed - retry $__CNT/$retry_count in $RETRY_SECONDS seconds"
sleep $RETRY_SECONDS &
PID_SLEEP=$!
wait $PID_SLEEP # enable trap-handler
PID_SLEEP=0
done
# handle HTTP error
[ $__STATUS -ne 200 ] && {
write_log 4 "GoDaddy reported an error:"
write_log 7 "$(cat $DATFILE)"
return 1
}
}
# Build base command to use
__PRGBASE="$CURL -RsS -w '%{http_code}' -o $DATFILE --stderr $ERRFILE"
# force network/interface-device to use for communication
if [ -n "$bind_network" ]; then
local __DEVICE
network_get_physdev __DEVICE $bind_network || \
write_log 13 "Can not detect local device using 'network_get_physdev $bind_network' - Error: '$?'"
write_log 7 "Force communication via device '$__DEVICE'"
__PRGBASE="$__PRGBASE --interface $__DEVICE"
fi
# force ip version to use
if [ $force_ipversion -eq 1 ]; then
[ $use_ipv6 -eq 0 ] && __PRGBASE="$__PRGBASE -4" || __PRGBASE="$__PRGBASE -6" # force IPv4/IPv6
fi
# set certificate parameters
if [ "$cacert" = "IGNORE" ]; then # idea from Ticket #15327 to ignore server cert
__PRGBASE="$__PRGBASE --insecure" # but not empty better to use "IGNORE"
elif [ -f "$cacert" ]; then
__PRGBASE="$__PRGBASE --cacert $cacert"
elif [ -d "$cacert" ]; then
__PRGBASE="$__PRGBASE --capath $cacert"
elif [ -n "$cacert" ]; then # it's not a file and not a directory but given
write_log 14 "No valid certificate(s) found at '$cacert' for HTTPS communication"
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
__PRGBASE="$__PRGBASE --noproxy '*'"
elif [ -z "$CURL_PROXY" ]; then
# if libcurl has no proxy support and proxy should be used then force ERROR
write_log 13 "cURL: libcurl compiled without Proxy support"
fi
# set headers
__PRGBASE="$__PRGBASE --header 'Authorization: sso-key $username:$password' "
__PRGBASE="$__PRGBASE --header 'Accept: application/json' "
__PRGBASE="$__PRGBASE --header 'Content-Type: application/json; charset=utf-8' "
# read data from godaddy.com
__RUNPROG="$__PRGBASE --request GET $__URL"
godaddy_transfer || return 1
# HTTP 200 OK, now analyse data and check if update needed
__DATA=$(sed -r 's/.+data":"(.+)","t.+/\1/g' $DATFILE)
# check data
[ $use_ipv6 -eq 0 ] \
&& __DATA=$(printf "%s" "$__DATA" | grep -m 1 -o "$IPV4_REGEX") \
|| __DATA=$(printf "%s" "$__DATA" | grep -m 1 -o "$IPV6_REGEX")
# we got data so verify
[ -n "$__DATA" ] && {
# expand IPv6 for compare
if [ $use_ipv6 -eq 1 ]; then
expand_ipv6 $__IP __IPV6
expand_ipv6 $__DATA __DATA
[ "$__DATA" = "$__IPV6" ] && { # IPv6 no update needed
write_log 7 "IPv6 at GoDaddy.com already up to date"
return 0
}
else
[ "$__DATA" = "$__IP" ] && { # IPv4 no update needed
write_log 7 "IPv4 at GoDaddy.com already up to date"
return 0
}
fi
}
# update is needed
# let's build data to send,
# use file to work around double quotes '"' needed for json
cat > $DATFILE << EOF
[{"data":"$__IP"}]
EOF
# let's complete transfer command
__RUNPROG="$__PRGBASE --request PUT --data @$DATFILE $__URL"
godaddy_transfer || return 1
# HTTP 200 OK
return 0

12
net/ddns-scripts/files/update_nsupdate.sh Normal file → Executable file
View File

@ -17,9 +17,10 @@
#
local __TTL=600 #.preset DNS TTL (in seconds)
local __RRTYPE __PW __TCP
local __PROG=$(which nsupdate) # BIND nsupdate ?
[ -z "$__PROG" ] && __PROG=$(which knsupdate) # Knot nsupdate ?
[ -x /usr/bin/nsupdate ] || write_log 14 "'nsupdate' not installed or not executable !"
[ -z "$__PROG" ] && write_log 14 "'nsupdate' or 'knsupdate' not installed !"
[ -z "$username" ] && write_log 14 "Service section not configured correctly! Missing 'username'"
[ -z "$password" ] && write_log 14 "Service section not configured correctly! Missing 'password'"
[ -z "$dns_server" ] && write_log 14 "Service section not configured correctly! Missing 'dns_server'"
@ -35,12 +36,13 @@ update del $domain $__RRTYPE
update add $domain $__TTL $__RRTYPE $__IP
show
send
answer
quit
EOF
/usr/bin/nsupdate -d $__TCP $DATFILE >$ERRFILE 2>&1
$__PROG -d $__TCP $DATFILE >$ERRFILE 2>&1
# nsupdate always return success
write_log 7 "nsupdate reports:\n$(cat $ERRFILE)"
write_log 7 "(k)nsupdate reports:\n$(cat $ERRFILE)"
return 0
return 0

View File

@ -29,31 +29,31 @@ config ddns "global"
# and LuCI web application.
# For codes see man pages of date command.
# default: "%F %R" (ISO 8601 format)
# option date_format "%F %R"
# option ddns_dateformat "%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"
# option ddns_rundir "/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"
# option ddns_logdir "/var/log/ddns"
###########
# set number of lines stored in .log file before auto truncated
# default: "250" lines
# option log_lines "250"
# option ddns_loglines "250"
###########
# Whether to allow to send Private/Special IP's to the DDNS provider
# IPv4: 0.x, 10.x, 127.x, 172.16.x-172.31.x, 192.168.x
# IPv6: ::, Fxxx:
# default: "0" disabled
# option allow_local_ip "0"
# option upd_privateip "0"
#####################################################################
# DDNS service settings
@ -115,9 +115,13 @@ config service "myddns"
# option update_script ""
###########
# 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.
# Keep an eye on providers help pages.
#
# FQDN of ONE of your defined host at DDNS provider
# REQUIRED to verify what the current IP at DNS using nslookup/host command
# default: none
option lookup_host ""
# Your DNS name / replace [DOMAIN] in update_url
# default: none
option domain ""
@ -126,10 +130,21 @@ config service "myddns"
# default: none
option username ""
# Password of your DDNS service account / replace [PASSWORD] in update_url
# Password of your DDNS service account / replace [PASSWORD] in update url
# default: none
option password ""
###########
# Optional parameters for use inside update_url
#
# parameter that will be urlencoded before replacement of [PARAMENC] inside update url
# default: none
option param_enc ""
# parameter that repace [PARAMOPT] inside update url
# default: none
option param_opt ""
###########
# use HTTPS for secure communication with you DDNS provider
# personally found some providers having problems when not sending

View File

@ -18,13 +18,15 @@
#
# tested with spdns.de
local __URL="http://[USERNAME]:[PASSWORD]@update.spdns.de/nic/update?hostname=[DOMAIN]&myip=[IP]"
# inside url we need username and password
# inside url we need domain, username and password
[ -z "$domain" ] && write_log 14 "Service section not configured correctly! Missing 'domain'"
[ -z "$username" ] && write_log 14 "Service section not configured correctly! Missing 'username'"
[ -z "$password" ] && write_log 14 "Service section not configured correctly! Missing 'password'"
# do replaces in URL
__URL=$(echo $__URL | sed -e "s#\[USERNAME\]#$URL_USER#g" -e "s#\[PASSWORD\]#$URL_PASS#g" \
-e "s#\[DOMAIN\]#$domain#g" -e "s#\[IP\]#$__IP#g")
__URL=$(echo $__URL | | sed -e "s#\[USERNAME\]#$URL_USER#g" -e "s#\[PASSWORD\]#$URL_PASS#g" \
-e "s#\[PARAMENC\]#$URL_PENC#g" -e "s#\[PARAMOPT\]#$param_opt#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 "$__URL" || return 1
@ -34,6 +36,6 @@ write_log 7 "DDNS Provider answered:\n$(cat $DATFILE)"
# analyse provider answers
# "good [IP_ADR]" = successful
# "nochg [IP_ADR]" = no change but OK
grep -E "good|nochg" $DATFILE >/dev/null 2>&1
grep -i -E "good|nochg" $DATFILE >/dev/null 2>&1
return $? # "0" if "good" or "nochg" found

View File

@ -0,0 +1,39 @@
#!/bin/sh
URL="https://publicsuffix.org/list/public_suffix_list.dat"
TMPFILE=$(dirname $0)/public_suffix_list.tmp
DATFILE=$(dirname $0)/public_suffix_list.dat
wget -O $TMPFILE $URL || exit 1
# there might be backslashes (at line end they produce problems)
sed -i 's/\\//g' $TMPFILE
# clear DATFILE if exist
printf %s "" > $DATFILE
L=0; M=0
export CHARSET=UTF-8 # needed for idn
cat ${TMPFILE} | while read LINE; do
L=$(( L + 1 ))
printf "\\r\\t%s\\t%s" "in: $L " "out: $(( $L + $M )) "
printf %s\\n "$LINE" | grep -E "^\/\/" >/dev/null 2>&1 && {
# do not modify lines beginning with "//"
printf %s\\n "$LINE" >> $DATFILE
continue
}
printf %s\\n "$LINE" | grep -E "^$" >/dev/null 2>&1 && {
# do not modify empty lines
printf %s\\n "$LINE" >> $DATFILE
continue
}
ASCII=$(idn -a "$LINE") # write ASCII and UTF-8
if [ "$ASCII" != "$LINE" ]; then
printf %s\\n "$ASCII" >> $DATFILE
printf "\\t%s\\n" "add: $ASCII"
M=$(( M + 1 ))
fi
printf %s\\n "$LINE" >> $DATFILE
done
rm -f $TMPFILE
#gzip -f9 $DATFILE