diff --git a/net/ddns-scripts/Makefile b/net/ddns-scripts/Makefile index 9a8cc98a2e..ae4c448427 100644 --- a/net/ddns-scripts/Makefile +++ b/net/ddns-scripts/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ddns-scripts PKG_VERSION:=2.8.2 -PKG_RELEASE:=73 +PKG_RELEASE:=74 PKG_LICENSE:=GPL-2.0 @@ -342,6 +342,16 @@ define Package/ddns-scripts-huaweicloud/description Dynamic DNS Client scripts extension for huaweicloud.com API (require curl and openssl) endef +define Package/ddns-scripts-aliyun + $(call Package/ddns-scripts/Default) + TITLE:=Extension for Aliyun DNS API + DEPENDS:=ddns-scripts +curl +openssl-util +endef + +define Package/ddns-scripts-aliyun/description + Dynamic DNS Client scripts extension for aliyun.com API +endef + define Build/Configure endef @@ -427,6 +437,7 @@ define Package/ddns-scripts-services/install rm $(1)/usr/share/ddns/default/one.com.json rm $(1)/usr/share/ddns/default/porkbun.com-v3.json rm $(1)/usr/share/ddns/default/huaweicloud.com.json + rm $(1)/usr/share/ddns/default/aliyun.com.json endef @@ -818,6 +829,24 @@ fi exit 0 endef +define Package/ddns-scripts-aliyun/install + $(INSTALL_DIR) $(1)/usr/lib/ddns + $(INSTALL_BIN) ./files/usr/lib/ddns/update_aliyun_com.sh \ + $(1)/usr/lib/ddns + + $(INSTALL_DIR) $(1)/usr/share/ddns/default + $(INSTALL_DATA) ./files/usr/share/ddns/default/aliyun.com.json \ + $(1)/usr/share/ddns/default/ +endef + +define Package/ddns-scripts-aliyun/prerm +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + /etc/init.d/ddns stop +fi +exit 0 +endef + $(eval $(call BuildPackage,ddns-scripts)) $(eval $(call BuildPackage,ddns-scripts-services)) @@ -842,3 +871,4 @@ $(eval $(call BuildPackage,ddns-scripts-ns1)) $(eval $(call BuildPackage,ddns-scripts-one)) $(eval $(call BuildPackage,ddns-scripts-porkbun)) $(eval $(call BuildPackage,ddns-scripts-huaweicloud)) +$(eval $(call BuildPackage,ddns-scripts-aliyun)) diff --git a/net/ddns-scripts/files/usr/lib/ddns/update_aliyun_com.sh b/net/ddns-scripts/files/usr/lib/ddns/update_aliyun_com.sh new file mode 100644 index 0000000000..9a181f6d25 --- /dev/null +++ b/net/ddns-scripts/files/usr/lib/ddns/update_aliyun_com.sh @@ -0,0 +1,133 @@ +#!/bin/sh +# +#.Distributed under the terms of the GNU General Public License (GPL) version 2.0 +# 2023 ren dong +# +# Aliyun DNS Documentation at https://help.aliyun.com/document_detail/29742.html +# +# This script is parsed by dynamic_dns_functions.sh inside send_update() function +# +# using following options from /etc/config/ddns +# option username - AccessKeyID generated by Aliyun +# option password - AccessKeySecret generated by Aliyun +# option domain - "hostname@yourdomain.TLD" or "@yourdomain.TLD" +# +# variable __IP already defined with the ip-address to use for update +# + +# set API URL base +__URLBASE="https://alidns.aliyuncs.com/?" + +# check parameters +[ -z "$CURL" ] && [ -z "$CURL_SSL" ] && write_log 14 "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'" + +. /usr/share/libubox/jshn.sh + +local __RR __HOST __DOMAIN __TYPE + +# split __RR __DOMAIN from $domain +__RR=${domain%%@*} +__DOMAIN=${domain##*@} + +if [ -z "$__RR" ]; then + __RR="@" && __HOST="$__DOMAIN" +else + __HOST="$__RR.$__DOMAIN" +fi + +# set record type +[ "$use_ipv6" -eq 0 ] && __TYPE="A" || __TYPE="AAAA" + +# encode params using RFC3986 rule +encode_url_component() { + local str1 str2 index + str1=$(printf -- '%s' "$1" | $CURL -Gso /dev/null -w '%{url_effective}' --data-urlencode @- "aliyun.com" | cut -d "?" -f 2) + str2="" + index=0 + # convert the two hex numbers after '%' to uppercase + # we need uppercase hex, and use the above code is enough on other linux platform. but + # the curl of openwrt is a little bit different to other versions, i dont know why + while [ "$index" -lt ${#str1} ]; do + if [ "${str1:$index:1}" = "%" ]; then + str2="$str2$(printf -- '%s' "${str1:$index:3}" | tr [a-z] [A-Z])" && index=$((index + 3)) + else + str2="$str2${str1:$index:1}" && index=$((index + 1)) + fi + done + printf -- '%s' "$str2" +} + +do_request() { + local common_params canonicalized_query_string string_to_sign signature + local program http_code err + common_params="Format=JSON + Version=2015-01-09 + AccessKeyId=$username + SignatureMethod=HMAC-SHA1 + SignatureVersion=1.0 + Timestamp=$(encode_url_component "$(date -u +"%Y-%m-%dT%H:%M:%SZ")") + SignatureNonce=$(head /dev/urandom | tr -dc '0123456789' | head -c16)" + + # build canonicalized query string, notice we use ascii order when sorting + canonicalized_query_string="$(printf -- '%s' "$common_params $*" | sed 's/\s\+/\n/g' | LC_COLLATE=C sort | xargs | sed 's/\s/\&/g')" + + # calculate signature + string_to_sign="GET&$(encode_url_component "/")&$(encode_url_component "$canonicalized_query_string")" + signature="$(printf -- '%s' "$string_to_sign" | openssl sha1 -binary -hmac "$password&" | openssl base64)" + signature="Signature=$(encode_url_component "$signature")" + + program="$CURL -sSL -o $DATFILE --stderr $ERRFILE -w '%{http_code}' \"$__URLBASE$canonicalized_query_string&$signature\"" + + write_log 7 "Run command #> $program" + http_code=$(eval "$program") + err=$? + [ "$err" -eq 0 ] && [ "$http_code" -eq 200 ] || { + write_log 3 "Run command got error, curl err: $err, http_code: $http_code" + write_log 7 "DATFILE: $(cat "$DATFILE") ERRFILE $(cat "$ERRFILE")" + return 1 + } +} + +do_request "Action=DescribeSubDomainRecords" \ + "DomainName=$(encode_url_component "$__DOMAIN")" \ + "Type=$__TYPE" \ + "SubDomain=$(encode_url_component "$__HOST")" || return 1 + +# load record id and record value from the response +json_load_file "$DATFILE" +json_get_var __RECORD_COUNT TotalCount + +# if no record found, report error +[ "$__RECORD_COUNT" -eq 0 ] && { + write_log 7 "DNS record of $__HOST is not exist." + return 1 +} + +# if multiple records are found, only use the first one +[ "$__RECORD_COUNT" -gt 1 ] && { + write_log 4 "WARNING: found multiple records of $__HOST, only use the first one" +} + +# select the first DNS record +json_select DomainRecords +json_select Record +json_select 1 +# get the record id of the first DNS record +json_get_var __RECORD_ID RecordId +json_get_var __RECORD_VALUE Value + +# dont update if the ip has not changed +[ "$__RECORD_VALUE" = "$__IP" ] && { + write_log 7 "DNS record is up to date" + return 0 +} + +do_request "Action=UpdateDomainRecord" \ + "RR=$(encode_url_component "$__RR")" \ + "RecordId=$__RECORD_ID" \ + "Type=$__TYPE" \ + "Value=$(encode_url_component "$__IP")" || return 1 + +return 0 diff --git a/net/ddns-scripts/files/usr/share/ddns/default/aliyun.com.json b/net/ddns-scripts/files/usr/share/ddns/default/aliyun.com.json new file mode 100644 index 0000000000..c1ad8a5545 --- /dev/null +++ b/net/ddns-scripts/files/usr/share/ddns/default/aliyun.com.json @@ -0,0 +1,9 @@ +{ + "name": "aliyun.com", + "ipv4": { + "url": "update_aliyun_com.sh" + }, + "ipv6": { + "url": "update_aliyun_com.sh" + } +} diff --git a/net/ddns-scripts/files/usr/share/ddns/list b/net/ddns-scripts/files/usr/share/ddns/list index a1c3e91c84..6bacc23517 100644 --- a/net/ddns-scripts/files/usr/share/ddns/list +++ b/net/ddns-scripts/files/usr/share/ddns/list @@ -4,6 +4,7 @@ afraid.org-keyauth afraid.org-v2-basic afraid.org-v2-token all-inkl.com +aliyun.com changeip.com core-networks.de ddnss.de