Resolve a peer from tailscale status before falling back to DNS
MagicDNS does not work on this mesh, so `tailscale ip -4` missed and blocked on a system DNS lookup until it timed out: 5.04s per call against 0.010s for the status parse, paid by every mesh operation on both hosts. Exact match first, so no precision is traded for the speed.
This commit is contained in:
@@ -921,26 +921,48 @@ resolve_remote_ip() {
|
||||
info "$ICON_NET Remote IP: $REMOTE_SERVER"
|
||||
}
|
||||
|
||||
# Resolve any hostname to a Tailscale IPv4 — tries direct lookup, falls back to status parse.
|
||||
# Resolve any hostname to a Tailscale IPv4 — status parse first, DNS as a bounded last resort.
|
||||
# Usage: ip=$(resolve_tailscale_ip "hostname") — returns empty string on failure.
|
||||
#
|
||||
# `tailscale ip -4` used to be tried first, because Tailscale owns the mapping. It also resolves
|
||||
# through MagicDNS, which does not work on this mesh — the two hosts are on separate tailnets
|
||||
# shared into each other — so the name misses and the call blocks on a system DNS lookup until it
|
||||
# times out. Five seconds, every call, on every rsync, partnership check and remote collector.
|
||||
# The status parse costs ten milliseconds and carries the same mapping.
|
||||
#
|
||||
# Exactness is not traded away for the speed: an exact name match against `tailscale status` is as
|
||||
# precise as the lookup it replaces. The prefix match keeps its ambiguity guard, and the DNS path
|
||||
# still runs — bounded, and only when status cannot decide.
|
||||
#
|
||||
# Mirror of vv_resolve_tailscale_ip() in Plugin/unraid/include/config.php; the two must agree.
|
||||
resolve_tailscale_ip() {
|
||||
local hostname="${1,,}"
|
||||
local ip
|
||||
ip=$(tailscale ip -4 "$hostname" 2>/dev/null)
|
||||
if [[ -n "$ip" ]]; then
|
||||
echo "$ip"
|
||||
local status_out exact matches count ip
|
||||
|
||||
status_out=$(tailscale status 2>/dev/null)
|
||||
|
||||
exact=$(echo "$status_out" | awk -v name="$hostname" '
|
||||
{ split(tolower($2), parts, "."); if (parts[1] == name) { print $1; exit } }')
|
||||
if [[ -n "$exact" ]]; then
|
||||
echo "$exact"
|
||||
return
|
||||
fi
|
||||
# Fallback: unambiguous prefix match against tailscale status (either direction) — handles
|
||||
# Unraid's 15-char NetBIOS hostname truncation vs. a longer name recorded in master.conf.
|
||||
# Only accept the match when exactly one peer could qualify; never guess between multiple
|
||||
# candidates that happen to share a prefix (e.g. server1/server10).
|
||||
local matches count
|
||||
matches=$(tailscale status 2>/dev/null | awk -v name="$hostname" '
|
||||
|
||||
# Unambiguous prefix match, either direction — handles Unraid's 15-char NetBIOS hostname
|
||||
# truncation vs. a longer name recorded in master.conf. Only accept the match when exactly one
|
||||
# peer could qualify; never guess between candidates that share a prefix (server1/server10).
|
||||
matches=$(echo "$status_out" | awk -v name="$hostname" '
|
||||
{ split(tolower($2), parts, "."); host = parts[1];
|
||||
if (index(host, name) == 1 || index(name, host) == 1) print $1 }')
|
||||
count=$(echo "$matches" | grep -c .)
|
||||
[[ "$count" -eq 1 ]] && echo "$matches"
|
||||
if [[ "$count" -eq 1 ]]; then
|
||||
echo "$matches"
|
||||
return
|
||||
fi
|
||||
|
||||
# Last resort, and the slow one. Bounded so a broken MagicDNS costs two seconds, not five.
|
||||
ip=$(timeout 2 tailscale ip -4 "$hostname" 2>/dev/null)
|
||||
[[ -n "$ip" ]] && echo "$ip"
|
||||
}
|
||||
|
||||
# Strips the "unraid-" prefix (case-insensitive) and title-cases what remains.
|
||||
|
||||
Reference in New Issue
Block a user