Просмотр исходного кода

cmd/tailscaled, tailcfg, hostinfo: add flag to disable logging + support

As noted in #5617, our documented method of blocking log.tailscale.io
DNS no longer works due to bootstrap DNS.

Instead, provide an explicit flag (--no-logs-no-support) and/or env
variable (TS_NO_LOGS_NO_SUPPORT=true) to explicitly disable logcatcher
uploads. It also sets a bit on Hostinfo to say that the node is in that
mode so we can end any support tickets from such nodes more quickly.

This does not yet provide an easy mechanism for users on some
platforms (such as Windows, macOS, Synology) to set flags/env. On
Linux you'd used /etc/default/tailscaled typically. Making it easier
to set flags for other platforms is tracked in #5114.

Fixes #5617
Fixes tailscale/corp#1475

Change-Id: I72404e1789f9e56ec47f9b7021b44c025f7a373a
Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick 3 лет назад
Родитель
Сommit
45a3de14a6

+ 6 - 0
cmd/tailscaled/tailscaled.go

@@ -113,6 +113,7 @@ var args struct {
 	verbose        int
 	socksAddr      string // listen address for SOCKS5 server
 	httpProxyAddr  string // listen address for HTTP proxy server
+	disableLogs    bool
 }
 
 var (
@@ -144,6 +145,7 @@ func main() {
 	flag.StringVar(&args.socketpath, "socket", paths.DefaultTailscaledSocket(), "path of the service unix socket")
 	flag.StringVar(&args.birdSocketPath, "bird-socket", "", "path of the bird unix socket")
 	flag.BoolVar(&printVersion, "version", false, "print version information and exit")
+	flag.BoolVar(&args.disableLogs, "no-logs-no-support", false, "disable log uploads; this also disables any technical support")
 
 	if len(os.Args) > 0 && filepath.Base(os.Args[0]) == "tailscale" && beCLI != nil {
 		beCLI()
@@ -199,6 +201,10 @@ func main() {
 		args.statepath = paths.DefaultTailscaledStateFile()
 	}
 
+	if args.disableLogs {
+		envknob.SetNoLogsNoSupport()
+	}
+
 	if beWindowsSubprocess() {
 		return
 	}

+ 1 - 0
control/controlclient/direct.go

@@ -937,6 +937,7 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, readOnly bool
 			}
 			if resp.Debug.DisableLogTail {
 				logtail.Disable()
+				envknob.SetNoLogsNoSupport()
 			}
 			if resp.Debug.LogHeapPprof {
 				go logheap.LogHeap(resp.Debug.LogHeapURL)

+ 11 - 0
envknob/envknob.go

@@ -155,3 +155,14 @@ func SSHPolicyFile() string { return String("TS_DEBUG_SSH_POLICY_FILE") }
 
 // SSHIgnoreTailnetPolicy is whether to ignore the Tailnet SSH policy for development.
 func SSHIgnoreTailnetPolicy() bool { return Bool("TS_DEBUG_SSH_IGNORE_TAILNET_POLICY") }
+
+// NoLogsNoSupport reports whether the client's opted out of log uploads and
+// technical support.
+func NoLogsNoSupport() bool {
+	return Bool("TS_NO_LOGS_NO_SUPPORT")
+}
+
+// SetNoLogsNoSupport enables no-logs-no-support mode.
+func SetNoLogsNoSupport() {
+	os.Setenv("TS_NO_LOGS_NO_SUPPORT", "true")
+}

+ 17 - 15
hostinfo/hostinfo.go

@@ -17,6 +17,7 @@ import (
 	"time"
 
 	"go4.org/mem"
+	"tailscale.com/envknob"
 	"tailscale.com/tailcfg"
 	"tailscale.com/types/opt"
 	"tailscale.com/util/cloudenv"
@@ -32,21 +33,22 @@ func New() *tailcfg.Hostinfo {
 	hostname, _ := os.Hostname()
 	hostname = dnsname.FirstLabel(hostname)
 	return &tailcfg.Hostinfo{
-		IPNVersion:     version.Long,
-		Hostname:       hostname,
-		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,
-		GoVersion:      runtime.Version(),
-		DeviceModel:    deviceModel(),
-		Cloud:          string(cloudenv.Get()),
+		IPNVersion:      version.Long,
+		Hostname:        hostname,
+		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,
+		GoVersion:       runtime.Version(),
+		DeviceModel:     deviceModel(),
+		Cloud:           string(cloudenv.Get()),
+		NoLogsNoSupport: envknob.NoLogsNoSupport(),
 	}
 }
 

+ 4 - 0
ipn/localapi/localapi.go

@@ -25,6 +25,7 @@ import (
 	"time"
 
 	"tailscale.com/client/tailscale/apitype"
+	"tailscale.com/envknob"
 	"tailscale.com/ipn"
 	"tailscale.com/ipn/ipnlocal"
 	"tailscale.com/ipn/ipnstate"
@@ -213,6 +214,9 @@ func (h *Handler) serveBugReport(w http.ResponseWriter, r *http.Request) {
 	}
 
 	logMarker := fmt.Sprintf("BUG-%v-%v-%v", h.backendLogID, time.Now().UTC().Format("20060102150405Z"), randHex(8))
+	if envknob.NoLogsNoSupport() {
+		logMarker = "BUG-NO-LOGS-NO-SUPPORT-this-node-has-had-its-logging-disabled"
+	}
 	h.logf("user bugreport: %s", logMarker)
 	if note := r.FormValue("note"); len(note) > 0 {
 		h.logf("user bugreport note: %s", note)

+ 15 - 1
logpolicy/logpolicy.go

@@ -539,7 +539,10 @@ func New(collection string) *Policy {
 		conf.IncludeProcSequence = true
 	}
 
-	if val := getLogTarget(); val != "" {
+	if envknob.NoLogsNoSupport() {
+		log.Println("You have disabled logging. Tailscale will not be able to provide support.")
+		conf.HTTPC = &http.Client{Transport: noopPretendSuccessTransport{}}
+	} else if val := getLogTarget(); val != "" {
 		log.Println("You have enabled a non-default log target. Doing without being told to by Tailscale staff or your network administrator will make getting support difficult.")
 		conf.BaseURL = val
 		u, _ := url.Parse(val)
@@ -735,3 +738,14 @@ func goVersion() string {
 	}
 	return v
 }
+
+type noopPretendSuccessTransport struct{}
+
+func (noopPretendSuccessTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+	io.ReadAll(req.Body)
+	req.Body.Close()
+	return &http.Response{
+		StatusCode: 200,
+		Status:     "200 OK",
+	}, nil
+}

+ 1 - 0
tailcfg/tailcfg.go

@@ -495,6 +495,7 @@ type Hostinfo struct {
 	Hostname        string         `json:",omitempty"` // name of the host the client runs on
 	ShieldsUp       bool           `json:",omitempty"` // indicates whether the host is blocking incoming connections
 	ShareeNode      bool           `json:",omitempty"` // indicates this node exists in netmap because it's owned by a shared-to user
+	NoLogsNoSupport bool           `json:",omitempty"` // indicates that the user has opted out of sending logs and support
 	GoArch          string         `json:",omitempty"` // the host's GOARCH value (of the running binary)
 	GoVersion       string         `json:",omitempty"` // Go version binary was built with
 	RoutableIPs     []netip.Prefix `json:",omitempty"` // set of IP ranges this client can route

+ 1 - 0
tailcfg/tailcfg_clone.go

@@ -131,6 +131,7 @@ var _HostinfoCloneNeedsRegeneration = Hostinfo(struct {
 	Hostname        string
 	ShieldsUp       bool
 	ShareeNode      bool
+	NoLogsNoSupport bool
 	GoArch          string
 	GoVersion       string
 	RoutableIPs     []netip.Prefix

+ 1 - 0
tailcfg/tailcfg_test.go

@@ -47,6 +47,7 @@ func TestHostinfoEqual(t *testing.T) {
 		"Hostname",
 		"ShieldsUp",
 		"ShareeNode",
+		"NoLogsNoSupport",
 		"GoArch",
 		"GoVersion",
 		"RoutableIPs",

+ 2 - 0
tailcfg/tailcfg_view.go

@@ -266,6 +266,7 @@ func (v HostinfoView) DeviceModel() string    { return v.ж.DeviceModel }
 func (v HostinfoView) Hostname() string       { return v.ж.Hostname }
 func (v HostinfoView) ShieldsUp() bool        { return v.ж.ShieldsUp }
 func (v HostinfoView) ShareeNode() bool       { return v.ж.ShareeNode }
+func (v HostinfoView) NoLogsNoSupport() bool  { return v.ж.NoLogsNoSupport }
 func (v HostinfoView) GoArch() string         { return v.ж.GoArch }
 func (v HostinfoView) GoVersion() string      { return v.ж.GoVersion }
 func (v HostinfoView) RoutableIPs() views.IPPrefixSlice {
@@ -298,6 +299,7 @@ var _HostinfoViewNeedsRegeneration = Hostinfo(struct {
 	Hostname        string
 	ShieldsUp       bool
 	ShareeNode      bool
+	NoLogsNoSupport bool
 	GoArch          string
 	GoVersion       string
 	RoutableIPs     []netip.Prefix