ddns-scripts: refactor verify_host_port()
authorPaul Donald <[email protected]>
Fri, 11 Apr 2025 13:32:47 +0000 (15:32 +0200)
committerFlorian Eckert <[email protected]>
Wed, 25 Jun 2025 13:40:21 +0000 (15:40 +0200)
Leverage the resolveip utility - it does the same job that several
different resolvers do for a fraction of the resource usage. This...
to verify a host's connectivity.

resolveip dependency net delta: +2-3Kbytes

Also uses the ddns-scripts built-in 'timeout' function.

Signed-off-by: Paul Donald <[email protected]>
net/ddns-scripts/Makefile
net/ddns-scripts/files/usr/lib/ddns/dynamic_dns_functions.sh

index d6a6fe3ab6a7a35f85466d9597ea1576b821b203..d5f882c2d5c09d1e66579f4a28297222c7c04c57 100644 (file)
@@ -25,7 +25,7 @@ endef
 define Package/ddns-scripts
   $(call Package/ddns-scripts/Default)
   TITLE:=Dynamic DNS Client scripts (with IPv6 support)
-  DEPENDS:=+ddns-scripts-services
+  DEPENDS:=+ddns-scripts-services +resolveip
 endef
 
 define Package/ddns-scripts/description
index f8d0a6675bf464561193b783e8f43e1ee5af891e..ebafb629bc25f2f72ee8071c026d1b2b90525102 100644 (file)
@@ -86,6 +86,7 @@ KNOT_HOST=$(command -v khost)
 DRILL=$(command -v drill)
 HOSTIP=$(command -v hostip)
 NSLOOKUP=$(command -v nslookup)
+RESOLVEIP=$(command -v resolveip)
 
 # Transfer Programs
 WGET=$(command -v wget)
@@ -487,117 +488,66 @@ sanitize_variable() {
        fi
 }
 
