From 659e7837c6304d24419cdba94f7d6f3f7431f85a Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Tue, 18 Oct 2022 14:54:07 -0600 Subject: [PATCH] health, ipn/ipnlocal: when -no-logs-no-support is enabled, deny access to tailnets that have network logging enabled We want users to have the freedom to start tailscaled with `-no-logs-no-support`, but that is obviously in direct conflict with tailnets that have network logging enabled. When we detect that condition, we record the issue in health, notify the client, set WantRunning=false, and bail. We clear the item in health when a profile switch occurs, since it is a per-tailnet condition that should not propagate across profiles. Signed-off-by: Aaron Klotz --- health/health.go | 11 +++++++++++ ipn/ipnlocal/local.go | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/health/health.go b/health/health.go index a08c6100d..d4c319ff8 100644 --- a/health/health.go +++ b/health/health.go @@ -48,6 +48,7 @@ udp4Unbound bool controlHealth []string lastLoginErr error + localLogConfigErr error ) // Subsystem is the name of a subsystem whose health can be monitored. @@ -193,6 +194,13 @@ func SetDNSManagerHealth(err error) { setErr(SysDNSManager, err) } // DNSOSHealth returns the net/dns.OSConfigurator error state. func DNSOSHealth() error { return get(SysDNSOS) } +// SetLocalLogConfigHealth sets the error state of this client's local log configuration. +func SetLocalLogConfigHealth(err error) { + mu.Lock() + defer mu.Unlock() + localLogConfigErr = err +} + func RegisterDebugHandler(typ string, h http.Handler) { mu.Lock() defer mu.Unlock() @@ -397,6 +405,9 @@ func overallErrorLocked() error { if !anyInterfaceUp { return errors.New("network down") } + if localLogConfigErr != nil { + return localLogConfigErr + } if !ipnWantRunning { return fmt.Errorf("state=%v, wantRunning=%v", ipnState, ipnWantRunning) } diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 444f1cddd..c1ebef7a6 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -908,6 +908,21 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) { } if st.NetMap != nil { + if envknob.NoLogsNoSupport() && hasCapability(st.NetMap, tailcfg.CapabilityDataPlaneAuditLogs) { + msg := "tailnet requires logging to be enabled. Remove -no-logs-no-support from tailscaled command line." + health.SetLocalLogConfigHealth(errors.New(msg)) + // Connecting to this tailnet without logging is forbidden; boot us outta here. + b.mu.Lock() + prefs.WantRunning = false + p := prefs.View() + if err := b.pm.SetPrefs(p); err != nil { + b.logf("Failed to save new controlclient state: %v", err) + } + b.mu.Unlock() + np := stripKeysFromPrefs(p) + b.send(ipn.Notify{ErrMessage: &msg, Prefs: &np}) + return + } if netMap != nil { diff := st.NetMap.ConciseDiffFrom(netMap) if strings.TrimSpace(diff) == "" { @@ -4418,6 +4433,7 @@ func (b *LocalBackend) resetForProfileChangeLockedOnEntry() error { b.lastServeConfJSON = mem.B(nil) b.serveConfig = ipn.ServeConfigView{} b.enterStateLockedOnEntry(ipn.NoState) // Reset state. + health.SetLocalLogConfigHealth(nil) return b.Start(ipn.Options{}) }