Update dependencies
This commit is contained in:
482
vendor/tailscale.com/hostinfo/hostinfo.go
generated
vendored
Normal file
482
vendor/tailscale.com/hostinfo/hostinfo.go
generated
vendored
Normal file
@@ -0,0 +1,482 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package hostinfo answers questions about the host environment that Tailscale is
|
||||
// running on.
|
||||
package hostinfo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go4.org/mem"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/opt"
|
||||
"tailscale.com/types/ptr"
|
||||
"tailscale.com/util/cloudenv"
|
||||
"tailscale.com/util/dnsname"
|
||||
"tailscale.com/util/lineread"
|
||||
"tailscale.com/version"
|
||||
"tailscale.com/version/distro"
|
||||
)
|
||||
|
||||
var started = time.Now()
|
||||
|
||||
// New returns a partially populated Hostinfo for the current host.
|
||||
func New() *tailcfg.Hostinfo {
|
||||
hostname, _ := os.Hostname()
|
||||
hostname = dnsname.FirstLabel(hostname)
|
||||
return &tailcfg.Hostinfo{
|
||||
IPNVersion: version.Long(),
|
||||
Hostname: hostname,
|
||||
App: appTypeCached(),
|
||||
OS: version.OS(),
|
||||
OSVersion: GetOSVersion(),
|
||||
Container: lazyInContainer.Get(),
|
||||
Distro: condCall(distroName),
|
||||
DistroVersion: condCall(distroVersion),
|
||||
DistroCodeName: condCall(distroCodeName),
|
||||
Env: string(GetEnvType()),
|
||||
Desktop: desktop(),
|
||||
Package: packageTypeCached(),
|
||||
GoArch: runtime.GOARCH,
|
||||
GoArchVar: lazyGoArchVar.Get(),
|
||||
GoVersion: runtime.Version(),
|
||||
Machine: condCall(unameMachine),
|
||||
DeviceModel: deviceModelCached(),
|
||||
Cloud: string(cloudenv.Get()),
|
||||
NoLogsNoSupport: envknob.NoLogsNoSupport(),
|
||||
AllowsUpdate: envknob.AllowsRemoteUpdate(),
|
||||
WoLMACs: getWoLMACs(),
|
||||
}
|
||||
}
|
||||
|
||||
// non-nil on some platforms
|
||||
var (
|
||||
osVersion func() string
|
||||
packageType func() string
|
||||
distroName func() string
|
||||
distroVersion func() string
|
||||
distroCodeName func() string
|
||||
unameMachine func() string
|
||||
deviceModel func() string
|
||||
)
|
||||
|
||||
func condCall[T any](fn func() T) T {
|
||||
var zero T
|
||||
if fn == nil {
|
||||
return zero
|
||||
}
|
||||
return fn()
|
||||
}
|
||||
|
||||
var (
|
||||
lazyInContainer = &lazyAtomicValue[opt.Bool]{f: ptr.To(inContainer)}
|
||||
lazyGoArchVar = &lazyAtomicValue[string]{f: ptr.To(goArchVar)}
|
||||
)
|
||||
|
||||
type lazyAtomicValue[T any] struct {
|
||||
// f is a pointer to a fill function. If it's nil or points
|
||||
// to nil, then Get returns the zero value for T.
|
||||
f *func() T
|
||||
|
||||
once sync.Once
|
||||
v T
|
||||
}
|
||||
|
||||
func (v *lazyAtomicValue[T]) Get() T {
|
||||
v.once.Do(v.fill)
|
||||
return v.v
|
||||
}
|
||||
|
||||
func (v *lazyAtomicValue[T]) fill() {
|
||||
if v.f == nil || *v.f == nil {
|
||||
return
|
||||
}
|
||||
v.v = (*v.f)()
|
||||
}
|
||||
|
||||
// GetOSVersion returns the OSVersion of current host if available.
|
||||
func GetOSVersion() string {
|
||||
if s, _ := osVersionAtomic.Load().(string); s != "" {
|
||||
return s
|
||||
}
|
||||
if osVersion != nil {
|
||||
return osVersion()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func appTypeCached() string {
|
||||
if v, ok := appType.Load().(string); ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func packageTypeCached() string {
|
||||
if v, _ := packagingType.Load().(string); v != "" {
|
||||
return v
|
||||
}
|
||||
if packageType == nil {
|
||||
return ""
|
||||
}
|
||||
v := packageType()
|
||||
if v != "" {
|
||||
SetPackage(v)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// EnvType represents a known environment type.
|
||||
// The empty string, the default, means unknown.
|
||||
type EnvType string
|
||||
|
||||
const (
|
||||
KNative = EnvType("kn")
|
||||
AWSLambda = EnvType("lm")
|
||||
Heroku = EnvType("hr")
|
||||
AzureAppService = EnvType("az")
|
||||
AWSFargate = EnvType("fg")
|
||||
FlyDotIo = EnvType("fly")
|
||||
Kubernetes = EnvType("k8s")
|
||||
DockerDesktop = EnvType("dde")
|
||||
Replit = EnvType("repl")
|
||||
HomeAssistantAddOn = EnvType("haao")
|
||||
)
|
||||
|
||||
var envType atomic.Value // of EnvType
|
||||
|
||||
func GetEnvType() EnvType {
|
||||
if e, ok := envType.Load().(EnvType); ok {
|
||||
return e
|
||||
}
|
||||
e := getEnvType()
|
||||
envType.Store(e)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
deviceModelAtomic atomic.Value // of string
|
||||
osVersionAtomic atomic.Value // of string
|
||||
desktopAtomic atomic.Value // of opt.Bool
|
||||
packagingType atomic.Value // of string
|
||||
appType atomic.Value // of string
|
||||
firewallMode atomic.Value // of string
|
||||
)
|
||||
|
||||
// SetDeviceModel sets the device model for use in Hostinfo updates.
|
||||
func SetDeviceModel(model string) { deviceModelAtomic.Store(model) }
|
||||
|
||||
func deviceModelCached() string {
|
||||
if v, _ := deviceModelAtomic.Load().(string); v != "" {
|
||||
return v
|
||||
}
|
||||
if deviceModel == nil {
|
||||
return ""
|
||||
}
|
||||
v := deviceModel()
|
||||
if v != "" {
|
||||
deviceModelAtomic.Store(v)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// SetOSVersion sets the OS version.
|
||||
func SetOSVersion(v string) { osVersionAtomic.Store(v) }
|
||||
|
||||
// SetFirewallMode sets the firewall mode for the app.
|
||||
func SetFirewallMode(v string) { firewallMode.Store(v) }
|
||||
|
||||
// SetPackage sets the packaging type for the app.
|
||||
//
|
||||
// For Android, the possible values are:
|
||||
// - "googleplay": installed from Google Play Store.
|
||||
// - "fdroid": installed from the F-Droid repository.
|
||||
// - "amazon": installed from the Amazon Appstore.
|
||||
// - "unknown": when the installer package name is null.
|
||||
// - "unknown$installerPackageName": for unrecognized installer package names, prefixed by "unknown".
|
||||
// Additionally, tsnet sets this value to "tsnet".
|
||||
func SetPackage(v string) { packagingType.Store(v) }
|
||||
|
||||
// SetApp sets the app type for the app.
|
||||
// It is used by tsnet to specify what app is using it such as "golinks"
|
||||
// and "k8s-operator".
|
||||
func SetApp(v string) { appType.Store(v) }
|
||||
|
||||
// FirewallMode returns the firewall mode for the app.
|
||||
// It is empty if unset.
|
||||
func FirewallMode() string {
|
||||
s, _ := firewallMode.Load().(string)
|
||||
return s
|
||||
}
|
||||
|
||||
func desktop() (ret opt.Bool) {
|
||||
if runtime.GOOS != "linux" {
|
||||
return opt.Bool("")
|
||||
}
|
||||
if v := desktopAtomic.Load(); v != nil {
|
||||
v, _ := v.(opt.Bool)
|
||||
return v
|
||||
}
|
||||
|
||||
seenDesktop := false
|
||||
lineread.File("/proc/net/unix", func(line []byte) error {
|
||||
seenDesktop = seenDesktop || mem.Contains(mem.B(line), mem.S(" @/tmp/dbus-"))
|
||||
seenDesktop = seenDesktop || mem.Contains(mem.B(line), mem.S(".X11-unix"))
|
||||
seenDesktop = seenDesktop || mem.Contains(mem.B(line), mem.S("/wayland-1"))
|
||||
return nil
|
||||
})
|
||||
ret.Set(seenDesktop)
|
||||
|
||||
// Only cache after a minute - compositors might not have started yet.
|
||||
if time.Since(started) > time.Minute {
|
||||
desktopAtomic.Store(ret)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func getEnvType() EnvType {
|
||||
if inKnative() {
|
||||
return KNative
|
||||
}
|
||||
if inAWSLambda() {
|
||||
return AWSLambda
|
||||
}
|
||||
if inHerokuDyno() {
|
||||
return Heroku
|
||||
}
|
||||
if inAzureAppService() {
|
||||
return AzureAppService
|
||||
}
|
||||
if inAWSFargate() {
|
||||
return AWSFargate
|
||||
}
|
||||
if inFlyDotIo() {
|
||||
return FlyDotIo
|
||||
}
|
||||
if inKubernetes() {
|
||||
return Kubernetes
|
||||
}
|
||||
if inDockerDesktop() {
|
||||
return DockerDesktop
|
||||
}
|
||||
if inReplit() {
|
||||
return Replit
|
||||
}
|
||||
if inHomeAssistantAddOn() {
|
||||
return HomeAssistantAddOn
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// inContainer reports whether we're running in a container.
|
||||
func inContainer() opt.Bool {
|
||||
if runtime.GOOS != "linux" {
|
||||
return ""
|
||||
}
|
||||
var ret opt.Bool
|
||||
ret.Set(false)
|
||||
if _, err := os.Stat("/.dockerenv"); err == nil {
|
||||
ret.Set(true)
|
||||
return ret
|
||||
}
|
||||
if _, err := os.Stat("/run/.containerenv"); err == nil {
|
||||
// See https://github.com/cri-o/cri-o/issues/5461
|
||||
ret.Set(true)
|
||||
return ret
|
||||
}
|
||||
lineread.File("/proc/1/cgroup", func(line []byte) error {
|
||||
if mem.Contains(mem.B(line), mem.S("/docker/")) ||
|
||||
mem.Contains(mem.B(line), mem.S("/lxc/")) {
|
||||
ret.Set(true)
|
||||
return io.EOF // arbitrary non-nil error to stop loop
|
||||
}
|
||||
return nil
|
||||
})
|
||||
lineread.File("/proc/mounts", func(line []byte) error {
|
||||
if mem.Contains(mem.B(line), mem.S("lxcfs /proc/cpuinfo fuse.lxcfs")) {
|
||||
ret.Set(true)
|
||||
return io.EOF
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
func inKnative() bool {
|
||||
// https://cloud.google.com/run/docs/reference/container-contract#env-vars
|
||||
if os.Getenv("K_REVISION") != "" && os.Getenv("K_CONFIGURATION") != "" &&
|
||||
os.Getenv("K_SERVICE") != "" && os.Getenv("PORT") != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func inAWSLambda() bool {
|
||||
// https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html
|
||||
if os.Getenv("AWS_LAMBDA_FUNCTION_NAME") != "" &&
|
||||
os.Getenv("AWS_LAMBDA_FUNCTION_VERSION") != "" &&
|
||||
os.Getenv("AWS_LAMBDA_INITIALIZATION_TYPE") != "" &&
|
||||
os.Getenv("AWS_LAMBDA_RUNTIME_API") != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func inHerokuDyno() bool {
|
||||
// https://devcenter.heroku.com/articles/dynos#local-environment-variables
|
||||
if os.Getenv("PORT") != "" && os.Getenv("DYNO") != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func inAzureAppService() bool {
|
||||
if os.Getenv("APPSVC_RUN_ZIP") != "" && os.Getenv("WEBSITE_STACK") != "" &&
|
||||
os.Getenv("WEBSITE_AUTH_AUTO_AAD") != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func inAWSFargate() bool {
|
||||
return os.Getenv("AWS_EXECUTION_ENV") == "AWS_ECS_FARGATE"
|
||||
}
|
||||
|
||||
func inFlyDotIo() bool {
|
||||
if os.Getenv("FLY_APP_NAME") != "" && os.Getenv("FLY_REGION") != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func inReplit() bool {
|
||||
// https://docs.replit.com/programming-ide/getting-repl-metadata
|
||||
if os.Getenv("REPL_OWNER") != "" && os.Getenv("REPL_SLUG") != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func inKubernetes() bool {
|
||||
if os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func inDockerDesktop() bool {
|
||||
return os.Getenv("TS_HOST_ENV") == "dde"
|
||||
}
|
||||
|
||||
func inHomeAssistantAddOn() bool {
|
||||
if os.Getenv("SUPERVISOR_TOKEN") != "" || os.Getenv("HASSIO_TOKEN") != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// goArchVar returns the GOARM or GOAMD64 etc value that the binary was built
|
||||
// with.
|
||||
func goArchVar() string {
|
||||
bi, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
// Look for GOARM, GOAMD64, GO386, etc. Note that the little-endian
|
||||
// "le"-suffixed GOARCH values don't have their own environment variable.
|
||||
//
|
||||
// See https://pkg.go.dev/cmd/go#hdr-Environment_variables and the
|
||||
// "Architecture-specific environment variables" section:
|
||||
wantKey := "GO" + strings.ToUpper(strings.TrimSuffix(runtime.GOARCH, "le"))
|
||||
for _, s := range bi.Settings {
|
||||
if s.Key == wantKey {
|
||||
return s.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type etcAptSrcResult struct {
|
||||
mod time.Time
|
||||
disabled bool
|
||||
}
|
||||
|
||||
var etcAptSrcCache atomic.Value // of etcAptSrcResult
|
||||
|
||||
// DisabledEtcAptSource reports whether Ubuntu (or similar) has disabled
|
||||
// the /etc/apt/sources.list.d/tailscale.list file contents upon upgrade
|
||||
// to a new release of the distro.
|
||||
//
|
||||
// See https://github.com/tailscale/tailscale/issues/3177
|
||||
func DisabledEtcAptSource() bool {
|
||||
if runtime.GOOS != "linux" {
|
||||
return false
|
||||
}
|
||||
const path = "/etc/apt/sources.list.d/tailscale.list"
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil || !fi.Mode().IsRegular() {
|
||||
return false
|
||||
}
|
||||
mod := fi.ModTime()
|
||||
if c, ok := etcAptSrcCache.Load().(etcAptSrcResult); ok && c.mod.Equal(mod) {
|
||||
return c.disabled
|
||||
}
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
v := etcAptSourceFileIsDisabled(f)
|
||||
etcAptSrcCache.Store(etcAptSrcResult{mod: mod, disabled: v})
|
||||
return v
|
||||
}
|
||||
|
||||
func etcAptSourceFileIsDisabled(r io.Reader) bool {
|
||||
bs := bufio.NewScanner(r)
|
||||
disabled := false // did we find the "disabled on upgrade" comment?
|
||||
for bs.Scan() {
|
||||
line := strings.TrimSpace(bs.Text())
|
||||
if strings.Contains(line, "# disabled on upgrade") {
|
||||
disabled = true
|
||||
}
|
||||
if line == "" || line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
// Well, it has some contents in it at least.
|
||||
return false
|
||||
}
|
||||
return disabled
|
||||
}
|
||||
|
||||
// IsSELinuxEnforcing reports whether SELinux is in "Enforcing" mode.
|
||||
func IsSELinuxEnforcing() bool {
|
||||
if runtime.GOOS != "linux" {
|
||||
return false
|
||||
}
|
||||
out, _ := exec.Command("getenforce").Output()
|
||||
return string(bytes.TrimSpace(out)) == "Enforcing"
|
||||
}
|
||||
|
||||
// IsNATLabGuestVM reports whether the current host is a NAT Lab guest VM.
|
||||
func IsNATLabGuestVM() bool {
|
||||
if runtime.GOOS == "linux" && distro.Get() == distro.Gokrazy {
|
||||
cmdLine, _ := os.ReadFile("/proc/cmdline")
|
||||
return bytes.Contains(cmdLine, []byte("tailscale-tta=1"))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NAT Lab VMs have a unique MAC address prefix.
|
||||
// See
|
||||
21
vendor/tailscale.com/hostinfo/hostinfo_darwin.go
generated
vendored
Normal file
21
vendor/tailscale.com/hostinfo/hostinfo_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build darwin
|
||||
|
||||
package hostinfo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func init() {
|
||||
packageType = packageTypeDarwin
|
||||
}
|
||||
|
||||
func packageTypeDarwin() string {
|
||||
// Using tailscaled or IPNExtension?
|
||||
exe, _ := os.Executable()
|
||||
return filepath.Base(exe)
|
||||
}
|
||||
64
vendor/tailscale.com/hostinfo/hostinfo_freebsd.go
generated
vendored
Normal file
64
vendor/tailscale.com/hostinfo/hostinfo_freebsd.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build freebsd
|
||||
|
||||
package hostinfo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"tailscale.com/types/ptr"
|
||||
"tailscale.com/version/distro"
|
||||
)
|
||||
|
||||
func init() {
|
||||
osVersion = lazyOSVersion.Get
|
||||
distroName = distroNameFreeBSD
|
||||
distroVersion = distroVersionFreeBSD
|
||||
}
|
||||
|
||||
var (
|
||||
lazyVersionMeta = &lazyAtomicValue[versionMeta]{f: ptr.To(freebsdVersionMeta)}
|
||||
lazyOSVersion = &lazyAtomicValue[string]{f: ptr.To(osVersionFreeBSD)}
|
||||
)
|
||||
|
||||
func distroNameFreeBSD() string {
|
||||
return lazyVersionMeta.Get().DistroName
|
||||
}
|
||||
|
||||
func distroVersionFreeBSD() string {
|
||||
return lazyVersionMeta.Get().DistroVersion
|
||||
}
|
||||
|
||||
type versionMeta struct {
|
||||
DistroName string
|
||||
DistroVersion string
|
||||
DistroCodeName string
|
||||
}
|
||||
|
||||
func osVersionFreeBSD() string {
|
||||
var un unix.Utsname
|
||||
unix.Uname(&un)
|
||||
return unix.ByteSliceToString(un.Release[:])
|
||||
}
|
||||
|
||||
func freebsdVersionMeta() (meta versionMeta) {
|
||||
d := distro.Get()
|
||||
meta.DistroName = string(d)
|
||||
switch d {
|
||||
case distro.Pfsense:
|
||||
b, _ := os.ReadFile("/etc/version")
|
||||
meta.DistroVersion = string(bytes.TrimSpace(b))
|
||||
case distro.OPNsense:
|
||||
b, _ := exec.Command("opnsense-version").Output()
|
||||
meta.DistroVersion = string(bytes.TrimSpace(b))
|
||||
case distro.TrueNAS:
|
||||
b, _ := os.ReadFile("/etc/version")
|
||||
meta.DistroVersion = string(bytes.TrimSpace(b))
|
||||
}
|
||||
return
|
||||
}
|
||||
177
vendor/tailscale.com/hostinfo/hostinfo_linux.go
generated
vendored
Normal file
177
vendor/tailscale.com/hostinfo/hostinfo_linux.go
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build linux && !android
|
||||
|
||||
package hostinfo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"tailscale.com/types/ptr"
|
||||
"tailscale.com/util/lineread"
|
||||
"tailscale.com/version/distro"
|
||||
)
|
||||
|
||||
func init() {
|
||||
osVersion = lazyOSVersion.Get
|
||||
packageType = packageTypeLinux
|
||||
distroName = distroNameLinux
|
||||
distroVersion = distroVersionLinux
|
||||
distroCodeName = distroCodeNameLinux
|
||||
deviceModel = deviceModelLinux
|
||||
}
|
||||
|
||||
var (
|
||||
lazyVersionMeta = &lazyAtomicValue[versionMeta]{f: ptr.To(linuxVersionMeta)}
|
||||
lazyOSVersion = &lazyAtomicValue[string]{f: ptr.To(osVersionLinux)}
|
||||
)
|
||||
|
||||
type versionMeta struct {
|
||||
DistroName string
|
||||
DistroVersion string
|
||||
DistroCodeName string // "jammy", etc (VERSION_CODENAME from /etc/os-release)
|
||||
}
|
||||
|
||||
func distroNameLinux() string {
|
||||
return lazyVersionMeta.Get().DistroName
|
||||
}
|
||||
|
||||
func distroVersionLinux() string {
|
||||
return lazyVersionMeta.Get().DistroVersion
|
||||
}
|
||||
|
||||
func distroCodeNameLinux() string {
|
||||
return lazyVersionMeta.Get().DistroCodeName
|
||||
}
|
||||
|
||||
func deviceModelLinux() string {
|
||||
for _, path := range []string{
|
||||
// First try the Synology-specific location.
|
||||
// Example: "DS916+-j"
|
||||
"/proc/sys/kernel/syno_hw_version",
|
||||
|
||||
// Otherwise, try the Devicetree model, usually set on
|
||||
// ARM SBCs, etc.
|
||||
// Example: "Raspberry Pi 4 Model B Rev 1.2"
|
||||
// Example: "WD My Cloud Gen2: Marvell Armada 375"
|
||||
"/sys/firmware/devicetree/base/model", // Raspberry Pi 4 Model B Rev 1.2"
|
||||
} {
|
||||
b, _ := os.ReadFile(path)
|
||||
if s := strings.Trim(string(b), "\x00\r\n\t "); s != "" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getQnapQtsVersion(versionInfo string) string {
|
||||
for _, field := range strings.Fields(versionInfo) {
|
||||
if suffix, ok := strings.CutPrefix(field, "QTSFW_"); ok {
|
||||
return suffix
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func osVersionLinux() string {
|
||||
var un unix.Utsname
|
||||
unix.Uname(&un)
|
||||
return unix.ByteSliceToString(un.Release[:])
|
||||
}
|
||||
|
||||
func linuxVersionMeta() (meta versionMeta) {
|
||||
dist := distro.Get()
|
||||
meta.DistroName = string(dist)
|
||||
|
||||
propFile := "/etc/os-release"
|
||||
switch dist {
|
||||
case distro.Synology:
|
||||
propFile = "/etc.defaults/VERSION"
|
||||
case distro.OpenWrt:
|
||||
propFile = "/etc/openwrt_release"
|
||||
case distro.Unraid:
|
||||
propFile = "/etc/unraid-version"
|
||||
case distro.WDMyCloud:
|
||||
slurp, _ := os.ReadFile("/etc/version")
|
||||
meta.DistroVersion = string(bytes.TrimSpace(slurp))
|
||||
return
|
||||
case distro.QNAP:
|
||||
slurp, _ := os.ReadFile("/etc/version_info")
|
||||
meta.DistroVersion = getQnapQtsVersion(string(slurp))
|
||||
return
|
||||
}
|
||||
|
||||
m := map[string]string{}
|
||||
lineread.File(propFile, func(line []byte) error {
|
||||
eq := bytes.IndexByte(line, '=')
|
||||
if eq == -1 {
|
||||
return nil
|
||||
}
|
||||
k, v := string(line[:eq]), strings.Trim(string(line[eq+1:]), `"'`)
|
||||
m[k] = v
|
||||
return nil
|
||||
})
|
||||
|
||||
if v := m["VERSION_CODENAME"]; v != "" {
|
||||
meta.DistroCodeName = v
|
||||
}
|
||||
if v := m["VERSION_ID"]; v != "" {
|
||||
meta.DistroVersion = v
|
||||
}
|
||||
id := m["ID"]
|
||||
if id != "" {
|
||||
meta.DistroName = id
|
||||
}
|
||||
switch id {
|
||||
case "debian":
|
||||
// Debian's VERSION_ID is just like "11". But /etc/debian_version has "11.5" normally.
|
||||
// Or "bookworm/sid" on sid/testing.
|
||||
slurp, _ := os.ReadFile("/etc/debian_version")
|
||||
if v := string(bytes.TrimSpace(slurp)); v != "" {
|
||||
if '0' <= v[0] && v[0] <= '9' {
|
||||
meta.DistroVersion = v
|
||||
} else if meta.DistroCodeName == "" {
|
||||
meta.DistroCodeName = v
|
||||
}
|
||||
}
|
||||
case "", "centos": // CentOS 6 has no /etc/os-release, so its id is ""
|
||||
if meta.DistroVersion == "" {
|
||||
if cr, _ := os.ReadFile("/etc/centos-release"); len(cr) > 0 { // "CentOS release 6.10 (Final)
|
||||
meta.DistroVersion = string(bytes.TrimSpace(cr))
|
||||
}
|
||||
}
|
||||
}
|
||||
if v := m["PRETTY_NAME"]; v != "" && meta.DistroVersion == "" && !strings.HasSuffix(v, "/sid") {
|
||||
meta.DistroVersion = v
|
||||
}
|
||||
switch dist {
|
||||
case distro.Synology:
|
||||
meta.DistroVersion = m["productversion"]
|
||||
case distro.OpenWrt:
|
||||
meta.DistroVersion = m["DISTRIB_RELEASE"]
|
||||
case distro.Unraid:
|
||||
meta.DistroVersion = m["version"]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// linuxBuildTagPackageType is set by packagetype_*.go
|
||||
// build tag guarded files.
|
||||
var linuxBuildTagPackageType string
|
||||
|
||||
func packageTypeLinux() string {
|
||||
if v := linuxBuildTagPackageType; v != "" {
|
||||
return v
|
||||
}
|
||||
// Report whether this is in a snap.
|
||||
// See https://snapcraft.io/docs/environment-variables
|
||||
// We just look at two somewhat arbitrarily.
|
||||
if os.Getenv("SNAP_NAME") != "" && os.Getenv("SNAP") != "" {
|
||||
return "snap"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
38
vendor/tailscale.com/hostinfo/hostinfo_uname.go
generated
vendored
Normal file
38
vendor/tailscale.com/hostinfo/hostinfo_uname.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build linux || freebsd || openbsd || darwin
|
||||
|
||||
package hostinfo
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"tailscale.com/types/ptr"
|
||||
)
|
||||
|
||||
func init() {
|
||||
unameMachine = lazyUnameMachine.Get
|
||||
}
|
||||
|
||||
var lazyUnameMachine = &lazyAtomicValue[string]{f: ptr.To(unameMachineUnix)}
|
||||
|
||||
func unameMachineUnix() string {
|
||||
switch runtime.GOOS {
|
||||
case "android":
|
||||
// Don't call on Android for now. We're late in the 1.36 release cycle
|
||||
// and don't want to test syscall filters on various Android versions to
|
||||
// see what's permitted. Notably, the hostinfo_linux.go file has build
|
||||
// tag !android, so maybe Uname is verboten.
|
||||
return ""
|
||||
case "ios":
|
||||
// For similar reasons, don't call on iOS. There aren't many iOS devices
|
||||
// and we know their CPU properties so calling this is only risk and no
|
||||
// reward.
|
||||
return ""
|
||||
}
|
||||
var un unix.Utsname
|
||||
unix.Uname(&un)
|
||||
return unix.ByteSliceToString(un.Machine[:])
|
||||
}
|
||||
94
vendor/tailscale.com/hostinfo/hostinfo_windows.go
generated
vendored
Normal file
94
vendor/tailscale.com/hostinfo/hostinfo_windows.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package hostinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
"tailscale.com/types/ptr"
|
||||
"tailscale.com/util/winutil"
|
||||
"tailscale.com/util/winutil/winenv"
|
||||
)
|
||||
|
||||
func init() {
|
||||
distroName = lazyDistroName.Get
|
||||
osVersion = lazyOSVersion.Get
|
||||
packageType = lazyPackageType.Get
|
||||
}
|
||||
|
||||
var (
|
||||
lazyDistroName = &lazyAtomicValue[string]{f: ptr.To(distroNameWindows)}
|
||||
lazyOSVersion = &lazyAtomicValue[string]{f: ptr.To(osVersionWindows)}
|
||||
lazyPackageType = &lazyAtomicValue[string]{f: ptr.To(packageTypeWindows)}
|
||||
)
|
||||
|
||||
func distroNameWindows() string {
|
||||
if winenv.IsWindowsServer() {
|
||||
return "Server"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func osVersionWindows() string {
|
||||
major, minor, build := windows.RtlGetNtVersionNumbers()
|
||||
s := fmt.Sprintf("%d.%d.%d", major, minor, build)
|
||||
// Windows 11 still uses 10 as its major number internally
|
||||
if major == 10 {
|
||||
if ubr, err := getUBR(); err == nil {
|
||||
s += fmt.Sprintf(".%d", ubr)
|
||||
}
|
||||
}
|
||||
return s // "10.0.19041.388", ideally
|
||||
}
|
||||
|
||||
// getUBR obtains a fourth version field, the "Update Build Revision",
|
||||
// from the registry. This field is only available beginning with Windows 10.
|
||||
func getUBR() (uint32, error) {
|
||||
key, err := registry.OpenKey(registry.LOCAL_MACHINE,
|
||||
`SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE|registry.WOW64_64KEY)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer key.Close()
|
||||
|
||||
val, valType, err := key.GetIntegerValue("UBR")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if valType != registry.DWORD {
|
||||
return 0, registry.ErrUnexpectedType
|
||||
}
|
||||
|
||||
return uint32(val), nil
|
||||
}
|
||||
|
||||
func packageTypeWindows() string {
|
||||
if _, err := os.Stat(`C:\ProgramData\chocolatey\lib\tailscale`); err == nil {
|
||||
return "choco"
|
||||
}
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
home, _ := os.UserHomeDir()
|
||||
if strings.HasPrefix(exe, filepath.Join(home, "scoop", "apps", "tailscale")) {
|
||||
return "scoop"
|
||||
}
|
||||
msiSentinel, _ := winutil.GetRegInteger("MSI")
|
||||
if msiSentinel != 1 {
|
||||
// Atypical. Not worth trying to detect. Likely open
|
||||
// source tailscaled or a developer running by hand.
|
||||
return ""
|
||||
}
|
||||
result := "msi"
|
||||
if env, _ := winutil.GetRegString("MSIDist"); env != "" {
|
||||
result += "/" + env
|
||||
}
|
||||
return result
|
||||
}
|
||||
10
vendor/tailscale.com/hostinfo/packagetype_container.go
generated
vendored
Normal file
10
vendor/tailscale.com/hostinfo/packagetype_container.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build linux && ts_package_container
|
||||
|
||||
package hostinfo
|
||||
|
||||
func init() {
|
||||
linuxBuildTagPackageType = "container"
|
||||
}
|
||||
106
vendor/tailscale.com/hostinfo/wol.go
generated
vendored
Normal file
106
vendor/tailscale.com/hostinfo/wol.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package hostinfo
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"tailscale.com/envknob"
|
||||
)
|
||||
|
||||
// TODO(bradfitz): this is all too simplistic and static. It needs to run
|
||||
// continuously in response to netmon events (USB ethernet adapaters might get
|
||||
// plugged in) and look for the media type/status/etc. Right now on macOS it
|
||||
// still detects a half dozen "up" en0, en1, en2, en3 etc interfaces that don't
|
||||
// have any media. We should only report the one that's actually connected.
|
||||
// But it works for now (2023-10-05) for fleshing out the rest.
|
||||
|
||||
var wakeMAC = envknob.RegisterString("TS_WAKE_MAC") // mac address, "false" or "auto". for https://github.com/tailscale/tailscale/issues/306
|
||||
|
||||
// getWoLMACs returns up to 10 MAC address of the local machine to send
|
||||
// wake-on-LAN packets to in order to wake it up. The returned MACs are in
|
||||
// lowercase hex colon-separated form ("xx:xx:xx:xx:xx:xx").
|
||||
//
|
||||
// If TS_WAKE_MAC=auto, it tries to automatically find the MACs based on the OS
|
||||
// type and interface properties. (TODO(bradfitz): incomplete) If TS_WAKE_MAC is
|
||||
// set to a MAC address, that sole MAC address is returned.
|
||||
func getWoLMACs() (macs []string) {
|
||||
switch runtime.GOOS {
|
||||
case "ios", "android":
|
||||
return nil
|
||||
}
|
||||
if s := wakeMAC(); s != "" {
|
||||
switch s {
|
||||
case "auto":
|
||||
ifs, _ := net.Interfaces()
|
||||
for _, iface := range ifs {
|
||||
if iface.Flags&net.FlagLoopback != 0 {
|
||||
continue
|
||||
}
|
||||
if iface.Flags&net.FlagBroadcast == 0 ||
|
||||
iface.Flags&net.FlagRunning == 0 ||
|
||||
iface.Flags&net.FlagUp == 0 {
|
||||
continue
|
||||
}
|
||||
if keepMAC(iface.Name, iface.HardwareAddr) {
|
||||
macs = append(macs, iface.HardwareAddr.String())
|
||||
}
|
||||
if len(macs) == 10 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return macs
|
||||
case "false", "off": // fast path before ParseMAC error
|
||||
return nil
|
||||
}
|
||||
mac, err := net.ParseMAC(s)
|
||||
if err != nil {
|
||||
log.Printf("invalid MAC %q", s)
|
||||
return nil
|
||||
}
|
||||
return []string{mac.String()}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var ignoreWakeOUI = map[[3]byte]bool{
|
||||
{0x00, 0x15, 0x5d}: true, // Hyper-V
|
||||
{0x00, 0x50, 0x56}: true, // VMware
|
||||
{0x00, 0x1c, 0x14}: true, // VMware
|
||||
{0x00, 0x05, 0x69}: true, // VMware
|
||||
{0x00, 0x0c, 0x29}: true, // VMware
|
||||
{0x00, 0x1c, 0x42}: true, // Parallels
|
||||
{0x08, 0x00, 0x27}: true, // VirtualBox
|
||||
{0x00, 0x21, 0xf6}: true, // VirtualBox
|
||||
{0x00, 0x14, 0x4f}: true, // VirtualBox
|
||||
{0x00, 0x0f, 0x4b}: true, // VirtualBox
|
||||
{0x52, 0x54, 0x00}: true, // VirtualBox/Vagrant
|
||||
}
|
||||
|
||||
func keepMAC(ifName string, mac []byte) bool {
|
||||
if len(mac) != 6 {
|
||||
return false
|
||||
}
|
||||
base := strings.TrimRightFunc(ifName, unicode.IsNumber)
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
switch base {
|
||||
case "llw", "awdl", "utun", "bridge", "lo", "gif", "stf", "anpi", "ap":
|
||||
return false
|
||||
}
|
||||
}
|
||||
if mac[0] == 0x02 && mac[1] == 0x42 {
|
||||
// Docker container.
|
||||
return false
|
||||
}
|
||||
oui := [3]byte{mac[0], mac[1], mac[2]}
|
||||
if ignoreWakeOUI[oui] {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user