ddns-scripts: add ddns-scripts for huaweicloud
authorLehua Zhang <[email protected]>
Fri, 11 Oct 2024 06:35:09 +0000 (14:35 +0800)
committerFlorian Eckert <[email protected]>
Tue, 15 Oct 2024 07:13:52 +0000 (09:13 +0200)
Signed-off-by: Lehua Zhang <[email protected]>
net/ddns-scripts/Makefile
net/ddns-scripts/files/usr/lib/ddns/update_huaweicloud_com.sh [new file with mode: 0644]
net/ddns-scripts/files/usr/share/ddns/default/huaweicloud.com.json [new file with mode: 0644]

index 0561f995848c28d67059f861ba7eb29d5f5b9a77..cd23443fa24d5a0b267ac9407ab6392562a8c540 100644 (file)
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=ddns-scripts
 PKG_VERSION:=2.8.2
-PKG_RELEASE:=48
+PKG_RELEASE:=49
 
 PKG_LICENSE:=GPL-2.0
 
@@ -307,6 +307,15 @@ define Package/ddns-scripts-porkbun/description
        "option domain" to be the FQDN for which to configure DDNS
 endef
 
+define Package/ddns-scripts-huaweicloud
+  $(call Package/ddns-scripts/Default)
+  TITLE:=Extension for huaweicloud.com API
+  DEPENDS:=ddns-scripts +curl +openssl-util
+endef
+
+define Package/ddns-scripts-huaweicloud/description
+  Dynamic DNS Client scripts extension for huaweicloud.com API (require curl and openssl)
+endef
 
 define Build/Configure
 endef
@@ -386,6 +395,7 @@ define Package/ddns-scripts-services/install
        rm $(1)/usr/share/ddns/default/ns1.com.json
        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
 endef
 
 
@@ -721,6 +731,25 @@ exit 0
 endef
 
 
+define Package/ddns-scripts-huaweicloud/install
+       $(INSTALL_DIR) $(1)/usr/lib/ddns
+       $(INSTALL_BIN) ./files/usr/lib/ddns/update_huaweicloud_com.sh \
+               $(1)/usr/lib/ddns
+
+       $(INSTALL_DIR) $(1)/usr/share/ddns/default
+       $(INSTALL_DATA) ./files/usr/share/ddns/default/huaweicloud.com.json \
+               $(1)/usr/share/ddns/default/
+endef
+
+define Package/ddns-scripts-huaweicloud/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))
 $(eval $(call BuildPackage,ddns-scripts-utils))
@@ -741,3 +770,4 @@ $(eval $(call BuildPackage,ddns-scripts-transip))
 $(eval $(call BuildPackage,ddns-scripts-ns1))
 $(eval $(call BuildPackage,ddns-scripts-one))
 $(eval $(call BuildPackage,ddns-scripts-porkbun))