-# verify given host and port is connectable
-# $1   Host/IP to verify
-# $2   Port to verify
+# Verify host and port connectivity
+# $1: Host/IP
+# $2: Port
 verify_host_port() {
-       local __HOST=$1
-       local __PORT=$2
-       local __NC=$(command -v nc)
-       local __NCEXT=$($(command -v nc) --help 2>&1 | grep "\-w" 2>/dev/null)  # busybox nc compiled with extensions
-       local __IP __IPV4 __IPV6 __RUNPROG __PROG __ERR
        # return codes
        # 1     system specific error
        # 2     nslookup/host error
        # 3     nc (netcat) error
        # 4     unmatched IP version
+       local host port ipv4 ipv6 nc_cmd err_code
+       host=$1
+       port=$2
+       nc_cmd=$(command -v nc)
+       err_code=0
+
+       # Validate input parameters
+       [ $# -ne 2 ] && { write_log 12 "Error: verify_host_port() requires exactly 2 arguments"; return 1; }
+
+       # Resolve IP address
+       ipv4=$("$RESOLVEIP" -4 "$host")
+       ipv6=$("$RESOLVEIP" -6 "$host")
+       if [ -z "$ipv4" ] && [ -z "$ipv6" ]; then
+               write_log 3 "Failed to resolve any IPv4/6 for host: $host"
+               return 2
+       fi
 
-       [ $# -ne 2 ] && write_log 12 "Error calling 'verify_host_port()' - wrong number of parameters"
-
-       # check if ip or FQDN was given
-       __IPV4=$(echo $__HOST | grep -m 1 -o "$IPV4_REGEX$")    # do not detect ip in 0.0.0.0.example.com
-       __IPV6=$(echo $__HOST | grep -m 1 -o "$IPV6_REGEX")
-       # if FQDN given get IP address
-       [ -z "$__IPV4" -a -z "$__IPV6" ] && {
-               if [ -n "$BIND_HOST" ]; then    # use BIND host if installed
-                       __PROG="BIND host"
-                       __RUNPROG="$BIND_HOST $__HOST >$DATFILE 2>$ERRFILE"
-               elif [ -n "$KNOT_HOST" ]; then  # use Knot host if installed
-                       __PROG="Knot host"
-                       __RUNPROG="$KNOT_HOST $__HOST >$DATFILE 2>$ERRFILE"
-               elif [ -n "$DRILL" ]; then      # use drill if installed
-                       __PROG="drill"
-                       __RUNPROG="$DRILL -V0 $__HOST A >$DATFILE 2>$ERRFILE"                   # IPv4
-                       __RUNPROG="$__RUNPROG; $DRILL -V0 $__HOST AAAA >>$DATFILE 2>>$ERRFILE"  # IPv6
-               elif [ -n "$HOSTIP" ]; then     # use hostip if installed
-                       __PROG="hostip"
-                       __RUNPROG="$HOSTIP $__HOST >$DATFILE 2>$ERRFILE"                        # IPv4
-                       __RUNPROG="$__RUNPROG; $HOSTIP -6 $__HOST >>$DATFILE 2>>$ERRFILE"       # IPv6
-               else    # use BusyBox nslookup
-                       __PROG="BusyBox nslookup"
-                       __RUNPROG="$NSLOOKUP $__HOST >$DATFILE 2>$ERRFILE"
-               fi
-               write_log 7 "#> $__RUNPROG"
-               eval $__RUNPROG
-               __ERR=$?
-               # command error
-               [ $__ERR -gt 0 ] && {
-                       write_log 3 "DNS Resolver Error - $__PROG Error '$__ERR'"
-                       write_log 7 "$(cat $ERRFILE)"
-                       return 2
+       # check for forced IP version inconsistency
+       if [ "$force_ipversion" != 0 ]; then 
+               [ "$use_ipv6" = 0 ] && [ -z "$ipv4" ] && err_code=4
+               [ "$use_ipv6" = 1 ] && [ -z "$ipv6" ] && err_code=6
+               [ $err_code -gt 0 ] && {
+                       [ -n "$LUCI_HELPER" ] && write_log 14 "Error: verify_host_port(): no usable IP for the IP family that was forced"
+                       return 4
                }
-               # extract IP address
-               if [ -n "$BIND_HOST" ]; then    # use BIND host if installed
-                       __IPV4="$(awk -F "address " '/has address/ {print $2; exit}' "$DATFILE")"
-                       __IPV6="$(awk -F "address " '/has IPv6/ {print $2; exit}' "$DATFILE")"
-               elif [ -n "$KNOT_HOST" ]; then  # use Knot host if installed
-                       __IPV4="$(awk -F "address " '/has IPv4/ {print $2; exit}' "$DATFILE")"
-                       __IPV6="$(awk -F "address " '/has IPv6/ {print $2; exit}' "$DATFILE")"
-               elif [ -n "$DRILL" ]; then      # use drill if installed
-                       __IPV4="$(awk '/^'"$__HOST"'/ {print $5}' "$DATFILE" | grep -m 1 -o "$IPV4_REGEX")"
-                       __IPV6="$(awk '/^'"$__HOST"'/ {print $5}' "$DATFILE" | grep -m 1 -o "$IPV6_REGEX")"
-               elif [ -n "$HOSTIP" ]; then     # use hostip if installed
-                       __IPV4="$(grep -m 1 -o "$IPV4_REGEX" "$DATFILE")"
-                       __IPV6="$(grep -m 1 -o "$IPV6_REGEX" "$DATFILE")"
-               else    # use BusyBox nslookup
-                       __IPV4="$(sed -ne "/^Name:/,\$ { s/^Address[0-9 ]\{0,\}: \($IPV4_REGEX\).*$/\\1/p }" "$DATFILE")"
-                       __IPV6="$(sed -ne "/^Name:/,\$ { s/^Address[0-9 ]\{0,\}: \($IPV6_REGEX\).*$/\\1/p }" "$DATFILE")"
+       fi
+
+       # Check connectivity using nc
+       if [ -n "$nc_cmd" ]; then
+               write_log 7 "#> $RESOLVEIP"
+               if [ -n "$ipv4" ]; then
+                       timeout 3 "$nc_cmd" "$ipv4" "$port" >/dev/null 2>&1
+               else
+                       timeout 3 "$nc_cmd" "$ipv6" "$port" >/dev/null 2>&1
                fi
-       }
+               err_code=$?
+               if [ $err_code -eq 0 ]; then
 
-       # check IP version if forced
-       if [ $force_ipversion -ne 0 ]; then
-               __ERR=0
-               [ $use_ipv6 -eq 0 -a -z "$__IPV4" ] && __ERR=4
-               [ $use_ipv6 -eq 1 -a -z "$__IPV6" ] && __ERR=6
-               [ $__ERR -gt 0 ] && {
-                       [ -n "$LUCI_HELPER" ] && return 4
-                       write_log 14 "Verify host Error '4' - Forced IP Version IPv$__ERR don't match"
-               }
-       fi
+                       write_log 7 "Successfully connected to $host:$port"
+                       return 0
 
-       # verify nc command
-       # busybox nc compiled without -l option "NO OPT l!" -> critical error
-       $__NC --help 2>&1 | grep -i "NO OPT l!" >/dev/null 2>&1 && \
-               write_log 12 "Busybox nc (netcat) compiled without '-l' option, error 'NO OPT l!'"
-       # busybox nc compiled with extensions
-       $__NC --help 2>&1 | grep "\-w" >/dev/null 2>&1 && __NCEXT="TRUE"
-
-       # connectivity test
-       # run busybox nc to HOST PORT
-       # busybox might be compiled with "FEATURE_PREFER_IPV4_ADDRESS=n"
-       # then nc will try to connect via IPv6 if there is any IPv6 available on any host interface
-       # not worrying, if there is an IPv6 wan address
-       # so if not "force_ipversion" to use_ipv6 then connect test via ipv4, if available
-       [ $force_ipversion -ne 0 -a $use_ipv6 -ne 0 -o -z "$__IPV4" ] && __IP=$__IPV6 || __IP=$__IPV4
-
-       if [ -n "$__NCEXT" ]; then      # BusyBox nc compiled with extensions (timeout support)
-               __RUNPROG="$__NC -w 1 $__IP $__PORT </dev/null >$DATFILE 2>$ERRFILE"
-               write_log 7 "#> $__RUNPROG"
-               eval $__RUNPROG
-               __ERR=$?
-               [ $__ERR -eq 0 ] && return 0
-               write_log 3 "Connect error - BusyBox nc (netcat) Error '$__ERR'"
-               write_log 7 "$(cat $ERRFILE)"
-               return 3
-       else            # nc compiled without extensions (no timeout support)
-               __RUNPROG="timeout 2 -- $__NC $__IP $__PORT </dev/null >$DATFILE 2>$ERRFILE"
-               write_log 7 "#> $__RUNPROG"
-               eval $__RUNPROG
-               __ERR=$?
-               [ $__ERR -eq 0 ] && return 0
-               write_log 3 "Connect error - BusyBox nc (netcat) timeout Error '$__ERR'"
-               return 3
+               else
+
+                       write_log 3 "DNS Resolver Error - $RESOLVEIP (Error: $err_code)"
+                       write_log 7 "$(cat "$ERRFILE")"
+                       return 3
+
+               fi
+       else
+               write_log 3 "Netcat (nc) command not found."
+               return 1
        fi
 }