ipn/ipnlocal: add missing bus notify of peers on full netmap
The prior aa5da2e5f2 ("process node adds/removes in constant
time") commit missed a bus notification case, where new-style
subscribers set NotifyNoNetmap and then the controlclient map routing
sends a full update (rather than a delta). Those profiles + peers
need to be put on the bus too.
I noticed this only when porting the Android app over to use the
new bus stuff.
Updates #19607
Updates #12542
Change-Id: I82c35011d2c532222ca27f7d4e790522c31bd156
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
0e2b3f31af
commit
a8f40a2ca5
@@ -1998,6 +1998,13 @@ func (b *LocalBackend) setControlClientStatusLocked(c controlclient.Client, st c
|
||||
selfChange = st.NetMap.SelfNode.AsStruct()
|
||||
}
|
||||
notify := ipn.Notify{SelfChange: selfChange}
|
||||
if b.hasPeerChangeWatcherLocked() {
|
||||
notify.UserProfiles = st.NetMap.UserProfiles
|
||||
notify.PeersChanged = make([]*tailcfg.Node, 0, len(st.NetMap.Peers))
|
||||
for _, p := range st.NetMap.Peers {
|
||||
notify.PeersChanged = append(notify.PeersChanged, p.AsStruct())
|
||||
}
|
||||
}
|
||||
if goosGetsLegacyNetmapNotify {
|
||||
notify.NetMap = st.NetMap
|
||||
}
|
||||
@@ -3887,6 +3894,18 @@ func (b *LocalBackend) notifyForSessionLocked(sess *watchSession, n *ipn.Notify)
|
||||
return &nCopy
|
||||
}
|
||||
|
||||
// hasPeerChangeWatcherLocked reports whether any active watcher wants peer-set
|
||||
// notifications. b.mu must be held.
|
||||
func (b *LocalBackend) hasPeerChangeWatcherLocked() bool {
|
||||
syncs.AssertLocked(&b.mu)
|
||||
for _, sess := range b.notifyWatchers {
|
||||
if sess.mask&(ipn.NotifyPeerChanges|ipn.NotifyPeerPatches) != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// setAuthURLLocked sets the authURL and triggers [LocalBackend.popBrowserAuthNow] if the URL has changed.
|
||||
// This method is called when a new authURL is received from the control plane, meaning that either a user
|
||||
// has started a new interactive login (e.g., by running `tailscale login` or clicking Login in the GUI),
|
||||
|
||||
@@ -2184,6 +2184,55 @@ func TestNotifyForSessionPeerVisibility(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetControlClientStatusSendsFullNetmapAsPeerChanges(t *testing.T) {
|
||||
b := newTestLocalBackend(t)
|
||||
nw := newNotificationWatcher(t, b, ipnauth.Self)
|
||||
nw.watch(ipn.NotifyPeerChanges|ipn.NotifyNoNetMap, []wantedNotification{{
|
||||
name: "full netmap as peer changes",
|
||||
cond: func(t testing.TB, _ ipnauth.Actor, n *ipn.Notify) bool {
|
||||
if n.SelfChange == nil {
|
||||
return false
|
||||
}
|
||||
if n.NetMap != nil {
|
||||
t.Errorf("NetMap was delivered to NotifyNoNetMap watcher")
|
||||
}
|
||||
if got, want := len(n.PeersChanged), 2; got != want {
|
||||
t.Errorf("PeersChanged len = %d; want %d", got, want)
|
||||
return false
|
||||
}
|
||||
if got, want := len(n.UserProfiles), 3; got != want {
|
||||
t.Errorf("UserProfiles len = %d; want %d", got, want)
|
||||
return false
|
||||
}
|
||||
gotPeers := set.Of(n.PeersChanged[0].ID, n.PeersChanged[1].ID)
|
||||
wantPeers := set.Of(tailcfg.NodeID(10), tailcfg.NodeID(20))
|
||||
if !gotPeers.Equal(wantPeers) {
|
||||
t.Errorf("PeersChanged IDs = %v; want %v", gotPeers, wantPeers)
|
||||
}
|
||||
return true
|
||||
},
|
||||
}})
|
||||
|
||||
nm := &netmap.NetworkMap{
|
||||
SelfNode: (&tailcfg.Node{
|
||||
ID: 1,
|
||||
User: 1,
|
||||
Key: makeNodeKeyFromID(1),
|
||||
}).View(),
|
||||
Peers: []tailcfg.NodeView{
|
||||
(&tailcfg.Node{ID: 10, User: 2, Key: makeNodeKeyFromID(10)}).View(),
|
||||
(&tailcfg.Node{ID: 20, User: 3, Key: makeNodeKeyFromID(20)}).View(),
|
||||
},
|
||||
UserProfiles: map[tailcfg.UserID]tailcfg.UserProfileView{
|
||||
1: (&tailcfg.UserProfile{ID: 1, LoginName: "self@example.com"}).View(),
|
||||
2: (&tailcfg.UserProfile{ID: 2, LoginName: "peer1@example.com"}).View(),
|
||||
3: (&tailcfg.UserProfile{ID: 3, LoginName: "peer2@example.com"}).View(),
|
||||
},
|
||||
}
|
||||
b.SetControlClientStatus(b.cc, controlclient.Status{NetMap: nm, LoggedIn: true})
|
||||
nw.check()
|
||||
}
|
||||
|
||||
// TestNotifyForSessionUserProfilesGating verifies that
|
||||
// [Notify.UserProfiles] is only delivered to sessions opted in to
|
||||
// NotifyPeerChanges/NotifyPeerPatches, and is deduped per-UserID
|
||||
|
||||
Reference in New Issue
Block a user