diff --git a/Plugin/unraid/include/config.php b/Plugin/unraid/include/config.php index e07252f..9a5af3f 100644 --- a/Plugin/unraid/include/config.php +++ b/Plugin/unraid/include/config.php @@ -154,12 +154,22 @@ function vv_resolve_tailscale_ip(string $hostname): string { $h = strtolower($hostname); $ip = trim(shell_exec('tailscale ip -4 ' . escapeshellarg($h) . ' 2>/dev/null') ?: ''); if ($ip) return $ip; + + // 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). $out = shell_exec('tailscale status 2>/dev/null') ?: ''; + $matches = []; foreach (explode("\n", $out) as $line) { $cols = preg_split('/\s+/', trim($line)); - if (isset($cols[1]) && stripos($cols[1], $h . '.') === 0) return $cols[0]; + if (!isset($cols[1])) continue; + $peerHost = strtolower(explode('.', $cols[1])[0]); + if (str_starts_with($peerHost, $h) || str_starts_with($h, $peerHost)) { + $matches[] = $cols[0]; + } } - return ''; + return count($matches) === 1 ? $matches[0] : ''; } function vv_detect_host(): string { @@ -174,12 +184,15 @@ function vv_detect_host(): string { // Unraid truncates the Server Name to 15 chars (NetBIOS limit). If the live hostname // is at that exact limit, the name configured in master.conf (matching what Tailscale // shows for this peer — resolve_tailscale_ip() keys off the same value) may be a longer, - // untruncated version. Treat a same-prefix match as this host rather than 'unknown'. + // untruncated version. Only accept the match when it's unambiguous — exactly one + // configured host may qualify; never guess between multiple prefix candidates. if (strlen($hostname) === 15) { + $candidates = []; foreach ($m[1] as $i => $key) { $configured = trim($m[2][$i]); - if (strlen($configured) > 15 && stripos($configured, $hostname) === 0) return strtolower($key); + if (strlen($configured) > 15 && stripos($configured, $hostname) === 0) $candidates[] = $key; } + if (count($candidates) === 1) return strtolower($candidates[0]); } return 'unknown'; } diff --git a/common.sh b/common.sh index 8a91141..464a618 100755 --- a/common.sh +++ b/common.sh @@ -462,12 +462,29 @@ detect_hosts() { for host_var in HOST1 HOST2 HOST3 HOST4 HOST5 HOST6 HOST7 HOST8; do host_val="${!host_var:-}" [[ -z "$host_val" ]] && continue - if [[ "$local_hostname" == "$host_val" ]]; then + if [[ "${local_hostname,,}" == "${host_val,,}" ]]; then MY_ID="$host_var" break fi done + # Unraid truncates the Server Name to 15 chars (NetBIOS limit). If the live hostname + # is at that exact limit, a configured HOST* value may be a longer, untruncated version + # (matching what Tailscale shows for this peer — resolve_tailscale_ip() keys off the same + # value). Only accept the match if it's unambiguous — exactly one HOST* may qualify. + if [[ -z "$MY_ID" && ${#local_hostname} -eq 15 ]]; then + local candidate="" candidate_count=0 + for host_var in HOST1 HOST2 HOST3 HOST4 HOST5 HOST6 HOST7 HOST8; do + host_val="${!host_var:-}" + [[ -z "$host_val" ]] && continue + if [[ ${#host_val} -gt 15 && "${host_val,,}" == "${local_hostname,,}"* ]]; then + candidate="$host_var" + (( candidate_count++ )) + fi + done + [[ "$candidate_count" -eq 1 ]] && MY_ID="$candidate" + fi + if [[ -z "$MY_ID" ]]; then error "Unknown host: $local_hostname" error "Hostname must match a HOST* value in host*.conf" @@ -780,9 +797,20 @@ resolve_tailscale_ip() { local hostname="${1,,}" local ip ip=$(tailscale ip -4 "$hostname" 2>/dev/null) - [[ -z "$ip" ]] && \ - ip=$(tailscale status 2>/dev/null | awk -v name="$hostname" '$2 ~ "^" name { print $1; exit }') - echo "$ip" + if [[ -n "$ip" ]]; then + echo "$ip" + 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" ' + { 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" } # Strips the "unraid-" prefix (case-insensitive) and title-cases what remains.