From: bdk38 Date: Mon, 16 Feb 2026 12:49:45 +0000 (-0800) Subject: ddns-scripts: add API-based registered IP verification for Cloudflare proxied X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=f901d88ea4790add8bde39d969079871f252b096;p=openwrt-packages.git ddns-scripts: add API-based registered IP verification for Cloudflare proxied records Problem: When using Cloudflare with proxy enabled (orange cloud), DNS lookups return Cloudflare's edge IP instead of the actual origin IP registered in the dashboard. This causes ddns-scripts to incorrectly detect IP mismatches, triggering unnecessary updates and potential rate limiting. Solution: Add an optional 'use_api_check' configuration option that enables provider scripts to fetch the registered IP directly via their API, bypassing DNS lookups. Changes: - dynamic_dns_functions.sh: Add API check block to get_registered_ip() (~25 lines). When use_api_check is enabled, sources the provider script with GET_REGISTERED_IP=1 flag. Falls back to DNS lookup if API check is disabled, unsupported, or fails. - update_cloudflare_com_v4.sh: Add handler for GET_REGISTERED_IP mode (~15 lines). Reuses existing cURL setup and authentication to query Cloudflare API for actual record content. - etc/config/ddns: Document use_api_check option Behavior: - use_api_check=0 or unset: DNS lookup (existing behavior, no changes) - use_api_check=1 with API support: API query for registered IP - use_api_check=1 without API support: Falls back to DNS lookup - API failure: Gracefully falls back to DNS lookup Testing: - Cloudflare (proxied): Correctly retrieves origin IP via API - Cloudflare (non-proxied): Works correctly - No-IP: DNS lookup works (no regression) - IPv4 and IPv6 records tested - API failure gracefully falls back to DNS Signed-off-by: Wayne King 244781262+bdk38@users.noreply.github.com --- diff --git a/net/ddns-scripts/Makefile b/net/ddns-scripts/Makefile index 020c98229..db405263e 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:=91 +PKG_RELEASE:=92 PKG_LICENSE:=GPL-2.0 diff --git a/net/ddns-scripts/files/etc/config/ddns b/net/ddns-scripts/files/etc/config/ddns index b45855f0d..94bda2655 100644 --- a/net/ddns-scripts/files/etc/config/ddns +++ b/net/ddns-scripts/files/etc/config/ddns @@ -18,6 +18,7 @@ config service "myddns_ipv4" option interface "wan" option ip_source "network" option ip_network "wan" + option use_api_check "0" config service "myddns_ipv6" option update_url "http://[USERNAME]:[PASSWORD]@your.provider.net/nic/update?hostname=[DOMAIN]&myip=[IP]" @@ -29,4 +30,4 @@ config service "myddns_ipv6" option interface "wan6" option ip_source "network" option ip_network "wan6" - + option use_api_check "0" diff --git a/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_functions.sh b/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_functions.sh index 5afa5547c..c07a85974 100644 --- a/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_functions.sh +++ b/net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_functions.sh @@ -8,6 +8,9 @@ # extended and partial rewritten #.2014-2018 Christian Schoenebeck # +# 2026 Wayne King +# Added use_api_check option for providers with proxied records (e.g., Cloudflare) +# # function timeout # copied from http://www.ict.griffith.edu.au/anthony/software/timeout.sh # @author Anthony Thyssen 6 April 2011 @@ -985,9 +988,40 @@ get_registered_ip() { [ $is_glue -eq 1 -a -z "$BIND_HOST" ] && write_log 14 "Lookup of glue records is only supported using BIND host" write_log 7 "Detect registered/public IP" + # Ensure use_api_check defaults to 0 if not set + [ -z "$use_api_check" ] && use_api_check=0 + # set correct regular expression [ $use_ipv6 -eq 0 ] && __REGEX="$IPV4_REGEX" || __REGEX="$IPV6_REGEX" + # Attempt API check if enabled + if [ "$use_api_check" -eq 1 ]; then + local __SCRIPT + if [ -n "$update_script" ]; then + __SCRIPT="$update_script" + elif [ "$service_name" != "custom" ] && [ -n "$service_name" ]; then + local __SANITIZED + __SANITIZED=$(echo "$service_name" | sed 's/[.-]/_/g') + __SCRIPT="/usr/lib/ddns/update_${__SANITIZED}.sh" + fi + if [ -n "$__SCRIPT" ] && [ -f "$__SCRIPT" ]; then + write_log 7 "Using provider API for registered IP check via '$__SCRIPT'" + REGISTERED_IP="" + GET_REGISTERED_IP=1 + . "$__SCRIPT" + __ERR=$? + unset GET_REGISTERED_IP + if [ $__ERR -eq 0 ] && [ -n "$REGISTERED_IP" ]; then + write_log 7 "Registered IP '$REGISTERED_IP' detected via provider API" + [ -z "$IPFILE" ] || echo "$REGISTERED_IP" > "$IPFILE" + eval "$1=\"$REGISTERED_IP\"" + return 0 + else + write_log 4 "API check failed (error: '$__ERR') - falling back to DNS lookup" + fi + fi + fi + if [ -n "$BIND_HOST" ]; then __PROG="$BIND_HOST" [ $use_ipv6 -eq 0 ] && __PROG="$__PROG -t A" || __PROG="$__PROG -t AAAA" diff --git a/net/ddns-scripts/files/usr/lib/ddns/update_cloudflare_com_v4.sh b/net/ddns-scripts/files/usr/lib/ddns/update_cloudflare_com_v4.sh index b88672c12..e469b599f 100644 --- a/net/ddns-scripts/files/usr/lib/ddns/update_cloudflare_com_v4.sh +++ b/net/ddns-scripts/files/usr/lib/ddns/update_cloudflare_com_v4.sh @@ -6,6 +6,10 @@ #.based on Ben Kulbertis cloudflare-update-record.sh found at http://gist.github.com/benkulbertis #.and on George Johnson's cf-ddns.sh found at https://github.com/gstuartj/cf-ddns.sh #.2016-2018 Christian Schoenebeck +# +# 2026 Wayne King +# Added GET_REGISTERED_IP mode to retrieve the actual backend IP from Cloudflare API +# (DNS lookups return Cloudflare's proxy IP, not the actual registered IP) # CloudFlare API documentation, section DNS at https://developers.cloudflare.com/api/resources/dns/ # # This script is parsed by dynamic_dns_functions.sh inside send_update() function @@ -214,6 +218,22 @@ else } fi +# Check if we are being called for GET_REGISTERED_IP mode +# This is set by get_registered_ip() in dynamic_dns_functions.sh +if [ -n "$GET_REGISTERED_IP" ]; then + __RUNPROG="$__PRGBASE --request GET '$__URLBASE/zones/$__ZONEID/dns_records/$__RECID'" + cloudflare_transfer || return 1 + __DATA=$(jsonfilter -i "$DATFILE" -e "@.result.content" 2>/dev/null) + if [ -n "$__DATA" ]; then + write_log 7 "Registered IP '$__DATA' detected via Cloudflare API" + REGISTERED_IP="$__DATA" + return 0 + else + write_log 4 "Could not extract IP from Cloudflare API response" + return 127 + fi +fi + # If dns_record_id is specified, grab the stored IP for that specific record # So that the IP checking behavior below works even for domains with multiple IPs if [ -n "$dns_record_id" ]; then