diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go index 9c69faadf..fd1349f69 100644 --- a/control/controlclient/direct.go +++ b/control/controlclient/direct.go @@ -1065,6 +1065,24 @@ func undeltaPeers(mapRes *tailcfg.MapResponse, prev []*tailcfg.Node) { } } sortNodes(newFull) + + if mapRes.PeerSeenChange != nil { + peerByID := make(map[tailcfg.NodeID]*tailcfg.Node, len(newFull)) + for _, n := range newFull { + peerByID[n.ID] = n + } + now := time.Now() + for nodeID, seen := range mapRes.PeerSeenChange { + if n, ok := peerByID[nodeID]; ok { + if seen { + n.LastSeen = &now + } else { + n.LastSeen = nil + } + } + } + } + mapRes.Peers = newFull mapRes.PeersChanged = nil mapRes.PeersRemoved = nil diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 04ba9bd3d..e22c55150 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -32,7 +32,8 @@ import ( // 7: 2020-12-15: FilterRule.SrcIPs accepts CIDRs+ranges, doesn't warn about 0.0.0.0/:: // 8: 2020-12-19: client can receive IPv6 addresses and routes if beta enabled server-side // 9: 2020-12-30: client doesn't auto-add implicit search domains from peers; only DNSConfig.Domains -const CurrentMapRequestVersion = 9 +// 10: 2021-01-17: client understands MapResponse.PeerSeenChange +const CurrentMapRequestVersion = 10 type ID int64 @@ -636,6 +637,11 @@ type MapResponse struct { // PeersRemoved are the NodeIDs that are no longer in the peer list. PeersRemoved []NodeID `json:",omitempty"` + // PeerSeenChange contains information on how to update peers' LastSeen + // times. If the value is false, the peer is gone. If the value is true, + // the LastSeen time is now. Absent means unchanged. + PeerSeenChange map[NodeID]bool `json:",omitempty"` + // DNS is the same as DNSConfig.Nameservers. // // TODO(dmytro): should be sent in DNSConfig.Nameservers once clients have updated.