packages/net/ddns-scripts/files/usr/lib/ddns/update_huaweicloud_com.sh
2024-10-28 23:17:20 +08:00

153 lines
5.1 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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 KeyAK、SK documentation from https://support.huaweicloud.com/devg-apisign/api-sign-provide-aksk.html
# option domain - "hostname@yourdomain.TLD" # 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