+$(eval $(call BuildPackage,ddns-scripts-huaweicloud))
diff --git a/net/ddns-scripts/files/usr/lib/ddns/update_huaweicloud_com.sh b/net/ddns-scripts/files/usr/lib/ddns/update_huaweicloud_com.sh
new file mode 100644 (file)
index 0000000..1c21b1d
--- /dev/null
@@ -0,0 +1,152 @@
+#!/bin/sh
+#
+# script for sending updates to huaweicloud.com
+# 2023-2024 sxlehua <sxlehua at qq dot com>
+# API documentation at https://support.huaweicloud.com/api-dns/dns_api_62003.html
+# API signature documentation at https://support.huaweicloud.com/api-dns/dns_api_30003.html
+#
+# This script is parsed by dynamic_dns_functions.sh inside send_update() function
+# 
+# useage:
+# using following options from /etc/config/ddns
+# option username  - huaweicloud Access Key Id
+# option password  - huaweicloud Secret Access Key,AK、SK documentation from https://support.huaweicloud.com/devg-apisign/api-sign-provide-aksk.html
+# option domain    - "[email protected]" # syntax changed to remove split_FQDN() function and tld_names.dat.gz
+# 
+
+# Check inputs
+[ -z "$username" ] && write_log 14 "Configuration error! [username] cannot be empty"
+[ -z "$password" ] && write_log 14 "Configuration error! [password] cannot be empty"
+
+[ -z "$CURL" ] && [ -z "$CURL_SSL" ] && write_log 14 "huaweicloud API require cURL with SSL support. Please install"
+command -v openssl >/dev/null 2>&1 || write_log 14 "huaweicloud API require openssl-util support. Please install"
+
+# public variable
+local __HOST __DOMAIN __TYPE __ZONE_ID __RECORD_ID
+local __ENDPOINT="dns.cn-north-1.myhuaweicloud.com"
+local __TTL=120
+[ $use_ipv6 -eq 0 ] && __TYPE="A" || __TYPE="AAAA"
+
+# Get host and domain from $domain
+[ "${domain:0:2}" == "@." ] && domain="${domain/./}"        # host
+[ "$domain" == "${domain/@/}" ] && domain="${domain/./@}"   # host with no sperator
+__HOST="${domain%%@*}"
+__DOMAIN="${domain#*@}"
+[ -z "$__HOST" -o "$__HOST" == "$__DOMAIN" ] && __HOST="@"
+
+hcloud_transfer() {
+       local method=$1
+       local path=$2
+       local query=$3
+       local body=$4
+
+       local timestamp=$(date -u +'%Y%m%dT%H%M%SZ')
+       local contentType=""
+       if [ ! "$method" = "GET" ]; then
+               contentType="application/json"
+       fi
+       local _H_Content_Type=""
+
+       local canonicalUri="${path}"
+       # add / if need
+       echo $canonicalUri | grep -qE "/$" || canonicalUri="$canonicalUri/"
+       local canonicalQuery="$query" # for extend
+
+       local canonicalHeaders="host:$__ENDPOINT\nx-sdk-date:$timestamp\n"
+       local signedHeaders="host;x-sdk-date"
+
+       if [ ! "$contentType" = "" ]; then
+               canonicalHeaders="content-type:$contentType\n${canonicalHeaders}"
+               signedHeaders="content-type;$signedHeaders"
+               _H_Content_Type="Content-Type: ${contentType}"
+       fi
+
+       local hexencode=$(printf "%s" "$body" | openssl dgst -sha256 -hex 2>/dev/null | sed 's/^.* //')
+       local canonicalRequest="$method\n$canonicalUri\n$canonicalQuery\n$canonicalHeaders\n$signedHeaders\n$hexencode"
+       canonicalRequest="$(printf "$canonicalRequest%s")"
+
+       local stringToSign="SDK-HMAC-SHA256\n$timestamp\n$(printf "%s" "$canonicalRequest" | openssl dgst -sha256 -hex 2>/dev/null | sed 's/^.* //')"
+       stringToSign="$(printf "$stringToSign%s")"
+
+       local signature=$(printf "%s" "$stringToSign" | openssl dgst -sha256 -hmac "$password" 2>/dev/null | sed 's/^.* //')
+       authorization="SDK-HMAC-SHA256 Access=$username, SignedHeaders=$signedHeaders, Signature=$signature"
+
+       reqUrl="$__ENDPOINT$path"
+       if [ ! -z "$query" ]; then
+               reqUrl="$reqUrl""?$query"
+       fi
+
+       curl -s -X "${method}" \
+               -H "Host: $__ENDPOINT" \
+               -H "$_H_Content_Type" \
+               -H "Authorization: $authorization" \
+               -H "X-Sdk-Date: $timestamp" \
+               -d "${body}" \
+               "https://$reqUrl"
+
+       if [ $? -ne 0 ]; then
+               write_log 14 "rest api error"
+       fi
+}
+
+get_zone() {
+       local resp=`hcloud_transfer GET /v2/zones "name=$__DOMAIN.&search_mode=equal" ""`
+       __ZONE_ID=`printf "%s" $resp |  grep -Eo '"id":"[a-z0-9]+"' | cut -d':' -f2 | tr -d '"'`
+       if [ "$__ZONE_ID" = "" ]; then
+               write_log 14 "error, no zone"
+       fi
+}
+
+upd_record() {
+       local body="{\"name\":\"$__HOST.$__DOMAIN.\",\"type\":\"$__TYPE\",\"records\":[\"$__IP\"],\"ttl\":$__TTL}"
+       local resp=`hcloud_transfer PUT /v2/zones/"$__ZONE_ID"/recordsets/$__RECORD_ID "" "$body"`
+       local recordId=`printf "%s" $resp |  grep -Eo '"id":"[a-z0-9]+"' | cut -d':' -f2 | tr -d '"'`
+       if [ ! "$recordId" = "" ]; then
+               write_log 7 "upd [$recordId] success [$__TYPE] [$__IP]"
+       else
+               write_log 14 "upd ecord error [$resp]"
+       fi
+}
+
+add_record() {
+       local body="{\"name\":\"$__HOST.$__DOMAIN.\",\"type\":\"$__TYPE\",\"records\":[\"$__IP\"],\"ttl\":$__TTL}"
+       local resp=`hcloud_transfer POST /v2/zones/"$__ZONE_ID"/recordsets "" "$body"`
+       local recordId=`printf "%s" $resp |  grep -Eo '"id":"[a-z0-9]+"' | cut -d':' -f2 | tr -d '"'`
+       if [ ! "$recordId" = "" ]; then
+               write_log 7 "add [$recordId] success [$__TYPE] [$__IP]"
+       else
+               write_log 14 "add record error [$resp]"
+       fi
+}
+
+# Get DNS record
+get_record() {
+       local ret=0
+       local resp=`hcloud_transfer GET /v2/zones/$__ZONE_ID/recordsets "name=$__HOST.$__DOMAIN.&search_mode=equal" ""`
+       __RECORD_ID=`printf "%s" $resp |  grep -Eo '"id":"[a-z0-9]+"' | cut -d':' -f2 | tr -d '"' | head -1`
+       if [ "$__RECORD_ID" = "" ]; then
+               # Record needs to be add
+               ret=1
+       else
+               local remoteIp=`printf "%s" $resp | grep -Eo '"records":\[[^]]+]' | cut -d ':' -f 2-10 | tr -d '[' | tr -d ']' | tr -d '"' | head -1`
+               if [ ! "$remoteIp" = "$__IP" ]; then
+               # Record needs to be updated
+               ret=2
+               fi
+       fi
+       return $ret
+}
+
+get_zone
+get_record
+
+ret=$?
+if [ $ret -eq 0 ]; then
+       write_log 7 "nochg [$__IP]"
+fi
+if [ $ret -eq 1 ]; then
+       add_record
+fi
+if [ $ret -eq 2 ]; then
+       upd_record
+fi
diff --git a/net/ddns-scripts/files/usr/share/ddns/default/huaweicloud.com.json b/net/ddns-scripts/files/usr/share/ddns/default/huaweicloud.com.json
new file mode 100644 (file)
index 0000000..be549de
--- /dev/null
@@ -0,0 +1,9 @@
+{
+       "name": "huaweicloud.com",
+       "ipv4": {
+               "url": "update_huaweicloud_com.sh"
+       },
+       "ipv6": {
+               "url": "update_huaweicloud_com.sh"
+       }
+}