ipn/ipnlocal, control/controlclient: keep map poll alive on NoLogsNoSupport + flow logs

Fixes #11793

Change-Id: I77eab157b6be24799805ece905855b6fecfa91c9
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2024-04-20 11:32:48 -07:00
parent 375617c5c8
commit d37674a584
2 changed files with 25 additions and 13 deletions

View File

@ -93,6 +93,16 @@ type mapSession struct {
lastTKAInfo *tailcfg.TKAInfo lastTKAInfo *tailcfg.TKAInfo
lastNetmapSummary string // from NetworkMap.VeryConcise lastNetmapSummary string // from NetworkMap.VeryConcise
lastMaxExpiry time.Duration lastMaxExpiry time.Duration
// breakPeersForFlowLogs is whether we've detected a situation
// that's incompatible with flow logs: the tailnet admin has enabled
// network flow logs, but the local machine has been configured to
// not log. In this case, to be conservative, we drop all peers
// but keep the map poll connection open. This way, the admin can
// still get back into the machine later if they first disable flow
// logs. But we otherwise disable connectivity over Tailscale.
// See https://github.com/tailscale/tailscale/issues/11793
breakPeersForFlowLogs bool
} }
// newMapSession returns a mostly unconfigured new mapSession. // newMapSession returns a mostly unconfigured new mapSession.
@ -181,6 +191,8 @@ func (ms *mapSession) HandleNonKeepAliveMapResponse(ctx context.Context, resp *t
} }
} }
ms.controlKnobs.UpdateFromNodeAttributes(resp.Node.CapMap) ms.controlKnobs.UpdateFromNodeAttributes(resp.Node.CapMap)
ms.breakPeersForFlowLogs = envknob.NoLogsNoSupport() && resp.Node.CapMap.Contains(tailcfg.CapabilityDataPlaneAuditLogs)
} }
// Call Node.InitDisplayNames on any changed nodes. // Call Node.InitDisplayNames on any changed nodes.
@ -219,6 +231,9 @@ func (ms *mapSession) HandleNonKeepAliveMapResponse(ctx context.Context, resp *t
} }
func (ms *mapSession) tryHandleIncrementally(res *tailcfg.MapResponse) bool { func (ms *mapSession) tryHandleIncrementally(res *tailcfg.MapResponse) bool {
if ms.breakPeersForFlowLogs {
return false
}
if ms.controlKnobs != nil && ms.controlKnobs.DisableDeltaUpdates.Load() { if ms.controlKnobs != nil && ms.controlKnobs.DisableDeltaUpdates.Load() {
return false return false
} }
@ -805,6 +820,10 @@ func (ms *mapSession) netmap() *netmap.NetworkMap {
MaxKeyDuration: ms.lastMaxExpiry, MaxKeyDuration: ms.lastMaxExpiry,
} }
if ms.breakPeersForFlowLogs {
nm.Peers = nil
}
if ms.lastTKAInfo != nil && ms.lastTKAInfo.Head != "" { if ms.lastTKAInfo != nil && ms.lastTKAInfo.Head != "" {
if err := nm.TKAHead.UnmarshalText([]byte(ms.lastTKAInfo.Head)); err != nil { if err := nm.TKAHead.UnmarshalText([]byte(ms.lastTKAInfo.Head)); err != nil {
ms.logf("error unmarshalling TKAHead: %v", err) ms.logf("error unmarshalling TKAHead: %v", err)

View File

@ -1013,6 +1013,8 @@ func (b *LocalBackend) peerCapsLocked(src netip.Addr) tailcfg.PeerCapMap {
return nil return nil
} }
var noLogsNoSupportNotifyOnce sync.Once
// SetControlClientStatus is the callback invoked by the control client whenever it posts a new status. // SetControlClientStatus is the callback invoked by the control client whenever it posts a new status.
// Among other things, this is where we update the netmap, packet filters, DNS and DERP maps. // Among other things, this is where we update the netmap, packet filters, DNS and DERP maps.
func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st controlclient.Status) { func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st controlclient.Status) {
@ -1216,20 +1218,11 @@ func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st control
if st.NetMap != nil { if st.NetMap != nil {
if envknob.NoLogsNoSupport() && st.NetMap.HasCap(tailcfg.CapabilityDataPlaneAuditLogs) { if envknob.NoLogsNoSupport() && st.NetMap.HasCap(tailcfg.CapabilityDataPlaneAuditLogs) {
msg := "tailnet requires logging to be enabled. Remove --no-logs-no-support from tailscaled command line." msg := "tailnet requires logging to be enabled. Remove --no-logs-no-support from the tailscaled command line."
health.SetLocalLogConfigHealth(errors.New(msg)) health.SetLocalLogConfigHealth(errors.New(msg))
// Connecting to this tailnet without logging is forbidden; boot us outta here. noLogsNoSupportNotifyOnce.Do(func() {
b.mu.Lock() b.send(ipn.Notify{ErrMessage: ptr.To(msg)})
prefs.WantRunning = false })
p := prefs.View()
if err := b.pm.SetPrefs(p, ipn.NetworkProfile{
MagicDNSName: st.NetMap.MagicDNSSuffix(),
DomainName: st.NetMap.DomainName(),
}); err != nil {
b.logf("Failed to save new controlclient state: %v", err)
}
b.mu.Unlock()
b.send(ipn.Notify{ErrMessage: &msg, Prefs: &p})
return return
} }
if netMap != nil { if netMap != nil {