Fix Tailscale peer detection by parsing text output
All checks were successful
Build and Release / build-and-release (push) Successful in 1m13s

Replace JSON parsing with simpler text output parsing from tailscale
status command. The text format clearly shows hostname and connection
method (direct/relay/idle) making detection more reliable.

Fixes issues with incorrect hostname (localhost instead of actual name)
and incorrect connection method detection (showing relay when actually
using direct connection).
This commit is contained in:
Christoffer Martinsson 2025-12-09 10:34:55 +01:00
parent 5b1e39cfca
commit 8da4522d85
5 changed files with 46 additions and 48 deletions

6
Cargo.lock generated
View File

@ -279,7 +279,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "cm-dashboard"
version = "0.1.262"
version = "0.1.263"
dependencies = [
"anyhow",
"chrono",
@ -301,7 +301,7 @@ dependencies = [
[[package]]
name = "cm-dashboard-agent"
version = "0.1.262"
version = "0.1.263"
dependencies = [
"anyhow",
"async-trait",
@ -325,7 +325,7 @@ dependencies = [
[[package]]
name = "cm-dashboard-shared"
version = "0.1.262"
version = "0.1.263"
dependencies = [
"chrono",
"serde",

View File

@ -1,6 +1,6 @@
[package]
name = "cm-dashboard-agent"
version = "0.1.263"
version = "0.1.264"
edition = "2021"
[dependencies]

View File

@ -941,54 +941,52 @@ impl SystemdCollector {
/// Returns a list of (device_name, connection_method) tuples
fn get_tailscale_peers(&self) -> Vec<(String, String)> {
match Command::new("timeout")
.args(["2", "tailscale", "status", "--json"])
.args(["2", "tailscale", "status"])
.output()
{
Ok(output) if output.status.success() => {
let json_str = String::from_utf8_lossy(&output.stdout);
let status_output = String::from_utf8_lossy(&output.stdout);
let mut peers = Vec::new();
if let Ok(json_data) = serde_json::from_str::<serde_json::Value>(&json_str) {
// Look for the self peer (current node) in the peer list
if let Some(peer_map) = json_data["Peer"].as_object() {
// Iterate through all peers
for (_peer_id, peer_data) in peer_map {
// Only include active/online peers
if !peer_data["Online"].as_bool().unwrap_or(false) {
continue;
}
// Get peer hostname or DNS name
let peer_name = peer_data["HostName"]
.as_str()
.or_else(|| peer_data["DNSName"].as_str())
.unwrap_or("unknown")
.trim_end_matches('.')
.to_string();
// Determine connection method
let connection_method = if peer_data["Active"].as_bool().unwrap_or(false) {
// Check if using relay
let relay_node = peer_data["Relay"].as_str().unwrap_or("");
if !relay_node.is_empty() {
"relay"
} else if let Some(cur_addr) = peer_data["CurAddr"].as_str() {
// Check if using direct connection
if !cur_addr.is_empty() {
"direct"
} else {
"unknown"
}
} else {
"unknown"
}
} else {
"idle"
};
peers.push((peer_name, connection_method.to_string()));
}
// Parse tailscale status output
// Format: IP hostname user os status
// Example: 100.110.98.3 wslbox cm@ linux active; direct 192.168.30.227:53757
for line in status_output.lines() {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() < 5 {
continue; // Skip invalid lines
}
// parts[0] = IP
// parts[1] = hostname
// parts[2] = user
// parts[3] = OS
// parts[4+] = status (e.g., "active;", "direct", "192.168.30.227:53757" or "idle;" or "offline")
let hostname = parts[1];
let status_parts = &parts[4..];
// Determine connection method from status
let connection_method = if status_parts.is_empty() {
continue; // Skip if no status
} else {
let status_str = status_parts.join(" ");
if status_str.contains("offline") {
continue; // Skip offline peers
} else if status_str.contains("direct") {
"direct"
} else if status_str.contains("relay") {
"relay"
} else if status_str.contains("idle") {
"idle"
} else if status_str.contains("active") {
"active"
} else {
continue; // Skip unknown status
}
};
peers.push((hostname.to_string(), connection_method.to_string()));
}
peers

View File

@ -1,6 +1,6 @@
[package]
name = "cm-dashboard"
version = "0.1.263"
version = "0.1.264"
edition = "2021"
[dependencies]

View File

@ -1,6 +1,6 @@
[package]
name = "cm-dashboard-shared"
version = "0.1.263"
version = "0.1.264"
edition = "2021"
[dependencies]