From: Lin Fan Date: Tue, 20 Jan 2026 06:49:24 +0000 (+0800) Subject: ddns-scripts: add namesilo.com X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=1199a4035122c62522831e9978bf1f7c87c21a53;p=openwrt-packages.git ddns-scripts: add namesilo.com new service provider namesilo.com config guide: * set [domain] to apex domain * set [username] to subdomain (without apex domain) * set [password] to api key Signed-off-by: Lin Fan --- diff --git a/net/ddns-scripts/Makefile b/net/ddns-scripts/Makefile old mode 100644 new mode 100755 index a5d7b4c5f..c3983e077 --- a/net/ddns-scripts/Makefile +++ b/net/ddns-scripts/Makefile @@ -124,6 +124,16 @@ define Package/ddns-scripts-godaddy/description Dynamic DNS Client scripts extension for 'godaddy.com API v1'. endef +define Package/ddns-scripts-namesilo + $(call Package/ddns-scripts/Default) + TITLE:=Extension for namesilo.com API v1 + DEPENDS:=ddns-scripts +curl + PROVIDES:=ddns-scripts_namesilo.com-v1 +endef + +define Package/ddns-scripts-namesilo/description + Dynamic DNS Client scripts extension for 'namesilo.com API v1'. +endef define Package/ddns-scripts-digitalocean $(call Package/ddns-scripts/Default) @@ -436,6 +446,7 @@ define Package/ddns-scripts-services/install rm $(1)/usr/share/ddns/default/cloud.google.com-v1.json rm $(1)/usr/share/ddns/default/freedns.42.pl.json rm $(1)/usr/share/ddns/default/godaddy.com-v1.json + rm $(1)/usr/share/ddns/default/namesilo.com-v1.json rm $(1)/usr/share/ddns/default/digitalocean.com-v2.json rm $(1)/usr/share/ddns/default/dnspod.cn.json rm $(1)/usr/share/ddns/default/dnspod.cn-v3.json @@ -559,6 +570,23 @@ fi exit 0 endef +define Package/ddns-scripts-namesilo/install + $(INSTALL_DIR) $(1)/usr/lib/ddns + $(INSTALL_BIN) ./files/usr/lib/ddns/update_namesilo_com_v1.sh \ + $(1)/usr/lib/ddns + + $(INSTALL_DIR) $(1)/usr/share/ddns/default + $(INSTALL_DATA) ./files/usr/share/ddns/default/namesilo.com-v1.json \ + $(1)/usr/share/ddns/default +endef + +define Package/ddns-scripts-namesilo/prerm +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + /etc/init.d/ddns stop +fi +exit 0 +endef define Package/ddns-scripts-digitalocean/install $(INSTALL_DIR) $(1)/usr/lib/ddns @@ -889,6 +917,7 @@ $(eval $(call BuildPackage,ddns-scripts-cloudflare)) $(eval $(call BuildPackage,ddns-scripts-gcp)) $(eval $(call BuildPackage,ddns-scripts-freedns)) $(eval $(call BuildPackage,ddns-scripts-godaddy)) +$(eval $(call BuildPackage,ddns-scripts-namesilo)) $(eval $(call BuildPackage,ddns-scripts-digitalocean)) $(eval $(call BuildPackage,ddns-scripts-dnspod)) $(eval $(call BuildPackage,ddns-scripts-dnspod-v3)) diff --git a/net/ddns-scripts/files/usr/lib/ddns/update_namesilo_com_v1.sh b/net/ddns-scripts/files/usr/lib/ddns/update_namesilo_com_v1.sh new file mode 100755 index 000000000..8c0bf129b --- /dev/null +++ b/net/ddns-scripts/files/usr/lib/ddns/update_namesilo_com_v1.sh @@ -0,0 +1,235 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Script for updating NameSilo DNS records +# 2026 Lin Fan +# +# using following options from /etc/config/ddns +# username - sub domain +# password - api key +# domain - domain +# +# optional parameters (param_opt) from /etc/config/ddns +# ttl - ttl in seconds (e.g. ttl=7200, default '3600') +# pp - proxy protocol (e.g. pp=socks5h, default 'http') +# fmt - response format (e.g. fmt=xml, default 'json') +# +# reference: https://www.namesilo.com/api-reference +# +# SECURITY NOTE: +# The NameSilo API requires the API key to be passed as a URL query parameter. +# This means the key may be exposed in shell history, process listings (ps), +# and system logs that record full command lines. Use a dedicated API key and +# protect access to this system and its logs accordingly. + + +# check curl +[ -z "$CURL" ] || [ -z "$CURL_SSL" ] && { + write_log 14 "NameSilo script requires cURL with SSL support" + return 1 +} +[ -n "$proxy" ] && [ -z "$CURL_PROXY" ] && { + write_log 14 "cURL: libcurl compiled without proxy support" + return 1 +} + +# check options +[ -z "$username" ] && write_log 14 "NameSilo: 'username' (sub domain) not set" && return 1 +[ -z "$password" ] && write_log 14 "NameSilo: 'password' (api key) not set" && return 1 +[ -z "$domain" ] && write_log 14 "NameSilo: 'domain' not set" && return 1 +[ "$use_ipv6" -eq 1 ] && type="AAAA" || type="A" + +# parse optional parameters +[ -n "$param_opt" ] && { + for pair in $param_opt ; do + case $pair in + ttl=*) + param_opt_ttl=${pair#*=} + ;; + pp=*) + param_opt_pp=${pair#*=} + ;; + fmt=*) + param_opt_fmt=${pair#*=} + ;; + *) + # ignore others + ;; + esac + done +} + +# check optional parameters +ttl="${param_opt_ttl:-3600}" +fmt=$(echo ${param_opt_fmt:-json} | tr 'A-Z' 'a-z') +[ "$fmt" != "json" ] && [ "$fmt" != "xml" ] && { + write_log 14 "NameSilo: optional parameter 'fmt' must be json (default) or xml" + return 1 +} + +# load jshn.sh +[ "$fmt" == "json" ] && { + . /usr/share/libubox/jshn.sh +} + +# check xmlstarlet (optional) +[ "$fmt" == "xml" ] && { + XMLSTARLET=$(command -v xmlstarlet) + [ -z "$XMLSTARLET" ] && { + write_log 7 "Suggestion: install 'xmlstarlet' to parse XML response accurately" + } +} + +# curl command +CURL_CMD="$CURL -sSf -o $DATFILE --stderr $ERRFILE" +[ -n "$proxy" ] && { + [ -z "$param_opt_pp" ] && { + proxy_arg="--proxy ${proxy}" + } || { + proxy_arg="--proxy ${param_opt_pp}://${proxy}" + } + CURL_CMD="$CURL_CMD $proxy_arg" +} + +# extract response code +get_code() { + # json + [ "$fmt" == "json" ] && { + local json=$(cat) + local code + json_load "$json" + json_select "reply" + json_get_var code "code" + printf "%s\n" "$code" + return + } + + # xml + [ -n "$XMLSTARLET" ] && { + # try xmlstarlet first + $XMLSTARLET sel -t -v "/namesilo/reply/code" 2>/dev/null + } || { + # fallback to grep/sed + grep -o '.*' | sed 's///;s/<\/code>//' 2>/dev/null + } +} + +# extract detail message +get_detail() { + # json + [ "$fmt" == "json" ] && { + local json=$(cat) + local detail + json_load "$json" + json_select "reply" + json_get_var detail "detail" + printf "%s\n" "$detail" + return + } + + # xml + [ -n "$XMLSTARLET" ] && { + # try xmlstarlet first + $XMLSTARLET sel -t -v "/namesilo/reply/detail" 2>/dev/null + } || { + # fallback to grep/sed + grep -o '.*' | sed 's///;s/<\/detail>//' 2>/dev/null + } +} + +# extract rrid +get_rrid() { + # json + [ "$fmt" == "json" ] && { + local json=$(cat) + json_load "$json" + json_select "reply" + json_select "resource_record" + local idx=1 + while json_is_a $idx object ; do + local host + local rtyp + local rrid + json_select $idx + json_get_var host "host" + json_get_var rtyp "type" + json_get_var rrid "record_id" + [ "$host" == "$username" ] && [ "$rtyp" == "$type" ] && { + printf "%s\n" "$rrid" + return + } + idx=$(( idx + 1 )) + json_select .. + done + return + } + + # xml + [ -n "$XMLSTARLET" ] && { + # try xmlstarlet first + $XMLSTARLET sel -t -v "/namesilo/reply/resource_record/record_id[../host='${username}'][../type='${type}']" 2>/dev/null + } || { + # fallback to grep/sed + local record + for record in $(sed "s//\n/g" | + grep -o ".*$username.*") ; do + local rtyp=$(printf "%s\n" "$record" | sed "s/.*//;s/<\/type>.*//") + [ "$rtyp" == "$type" ] && { + printf "%s\n" "$record" | sed "s/.*//;s/<\/record_id>.*//" + return + } + done + } +} + +# call domain api +call_api() { + local endpoint="$1" + local params="$2" + local url="https://www.namesilo.com/api/${endpoint}?version=1&type=${fmt}&key=${password}&${params}" + + # call api + $CURL_CMD "$url" + local rc=$? + [ "$rc" -ne 0 ] && { + write_log 3 "NameSilo: API request to '$endpoint' failed with exit code $rc" + return 1 + } + + # check response + local response=$(cat "$DATFILE") + [ -z "$response" ] && { + write_log 3 "NameSilo: Empty response from API '$endpoint'" + return 1 + } + + # check reply code + local code=$(printf "%s\n" "$response" | get_code) + [ "$code" != "300" ] && { + local detail=$(printf "%s\n" "$response" | get_detail) + write_log 3 "NameSilo: API request to '$endpoint' returned with error '$code - $detail'" + return 1 + } + + printf '%s\n' "$response" + return 0 +} + +# get rrid +response=$(call_api dnsListRecords "domain=$domain") +[ -z "$response" ] && return 1 +rrid=$(printf "%s\n" "$response" | get_rrid) +[ -z "$rrid" ] && { + write_log 14 "NameSilo: No matching '$type' DNS record found for host '$username' in domain '$domain'" + return 1 +} + +# update subdomain record +call_api dnsUpdateRecord "domain=$domain&rrid=$rrid&rrhost=$username&rrvalue=$__IP&rrttl=$ttl" && { + write_log 7 "NameSilo: '$type' DNS record for '$username.$domain' updated successfully to IP '$__IP'" + return 0 +} || { + write_log 3 "NameSilo: Failed to update '$type' DNS record for '$username.$domain' to IP '$__IP'" + return 1 +} diff --git a/net/ddns-scripts/files/usr/share/ddns/default/namesilo.com-v1.json b/net/ddns-scripts/files/usr/share/ddns/default/namesilo.com-v1.json new file mode 100644 index 000000000..f8802e4a9 --- /dev/null +++ b/net/ddns-scripts/files/usr/share/ddns/default/namesilo.com-v1.json @@ -0,0 +1,9 @@ +{ + "name": "namesilo.com-v1", + "ipv4": { + "url": "update_namesilo_com_v1.sh" + }, + "ipv6": { + "url": "update_namesilo_com_v1.sh" + } +}