From 04b9f0980e657068db96f87dc8fb5417dea10174 Mon Sep 17 00:00:00 2001 From: Tom DNetto Date: Thu, 7 Apr 2022 11:42:48 -0700 Subject: [PATCH] hostinfo, tailcfg: add desktop detection on Linux to hostinfo From the machines tab its hard to differenciate desktop Linux installs from server Linux installs. Transmitting this information should make this determination a lot easier. Due to the reality that tailscaled is likely a system process, the standard checks based on XDG_SESSION_TYPE or DISPLAY environment variables are not possible (those variables won't be set). Instead, we look for listening unix sockets that are typical of desktop installs. Signed-off-by: Tom DNetto --- hostinfo/hostinfo.go | 10 ++++++++++ hostinfo/hostinfo_linux.go | 21 +++++++++++++++++++++ tailcfg/tailcfg.go | 1 + tailcfg/tailcfg_clone.go | 1 + tailcfg/tailcfg_test.go | 2 +- 5 files changed, 34 insertions(+), 1 deletion(-) diff --git a/hostinfo/hostinfo.go b/hostinfo/hostinfo.go index 50ce6c8966b57..2a855aaa6e7c2 100644 --- a/hostinfo/hostinfo.go +++ b/hostinfo/hostinfo.go @@ -31,6 +31,7 @@ func New() *tailcfg.Hostinfo { Hostname: hostname, OS: version.OS(), OSVersion: GetOSVersion(), + Desktop: desktop(), Package: packageTypeCached(), GoArch: runtime.GOARCH, DeviceModel: deviceModel(), @@ -97,6 +98,7 @@ func GetEnvType() EnvType { var ( deviceModelAtomic atomic.Value // of string osVersionAtomic atomic.Value // of string + desktopAtomic atomic.Value // of bool packagingType atomic.Value // of string ) @@ -106,6 +108,9 @@ func SetDeviceModel(model string) { deviceModelAtomic.Store(model) } // SetOSVersion sets the OS version. func SetOSVersion(v string) { osVersionAtomic.Store(v) } +// SetDesktop sets the desktop for use in HostInfo updates. +func SetDesktop(d bool) { desktopAtomic.Store(d) } + // SetPackage sets the packaging type for the app. // // As of 2022-03-25, this is used by Android ("nogoogle" for the @@ -117,6 +122,11 @@ func deviceModel() string { return s } +func desktop() bool { + s, _ := desktopAtomic.Load().(bool) + return s +} + func getEnvType() EnvType { if inKnative() { return KNative diff --git a/hostinfo/hostinfo_linux.go b/hostinfo/hostinfo_linux.go index 90ceece908147..e4aa1c9aa6bca 100644 --- a/hostinfo/hostinfo_linux.go +++ b/hostinfo/hostinfo_linux.go @@ -26,6 +26,27 @@ func init() { if v := linuxDeviceModel(); v != "" { SetDeviceModel(v) } + SetDesktop(linuxDesktop()) +} + +// linuxDesktop attempts to detect the class of desktop being used by the +// system, if any. Given that tailscaled is likely to be run as a system +// service, the usual environment-variable checks are not possible. Instead, +// we look for unix sockets typical of a desktop Linux setup. +func linuxDesktop() bool { + seenDesktop := false + + err := lineread.File("/proc/net/unix", func(line []byte) error { + seenDesktop = seenDesktop || strings.Contains(string(line), " @/tmp/dbus-") + seenDesktop = seenDesktop || strings.Contains(string(line), ".X11-unix") + seenDesktop = seenDesktop || strings.Contains(string(line), "/wayland-1") + return nil + }) + if err != nil { + return false + } + + return seenDesktop } func linuxDeviceModel() string { diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index c6b556d69278f..7aab7566e7429 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -460,6 +460,7 @@ type Hostinfo struct { BackendLogID string `json:",omitempty"` // logtail ID of backend instance OS string `json:",omitempty"` // operating system the client runs on (a version.OS value) OSVersion string `json:",omitempty"` // operating system version, with optional distro prefix ("Debian 10.4", "Windows 10 Pro 10.0.19041") + Desktop bool `json:",omitempty"` // if a desktop was detected on Linux Package string `json:",omitempty"` // Tailscale package to disambiguate ("choco", "appstore", etc; "" for unknown) DeviceModel string `json:",omitempty"` // mobile phone model ("Pixel 3a", "iPhone12,3") Hostname string `json:",omitempty"` // name of the host the client runs on diff --git a/tailcfg/tailcfg_clone.go b/tailcfg/tailcfg_clone.go index b1a3572ba4104..6f532edc27300 100644 --- a/tailcfg/tailcfg_clone.go +++ b/tailcfg/tailcfg_clone.go @@ -117,6 +117,7 @@ var _HostinfoCloneNeedsRegeneration = Hostinfo(struct { BackendLogID string OS string OSVersion string + Desktop bool Package string DeviceModel string Hostname string diff --git a/tailcfg/tailcfg_test.go b/tailcfg/tailcfg_test.go index 6d580064b8981..e5135a407a086 100644 --- a/tailcfg/tailcfg_test.go +++ b/tailcfg/tailcfg_test.go @@ -28,7 +28,7 @@ func fieldsOf(t reflect.Type) (fields []string) { func TestHostinfoEqual(t *testing.T) { hiHandles := []string{ "IPNVersion", "FrontendLogID", "BackendLogID", - "OS", "OSVersion", "Package", "DeviceModel", "Hostname", + "OS", "OSVersion", "Desktop", "Package", "DeviceModel", "Hostname", "ShieldsUp", "ShareeNode", "GoArch", "RoutableIPs", "RequestTags",