diff --git a/ddnsmngr/Config.in b/ddnsmngr/Config.in new file mode 100644 index 000000000..c9ce72f8c --- /dev/null +++ b/ddnsmngr/Config.in @@ -0,0 +1,16 @@ +if PACKAGE_ddnsmngr +choice + prompt "Select backend for dynamic DNS management" + default DDNSMNGR_BACKEND_DDNSSCRIPT + depends on PACKAGE_ddnsmngr + help + Select which package to use for dynamic DNS support + +config DDNSMNGR_BACKEND_DDNSSCRIPT + bool "Use ddns_script" + +config DDNSMNGR_BACKEND_INADYN + bool "Use inadyn" + +endchoice +endif diff --git a/ddnsmngr/Makefile b/ddnsmngr/Makefile new file mode 100644 index 000000000..a387e094f --- /dev/null +++ b/ddnsmngr/Makefile @@ -0,0 +1,79 @@ +# +# Copyright (C) 2024 IOPSYS +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=ddnsmngr +PKG_VERSION:=1.0.0 + +LOCAL_DEV:=0 +ifneq ($(LOCAL_DEV),1) +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://dev.iopsys.eu/bbf/ddnsmngr.git +PKG_SOURCE_VERSION:=d0d37df44644ef2c1a0b11d3a4f92dc694ae1010 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz +PKG_MIRROR_HASH:=skip +endif + +PKG_LICENSE:=BSD-3-Clause +PKG_LICENSE_FILES:=LICENSE +PKG_CONFIG_DEPENDS:=CONFIG_DDNSMNGR_BACKEND_DDNSSCRIPT CONFIG_DDNSMNGR_BACKEND_INADYN + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=utils + CATEGORY:=Utilities + SUBMENU:=TRx69 + TITLE:=Dynamic DNS manager + DEPENDS:=+libbbfdm-api +DDNSMNGR_BACKEND_DDNSSCRIPT:ddns-scripts +DDNSMNGR_BACKEND_INADYN:inadyn + MENU:=1 +endef + +define Package/$(PKG_NAME)/config + source "$(SOURCE)/Config.in" +endef + +MAKE_PATH:=src + +define Package/$(PKG_NAME)/description + Manage dynamic DNS updation and provides Device.DynamicDNS. datamodel object based on TR181-2.16 +endef + +ifeq ($(LOCAL_DEV),1) +define Build/Prepare + $(CP) -rf ~/git/ddnsmngr/* $(PKG_BUILD_DIR)/ +endef +endif + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/etc/ddnsmngr + $(INSTALL_DIR) $(1)/etc/ddnsmngr/ddns + $(INSTALL_DIR) $(1)/etc/ddnsmngr/servers + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_DIR) $(1)/usr/lib/ddnsmngr + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_DIR) $(1)/usr/libexec/rpcd + $(INSTALL_DATA) $(PKG_BUILD_DIR)/src/libddnsmngr.so $(1)/etc/ddnsmngr/ + $(INSTALL_DATA) ./files/etc/ddnsmngr/input.json $(1)/etc/ddnsmngr/ + $(INSTALL_DATA) ./files/etc/config/ddnsmngr $(1)/etc/config/ddnsmngr + $(INSTALL_BIN) ./files/etc/uci-defaults/01-ddns-config-migrate $(1)/etc/uci-defaults/ + $(INSTALL_BIN) ./files/etc/init.d/ddnsmngr $(1)/etc/init.d/ddnsmngr +ifeq ($(CONFIG_DDNSMNGR_BACKEND_DDNSSCRIPT),y) + $(INSTALL_BIN) ./files/usr/lib/ddns_script/ddnsmngr_service.sh $(1)/usr/lib/ddnsmngr/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns-script/usr/lib/ddnsmngr/ddnsmngr_updater.sh $(1)/usr/lib/ddnsmngr/ + $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/ddns-script/server/* $(1)/etc/ddnsmngr/servers + $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns-script/usr/libexec/rpcd/ddnsmngr $(1)/usr/libexec/rpcd/ddnsmngr +endif +ifeq ($(CONFIG_DDNSMNGR_BACKEND_INADYN),y) + $(INSTALL_BIN) ./files/usr/lib/inadyn/ddnsmngr_service.sh $(1)/usr/lib/ddnsmngr/ + $(INSTALL_DATA) $(PKG_BUILD_DIR)/files/inadyn/server/* $(1)/etc/ddnsmngr/servers + $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/inadyn/usr/libexec/rpcd/ddnsmngr $(1)/usr/libexec/rpcd/ddnsmngr +endif +endef + + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/ddnsmngr/files/etc/config/ddnsmngr b/ddnsmngr/files/etc/config/ddnsmngr new file mode 100644 index 000000000..0f6073f92 --- /dev/null +++ b/ddnsmngr/files/etc/config/ddnsmngr @@ -0,0 +1,23 @@ +config ddnsmngr 'global' + option configfile '/var/run/ddnsmngr/ddnsmngr.json' + option ddns_dateformat '%F %R' + option ddns_rundir '/var/run/ddnsmngr' + option ddns_logdir '/var/log/ddnsmngr' + option ddns_loglines '250' + option upd_privateip '0' + option use_curl '1' + +config server 'ddns_server_1' + option enabled '1' + option service 'dynu.com' + option name 'dynu.com' + +config server 'ddns_server_2' + option enabled '1' + option service 'dyndns.org' + option name 'dyndns.org' + +config server 'ddns_server_3' + option enabled '1' + option service 'zoneedit.com' + option name 'zoneedit.com' diff --git a/ddnsmngr/files/etc/ddnsmngr/input.json b/ddnsmngr/files/etc/ddnsmngr/input.json new file mode 100644 index 000000000..91580ecfe --- /dev/null +++ b/ddnsmngr/files/etc/ddnsmngr/input.json @@ -0,0 +1,15 @@ +{ + "daemon": { + "input": { + "type": "DotSo", + "name": "/etc/ddnsmngr/libddnsmngr.so" + }, + "output": { + "type": "UBUS", + "name": "bbfdm.ddnsmngr", + "parent_dm": "Device.", + "object": "DynamicDNS", + "root_obj": "bbfdm" + } + } +} diff --git a/ddnsmngr/files/etc/init.d/ddnsmngr b/ddnsmngr/files/etc/init.d/ddnsmngr new file mode 100644 index 000000000..b1d410657 --- /dev/null +++ b/ddnsmngr/files/etc/init.d/ddnsmngr @@ -0,0 +1,29 @@ +#!/bin/sh /etc/rc.common + +START=80 +STOP=10 +USE_PROCD=1 +DM_INPUT="/etc/ddnsmngr/input.json" + +. /etc/bbfdm/bbfdm_services.sh +. /usr/lib/ddnsmngr/ddnsmngr_service.sh + +start_service() { + start_ddnsmngr_service + bbfdm_add_service "bbfdm.ddnsmngr" "${DM_INPUT}" +} + +stop_service() { + stop_ddnsmngr_service +} + +reload_service() { + stop + sleep 1 + start +} + +service_triggers() { + procd_add_reload_trigger ddnsmngr + add_ddnsmngr_triggers +} diff --git a/ddnsmngr/files/etc/uci-defaults/01-ddns-config-migrate b/ddnsmngr/files/etc/uci-defaults/01-ddns-config-migrate new file mode 100644 index 000000000..1e3409d85 --- /dev/null +++ b/ddnsmngr/files/etc/uci-defaults/01-ddns-config-migrate @@ -0,0 +1,170 @@ +#!/bin/sh + +. /lib/functions.sh + +cl_id=1 +srv_id=1 + +function get_ddns_config_option() { + local val + + val="$(uci -q get ddns.${1}.${2})" + + if [ -z "${val}" ] && [ -n "${3}" ]; then + val="${3}" + fi + + echo "${val}" +} + +function config_supported_service() { + if ! uci -q get ddnsmngr.global >/dev/null 2>&1; then + uci -q set ddnsmngr.global="ddnsmngr" + fi + + servers="" + + for i in $(find /etc/ddnsmngr/servers/ -name '*.json' | cut -d'/' -f 5 | sed "s/.json//") + do + if [ -z "${servers}" ]; then + servers="${i}" + else + servers="${servers},${i}" + fi + done + + uci -q set ddnsmngr.global.supported_services="${servers}" +} + +function migrate_service_section() { + client_sec="" + enabled="$(get_ddns_config_option ${1} enabled "0")" + service_name="$(get_ddns_config_option ${1} service_name)" + interface="$(get_ddns_config_option ${1} interface)" + ip_network="$(get_ddns_config_option ${1} ip_network)" + username="$(get_ddns_config_option ${1} username)" + password="$(get_ddns_config_option ${1} password)" + lookup_host="$(get_ddns_config_option ${1} lookup_host)" + use_ipv6="$(get_ddns_config_option ${1} use_ipv6 "0")" + force_ipversion="$(get_ddns_config_option ${1} force_ipversion "0")" + use_https="$(get_ddns_config_option ${1} use_https "0")" + force_dnstcp="$(get_ddns_config_option ${1} force_dnstcp "0")" + + if [ -z "${service_name}" ]; then + uci -q delete ddns."${1}" + return 0 + fi + + # check server file is present in device + if [ ! -f "/etc/ddnsmngr/servers/${service_name}.json" ]; then + uci -q delete ddns."${1}" + return 0 + fi + + # Check if client section is already added for this service + clients=$(uci -q show ddnsmngr | grep "=client") + client_count=$(echo "${clients}" | wc -l) + + tmp=0 + while [ $tmp -lt $client_count ] + do + mngr_serv="$(uci -q get ddnsmngr.@client[$tmp].service_name)" + mngr_intf="$(uci -q get ddnsmngr.@client[$tmp].interface)" + mngr_netw="$(uci -q get ddnsmngr.@client[$tmp].ip_network)" + mngr_user="$(uci -q get ddnsmngr.@client[$tmp].username)" + mngr_ipv6="$(uci -q get ddnsmngr.@client[$tmp].use_ipv6)" + mngr_forceip="$(uci -q get ddnsmngr.@client[$tmp].force_ipversion)" + mngr_https="$(uci -q get ddnsmngr.@client[$tmp].use_https)" + mngr_dnstcp="$(uci -q get ddnsmngr.@client[$tmp].force_dnstcp)" + + [ -z "${mngr_ipv6}" ] && mngr_ipv6="0" + [ -z "${mngr_forceip}" ] && mngr_forceip="0" + [ -z "${mngr_https}" ] && mngr_https="0" + [ -z "${mngr_dnstcp}" ] && mngr_dnstcp="0" + + if [ "${mngr_serv}" == "${service_name}" ] && [ "${mngr_intf}" == "${interface}" ] && \ + [ "${mngr_netw}" == "${ip_network}" ] && [ "${mngr_user}" == "${username}" ] && \ + [ "${mngr_ipv6}" == "${use_ipv6}" ] && [ "${mngr_forceip}" == "${force_ipversion}" ] && \ + [ "${mngr_https}" == "${use_https}" ] && [ "${mngr_dnstcp}" == "${force_dnstcp}" ]; then + break + fi + + tmp=$(( tmp + 1 )) + done + + if [ $tmp -ne $client_count ]; then + i=0 + for client in $clients; do + if [ $i -eq $tmp ]; then + client_sec="$(echo $client | cut -d'=' -f 1 | cut -d'.' -f 2)" + break + fi + i=$(( i + 1 )) + done + + if [ $enabled -eq 1 ]; then + uci -q set ddnsmngr."${client_sec}".enabled="1" + fi + else + client_sec=ddns_mig_client_"${cl_id}" + + uci -q set ddnsmngr."${client_sec}"="client" + uci -q set ddnsmngr."${client_sec}".enabled="${enabled}" + uci -q set ddnsmngr."${client_sec}".service_name="${service_name}" + uci -q set ddnsmngr."${client_sec}".interface="${interface}" + uci -q set ddnsmngr."${client_sec}".ip_network="${ip_network}" + uci -q set ddnsmngr."${client_sec}".username="${username}" + uci -q set ddnsmngr."${client_sec}".password="${password}" + uci -q set ddnsmngr."${client_sec}".use_ipv6="${use_ipv6}" + uci -q set ddnsmngr."${client_sec}".force_ipversion="${force_ipversion}" + uci -q set ddnsmngr."${client_sec}".use_https="${use_https}" + uci -q set ddnsmngr."${client_sec}".force_dnstcp="${force_dnstcp}" + + cl_id=$(( cl_id + 1 )) + + # add server section if not added + servers=$(uci -q show ddnsmngr | grep "service=\'${service_name}\'") + if [ -z "${servers}" ]; then + server_sec=ddns_mig_server_"${srv_id}" + uci -q set ddnsmngr."${server_sec}"="server" + uci -q set ddnsmngr."${server_sec}".enabled="1" + uci -q set ddnsmngr."${server_sec}".service="${service_name}" + uci -q set ddnsmngr."${server_sec}".name="${service_name}" + + srv_id=$(( srv_id + 1 )) + fi + fi + + + # if lookup_host is set then add host section + if [ -n "${lookup_host}" ] && [ -n "${client_sec}" ]; then + # check number of hosts present for this client + host_count=$(uci -q show ddnsmngr | grep "dm_parent=\'${client_sec}\'" | wc -l) + host_ix=$(( host_count + 1 )) + host_sec="${client_sec}"_host_"${host_ix}" + + uci -q set ddnsmngr."${host_sec}"="host" + uci -q set ddnsmngr."${host_sec}".enabled="${enabled}" + uci -q set ddnsmngr."${host_sec}".lookup_host="${lookup_host}" + uci -q set ddnsmngr."${host_sec}".dm_parent="${client_sec}" + fi + + uci -q delete ddns."${1}" +} + +function migrate_ddns_config() { + if [ ! -f "/etc/config/ddnsmngr" ]; then + # Create ddnsmngr config file + touch /etc/config/ddnsmngr + fi + + config_supported_service + + config_load ddns + config_foreach migrate_service_section service + + uci -q commit ddns + uci -q commit ddnsmngr +} + +migrate_ddns_config diff --git a/ddnsmngr/files/usr/lib/ddns_script/ddnsmngr_service.sh b/ddnsmngr/files/usr/lib/ddns_script/ddnsmngr_service.sh new file mode 100644 index 000000000..651dedb1f --- /dev/null +++ b/ddnsmngr/files/usr/lib/ddns_script/ddnsmngr_service.sh @@ -0,0 +1,169 @@ +#! /bin/sh + +RUNDIR="/var/run/ddnsmngr" +LOGDIR="/var/log/ddnsmngr" +PROG="/usr/lib/ddnsmngr/ddnsmngr_updater.sh" +CONFIGFILE="/var/run/ddnsmngr/ddnsmngr.json" +CLIENT_INTFS="" + +. /usr/share/libubox/jshn.sh + +log() { + echo "$*"|logger -t ddnsmngr.init -p debug +} + +validate_host_section() { + uci_validate_section ddnsmngr host "${1}" \ + 'enabled:bool:0' \ + 'lookup_host:string' \ + 'dm_parent:string' +} + +validate_client_section() { + uci_validate_section ddnsmngr client "${1}" \ + 'enabled:bool:0' \ + 'service_name:string' \ + 'interface:string' \ + 'ip_network:string' \ + 'username:string' \ + 'password:string' \ + 'use_https:bool:0' \ + 'force_dnstcp:bool:0' \ + 'use_ipv6:bool:0' \ + 'force_ipversion:bool:0' +} + +add_object() { + local enabled lookup_host dm_parent use_ipv6 force_ipversion proc_info_file + local service_name interface ip_network username password use_https force_dnstcp + + validate_host_section "${1}" || { + log "Validation of host section failed" + return 0 + } + + if [ "${enabled}" -ne 1 ] || [ -z "${dm_parent}" ]; then + return 0 + fi + + validate_client_section "${dm_parent}" || { + log "Validation of client section failed" + return 0 + } + + if [ "${enabled}" -ne 1 ]; then + return 0 + fi + + service_name=$(uci -q get ddnsmngr.${dm_parent}.service_name) + if [ -z "${service_name}" ]; then + return 0 + fi + + service_section=$(uci -q show ddnsmngr | grep "service=\'${service_name}\'" | cut -d'.' -f 2 | head -1) + if [ -z "${service_section}" ]; then + return 0 + fi + + service_enabled=$(uci -q get ddnsmngr.${service_section}.enabled) + if [ "${service_enabled}" -ne 1 ]; then + return 0 + fi + + json_add_object + json_add_string "interface" "${interface}" + json_add_string "service_name" "${service_name}" + json_add_string "username" "${username}" + json_add_string "password" "${password}" + json_add_string "lookup_host" "${lookup_host}" + json_add_string "ip_network" "${ip_network}" + json_add_string "proc_info_file" "${1}" + json_add_string "use_ipv6" "${use_ipv6}" + json_add_string "force_ipversion" "${force_ipversion}" + json_add_string "use_https" "${use_https}" + json_add_string "force_dnstcp" "${force_dnstcp}" + json_close_object + + if [ -z "${interface}" ]; then + if [ "${use_ipv6}" -eq 0 ]; then + interface="wan" + else + interface="wan6" + fi + fi + + for intf in $CLIENT_INTFS; do + if [ "${intf}" == "${interface}" ]; then + return 0 + fi + done + + CLIENT_INTFS="${CLIENT_INTFS} ${interface}" +} + +start_ddnsmngr_service() { + run_dir=$(uci -q get ddnsmngr.global.ddns_rundir) + log_dir=$(uci -q get ddnsmngr.global.ddns_logdir) + + if [ -n "${run_dir}" ]; then + RUNDIR="${run_dir}" + fi + + if [ -n "${log_dir}" ]; then + LOGDIR="${log_dir}" + fi + + mkdir -p "${RUNDIR}" + mkdir -p "${LOGDIR}" + + conf_file=$(uci -q get ddnsmngr.global.configfile) + if [ -n "${conf_file}" ]; then + CONFIGFILE="${conf_file}" + fi + + touch "${CONFIGFILE}" + + if [ ! -f "${CONFIGFILE}" ]; then + log "Can not create ${CONFIGFILE}, exit" + exit 0 + fi + + json_init + json_add_array "services" + + config_load ddnsmngr + config_foreach add_object host + + json_close_array + json_dump > "${CONFIGFILE}" + + procd_open_instance ddnsmngr + procd_set_param command "$PROG" + procd_append_param command -c "${CONFIGFILE}" + procd_append_param command -- start + procd_close_instance +} + +stop_ddnsmngr_service() { + conf_file=$(uci -q get ddnsmngr.global.configfile) + if [ -n "${conf_file}" ]; then + CONFIGFILE="${conf_file}" + fi + + if [ ! -f "${CONFIGFILE}" ]; then + log "${CONFIGFILE} not found, can't stop services if running any" + fi + + "$PROG" -c "${CONFIGFILE}" -- stop + return 0 +} + +add_ddnsmngr_triggers() { + procd_open_trigger + for intf in $CLIENT_INTFS; do + # No need to handle other ifevents like ifupdate etc + procd_add_interface_trigger "interface.*.up" $intf /etc/init.d/ddnsmngr restart + procd_add_interface_trigger "interface.*.down" $intf /etc/init.d/ddnsmngr restart + done + procd_close_trigger +} diff --git a/ddnsmngr/files/usr/lib/inadyn/ddnsmngr_service.sh b/ddnsmngr/files/usr/lib/inadyn/ddnsmngr_service.sh new file mode 100644 index 000000000..054325188 --- /dev/null +++ b/ddnsmngr/files/usr/lib/inadyn/ddnsmngr_service.sh @@ -0,0 +1,311 @@ +#!/bin/sh + +PROG="/usr/sbin/inadyn" +CONFIGPATH="/tmp/inadyn_config" +PIDPATH="/etc/inadyn_pid" +CLIENT_INTFS="" +CONFIG_FILES="" +SERVER_PATH="/etc/ddnsmngr/servers" + +FORMAT="custom [SECTION] {\n\tusername\t= [USER]\n\tpassword\t= [PWD]\n\tddns-server\t= [SERV]\n\tddns-path\t= [URI]\n\tssl\t\t= [SSL]\n\thostname\t= [NAME]\n\tcheckip-command\t= [CMD]\n\tddns-response\t= [RESPONSES]\n}" + + +. /usr/share/libubox/jshn.sh + +log() { + echo "$*"|logger -t ddnsmngr.init -p debug +} + +get_service_data() { + local provider="$1" + shift + local dir="$1" + shift + local ipv6="$1" + shift + + local name data url answer script + + [ $# -ne 2 ] && { + return 1 + } + + [ -f "${dir}/${provider}.json" ] || { + eval "$1=\"\"" + eval "$2=\"\"" + return 1 + } + + json_load_file "${dir}/${provider}.json" + json_get_var name "name" + if [ "$ipv6" -eq "1" ]; then + json_select "ipv6" + else + json_select "ipv4" + fi + json_get_var data "url" + json_get_var answer "answer" + json_select ".." + json_cleanup + + response="" + if [ -n "${answer}" ]; then + answer=$(echo "${answer}" | sed 's/|/ /g') + for ans in $answer; do + if [ -z "${response}" ]; then + response="${ans}" + else + response="${response}, ${ans}" + fi + done + response="{ ${response} }" + fi + + eval "$1=\"$data\"" + eval "$2=\"$response\"" + + return 0 +} + +generate_inadyn_config() { + json_load "${1}" + json_get_var service_name service_name + json_get_var use_ipv6 use_ipv6 + json_get_var interface interface + json_get_var username username + json_get_var password password + json_get_var host lookup_host + json_get_var conf_file config_file + json_get_var conf_dir config_dir + json_get_var server_address server_address + json_cleanup + + if [ -z "${service_name}" ] || [ -z "${host}" ]; then + return 1 + fi + + if [ -z "${conf_file}" ]; then + return 1 + fi + + if [ -z "${conf_dir}" ]; then + return 1 + fi + + # First look into custom path to load the url otherwise default path + get_service_data "${service_name}" "${SERVER_PATH}" "${use_ipv6}" server_url server_answer + + if [ -z "${server_url}" ]; then + return 1 + fi + + # Need to pick proto, server address and request uri separately from the url + # format http://[server_address]/[update_Request_uri] + proto=$(echo $server_url | cut -d':' -f 1) + serv=$(echo $server_url | cut -d'/' -f 3 | cut -d'@' -f 2) + uri=${server_url#*$serv} + + if [ -z $proto ] || [ -z $serv ] || [ -z $uri ]; then + return 1 + fi + + path=$(echo "$uri" | sed 's/&/\\&/g') + update_uri=$(echo $path | sed -e "s#\[DOMAIN\]#%h#g" -e "s#\[PASSWORD\]#%p#g" \ + -e "s#\[USERNAME\]#%u#g" -e "s#\[IP\]#%i#g") + + if [ -z "${interface}" ]; then + if [ "${use_ipv6}" -eq 0 ]; then + interface="wan" + else + interface="wan6" + fi + fi + + # now get the physical interface name + intf=$(ifstatus "${interface}" | jsonfilter -e '@.device') + if [ -z "${intf}" ]; then + return 1 + fi + + # command to get ip of the interface + if [ "${use_ipv6}" -eq 0 ]; then + get_ip="\"ifstatus ${interface} | jsonfilter -e '@[\\\\\"ipv4-address\\\\\"][0].address'\"" + else + get_ip="\"ifstatus ${interface} | jsonfilter -e '@[\\\\\"ipv6-address\\\\\"][0].address'\"" + fi + + if [ "${proto}" = "http" ]; then + ssl="false" + else + ssl="true" + fi + + inadyn_ver=$(inadyn -v) + user_agent="inadyn/${inadyn_ver}" + + config_file="${conf_dir}/${conf_file}" + touch "${config_file}" + + echo "iface = ${intf}" > "${config_file}" + echo "period = 600" >> "${config_file}" + echo "user-agent = ${user_agent}" >> "${config_file}" + + if [ "${use_ipv6}" -eq 1 ]; then + echo "allow-ipv6 = true" >> "${config_file}" + fi + + if [ -z "${password}" ]; then + FORMAT=$(echo "${FORMAT}" | sed 's/\\tpassword\\t= \[PWD\]\\n//g') + fi + + if [ -z "${server_answer}" ]; then + FORMAT=$(echo "${FORMAT}" | sed 's/\\tddns-response\\t= \[RESPONSES\]\\n//g') + fi + + config=$(echo $FORMAT | sed -e "s#\[SECTION\]#$conf_file#g" -e "s#\[PWD\]#$password#g" \ + -e "s#\[USER\]#$username#g" -e "s#\[SERV\]#$serv#g" \ + -e "s#\[URI\]#\"$update_uri\"#g" -e "s#\[SSL\]#$ssl#g" \ + -e "s#\[NAME\]#$host#g" -e "s#\[CMD\]#$get_ip#g" \ + -e "s#\[RESPONSES\]#$server_answer#g") + + echo -e "\n\n${config}" >> "${config_file}" + + return 0 +} + +validate_host_section() { + uci_validate_section ddnsmngr host "${1}" \ + 'enabled:bool:0' \ + 'lookup_host:string' \ + 'dm_parent:string' +} + +validate_client_section() { + uci_validate_section ddnsmngr client "${1}" \ + 'enabled:bool:0' \ + 'service_name:string' \ + 'interface:string' \ + 'ip_network:string' \ + 'username:string' \ + 'password:string' \ + 'use_https:bool:0' \ + 'force_dnstcp:bool:0' \ + 'use_ipv6:bool:0' \ + 'force_ipversion:bool:0' +} + +add_object() { + local enabled lookup_host dm_parent use_ipv6 force_ipversion + local service_name interface ip_network username password use_https force_dnstcp + + validate_host_section "${1}" || { + log "Validation of host section failed" + return + } + + if [ "${enabled}" -ne 1 ] || [ -z "${dm_parent}" ]; then + return + fi + + validate_client_section "${dm_parent}" || { + log "Validation of client section failed" + return + } + + if [ "${enabled}" -ne 1 ]; then + return + fi + + service_name=$(uci -q get ddnsmngr.${dm_parent}.service_name) + if [ -z "${service_name}" ]; then + return + fi + + service_section=$(uci show ddnsmngr | grep "service=\'${service_name}\'" | cut -d'.' -f 2 | head -1) + if [ -z "${service_section}" ]; then + return + fi + + service_enabled=$(uci -q get ddnsmngr.${service_section}.enabled) + if [ "${service_enabled}" -ne 1 ]; then + return + fi + + json_init + json_add_string "interface" "${interface}" + json_add_string "service_name" "${service_name}" + json_add_string "username" "${username}" + json_add_string "password" "${password}" + json_add_string "lookup_host" "${lookup_host}" + json_add_string "ip_network" "${ip_network}" + json_add_string "use_ipv6" "${use_ipv6}" + json_add_string "force_ipversion" "${force_ipversion}" + json_add_string "use_https" "${use_https}" + json_add_string "force_dnstcp" "${force_dnstcp}" + json_add_string "config_file" "${1}" + json_add_string "config_dir" "${CONFIGPATH}" + + json_str=$(json_dump) + json_cleanup + + generate_inadyn_config "${json_str}" + + if [ "$?" -ne 0 ]; then + return + fi + + CONFIG_FILES="${CONFIG_FILES} ${1}" + + if [ -z "${interface}" ]; then + if [ "${use_ipv6}" -eq 0 ]; then + interface="wan" + else + interface="wan6" + fi + fi + + for intf in $CLIENT_INTFS; do + if [ "${intf}" == "${interface}" ]; then + return + fi + done + + CLIENT_INTFS="${CLIENT_INTFS} ${interface}" +} + +start_ddnsmngr_service() { + rm -rf $CONFIGPATH + mkdir $CONFIGPATH + mkdir -p $PIDPATH + + config_load ddnsmngr + config_foreach add_object host + + i=1 + for conf in $CONFIG_FILES; do + instance="ddnsmngr_${i}" + i=$(( i + 1 )) + + procd_open_instance $instance + procd_set_param command "$PROG" + procd_append_param command -f "${CONFIGPATH}/${conf}" + procd_append_param command -l debug + procd_append_param command -P "${PIDPATH}/${conf}" + procd_append_param command -n -C + procd_close_instance + done +} + +stop_ddnsmngr_service() { + rm -rf $CONFIGPATH + return 0 +} + +add_ddnsmngr_triggers() { + procd_open_trigger + for intf in $CLIENT_INTFS; do + # No need to handle other ifevents like ifupdate etc + procd_add_interface_trigger "interface.*.up" $intf /etc/init.d/ddnsmngr restart + done + procd_close_trigger +}