diff options
Diffstat (limited to 'ipn')
| -rw-r--r-- | ipn/ipnlocal/c2n_test.go | 3 | ||||
| -rw-r--r-- | ipn/ipnlocal/expiry.go | 86 | ||||
| -rw-r--r-- | ipn/ipnlocal/expiry_test.go | 27 | ||||
| -rw-r--r-- | ipn/ipnlocal/local.go | 1 |
4 files changed, 90 insertions, 27 deletions
diff --git a/ipn/ipnlocal/c2n_test.go b/ipn/ipnlocal/c2n_test.go index 75a57dee5..9586549c3 100644 --- a/ipn/ipnlocal/c2n_test.go +++ b/ipn/ipnlocal/c2n_test.go @@ -268,6 +268,8 @@ func TestRedactNetmapPrivateKeys(t *testing.T) { f(tailcfg.DisplayMessage{}, "Severity"): false, f(tailcfg.DisplayMessage{}, "Text"): false, f(tailcfg.DisplayMessage{}, "Title"): false, + f(tailcfg.ExtraCapMapValue{}, "Expiry"): false, + f(tailcfg.ExtraCapMapValue{}, "Value"): false, f(tailcfg.FilterRule{}, "CapGrant"): false, f(tailcfg.FilterRule{}, "DstPorts"): false, f(tailcfg.FilterRule{}, "IPProto"): false, @@ -353,6 +355,7 @@ func TestRedactNetmapPrivateKeys(t *testing.T) { f(tailcfg.Node{}, "DiscoKey"): false, f(tailcfg.Node{}, "Endpoints"): false, f(tailcfg.Node{}, "ExitNodeDNSResolvers"): false, + f(tailcfg.Node{}, "ExtraCapMap"): false, f(tailcfg.Node{}, "Expired"): false, f(tailcfg.Node{}, "HomeDERP"): false, f(tailcfg.Node{}, "Hostinfo"): false, diff --git a/ipn/ipnlocal/expiry.go b/ipn/ipnlocal/expiry.go index 849e28610..961c9ff4c 100644 --- a/ipn/ipnlocal/expiry.go +++ b/ipn/ipnlocal/expiry.go @@ -153,6 +153,39 @@ func (em *expiryManager) flagExpiredPeers(netmap *netmap.NetworkMap, localNow ti } } +func (em *expiryManager) expireNodeCaps(netmap *netmap.NetworkMap, localNow time.Time) { + controlNow := localNow.Add(em.clockDelta.Load()) + if controlNow.Before(flagExpiredPeersEpoch) { + em.logf("netmap: expireNodeCaps: [unexpected] delta-adjusted current time is before hardcoded epoch; skipping") + return + } + expireCaps := func(n *tailcfg.Node) (changed bool) { + if len(n.ExtraCapMap) == 0 { + return false + } + for capName, cap := range n.ExtraCapMap { + if !cap.Expiry.IsZero() && cap.Expiry.Before(controlNow) { + delete(n.ExtraCapMap, capName) + changed = true + } + } + return changed + } + if netmap.SelfNode.Valid() { + // TODO(anton): don't clone if there's nothing to change. + self := netmap.SelfNode.AsStruct() + if expireCaps(self) { + netmap.SelfNode = self.View() + } + } + for i, peer := range netmap.Peers { + p := peer.AsStruct() + if expireCaps(p) { + netmap.Peers[i] = p.View() + } + } +} + // nextPeerExpiry returns the time that the next node in the netmap expires // (including the self node), based on their KeyExpiry. It skips nodes that are // already marked as Expired. If there are no nodes expiring in the future, @@ -174,43 +207,42 @@ func (em *expiryManager) nextPeerExpiry(nm *netmap.NetworkMap, localNow time.Tim } var nextExpiry time.Time // zero if none - for _, peer := range nm.Peers { - if peer.KeyExpiry().IsZero() { - continue // tagged node - } else if peer.Expired() { - // Peer already expired; Expired is set by the - // flagExpiredPeers function, above. - continue - } else if peer.KeyExpiry().Before(controlNow) { - // This peer already expired, and peer.Expired - // isn't set for some reason. Skip this node. - continue + update := func(expiry time.Time) { + if expiry.IsZero() { + return } - // nextExpiry being zero is a sentinel that we haven't yet set // an expiry; otherwise, only update if this node's expiry is // sooner than the currently-stored one (since we want the // soonest-occurring expiry time). - if nextExpiry.IsZero() || peer.KeyExpiry().Before(nextExpiry) { - nextExpiry = peer.KeyExpiry() + if nextExpiry.IsZero() || expiry.Before(nextExpiry) { + nextExpiry = expiry + } + } + handleNode := func(n tailcfg.NodeView) { + if n.KeyExpiry().IsZero() { + // tagged node + } else if n.Expired() { + // Already expired; Expired is set by the + // flagExpiredPeers function, above. + } else if n.KeyExpiry().Before(controlNow) { + // Already expired, but Expired + // isn't set for some reason. Skip it. + } else { + update(n.KeyExpiry()) + } + // Also handle expiring caps. + for _, c := range n.ExtraCapMap().All() { + update(c.Expiry()) } } + for _, peer := range nm.Peers { + handleNode(peer) + } // Ensure that we also fire this timer if our own node key expires. if nm.SelfNode.Valid() { - selfExpiry := nm.SelfNode.KeyExpiry() - - if selfExpiry.IsZero() { - // No expiry for self node - } else if selfExpiry.Before(controlNow) { - // Self node already expired; we don't want to return a - // time in the past, so skip this. - } else if nextExpiry.IsZero() || selfExpiry.Before(nextExpiry) { - // Self node expires after now, but before the soonest - // peer in the netmap; update our next expiry to this - // time. - nextExpiry = selfExpiry - } + handleNode(nm.SelfNode) } // As an additional defense in depth, never return a time that is diff --git a/ipn/ipnlocal/expiry_test.go b/ipn/ipnlocal/expiry_test.go index 2c646ca72..d65788a28 100644 --- a/ipn/ipnlocal/expiry_test.go +++ b/ipn/ipnlocal/expiry_test.go @@ -15,6 +15,7 @@ import ( "tailscale.com/types/key" "tailscale.com/types/netmap" "tailscale.com/util/eventbus/eventbustest" + "tailscale.com/util/mak" ) func TestFlagExpiredPeers(t *testing.T) { @@ -238,6 +239,32 @@ func TestNextPeerExpiry(t *testing.T) { }, want: noExpiry, }, + { + name: "self_attribute", + netmap: &netmap.NetworkMap{ + Peers: nodeViews([]*tailcfg.Node{ + n(1, "foo", timeInMoreFuture, func(n *tailcfg.Node) { + mak.Set(&n.ExtraCapMap, "foo", tailcfg.ExtraCapMapValue{Expiry: timeInMoreFuture}) + }), + }), + SelfNode: n(2, "self", noExpiry, func(n *tailcfg.Node) { + mak.Set(&n.ExtraCapMap, "foo", tailcfg.ExtraCapMapValue{Expiry: timeInFuture}) + }).View(), + }, + want: timeInFuture, + }, + { + name: "peer_attribute", + netmap: &netmap.NetworkMap{ + Peers: nodeViews([]*tailcfg.Node{ + n(1, "foo", timeInMoreFuture, func(n *tailcfg.Node) { + mak.Set(&n.ExtraCapMap, "foo", tailcfg.ExtraCapMapValue{Expiry: timeInFuture}) + }), + }), + SelfNode: n(2, "self", timeInMoreFuture).View(), + }, + want: timeInFuture, + }, } for _, tt := range tests { diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index ce42ae75a..9f154912f 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -1575,6 +1575,7 @@ func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st control if st.NetMap != nil { now := b.clock.Now() b.em.flagExpiredPeers(st.NetMap, now) + b.em.expireNodeCaps(st.NetMap, now) // Always stop the existing netmap timer if we have a netmap; // it's possible that we have no nodes expiring, so we should |
