diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 1367bbebc..4e49741a5 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -343,7 +343,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/util/osshare from tailscale.com/ipn/ipnlocal+ W tailscale.com/util/pidowner from tailscale.com/ipn/ipnauth tailscale.com/util/racebuild from tailscale.com/logpolicy - tailscale.com/util/rands from tailscale.com/ipn/localapi + tailscale.com/util/rands from tailscale.com/ipn/localapi+ tailscale.com/util/ringbuffer from tailscale.com/wgengine/magicsock tailscale.com/util/set from tailscale.com/health+ tailscale.com/util/singleflight from tailscale.com/control/controlclient+ diff --git a/ipn/backend.go b/ipn/backend.go index 806598aa2..8da7e6a5c 100644 --- a/ipn/backend.go +++ b/ipn/backend.go @@ -61,7 +61,7 @@ const ( // each one via RequestEngineStatus. NotifyWatchEngineUpdates NotifyWatchOpt = 1 << iota - NotifyInitialState // if set, the first Notify message (sent immediately) will contain the current State + BrowseToURL + NotifyInitialState // if set, the first Notify message (sent immediately) will contain the current State + BrowseToURL + SessionID NotifyInitialPrefs // if set, the first Notify message (sent immediately) will contain the current Prefs NotifyInitialNetMap // if set, the first Notify message (sent immediately) will contain the current NetMap @@ -77,6 +77,12 @@ type Notify struct { _ structs.Incomparable Version string // version number of IPN backend + // SessionID identifies the unique WatchIPNBus session. + // This field is only set in the first message when requesting + // NotifyInitialState. Clients must store it on their side as + // following notifications will not include this field. + SessionID string `json:",omitempty"` + // ErrMessage, if non-nil, contains a critical error message. // For State InUseOtherUser, ErrMessage is not critical and just contains the details. ErrMessage *string diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 69bba760f..b516b12c0 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -78,6 +78,7 @@ import ( "tailscale.com/util/mak" "tailscale.com/util/multierr" "tailscale.com/util/osshare" + "tailscale.com/util/rands" "tailscale.com/util/set" "tailscale.com/util/systemd" "tailscale.com/util/testenv" @@ -1935,6 +1936,8 @@ func (b *LocalBackend) ResendHostinfoIfNeeded() { func (b *LocalBackend) WatchNotifications(ctx context.Context, mask ipn.NotifyWatchOpt, onWatchAdded func(), fn func(roNotify *ipn.Notify) (keepGoing bool)) { ch := make(chan *ipn.Notify, 128) + sessionID := rands.HexString(16) + origFn := fn if mask&ipn.NotifyNoPrivateKeys != 0 { fn = func(n *ipn.Notify) bool { @@ -1956,10 +1959,12 @@ func (b *LocalBackend) WatchNotifications(ctx context.Context, mask ipn.NotifyWa var ini *ipn.Notify b.mu.Lock() + const initialBits = ipn.NotifyInitialState | ipn.NotifyInitialPrefs | ipn.NotifyInitialNetMap if mask&initialBits != 0 { ini = &ipn.Notify{Version: version.Long()} if mask&ipn.NotifyInitialState != 0 { + ini.SessionID = sessionID ini.State = ptr.To(b.state) if b.state == ipn.NeedsLogin { ini.BrowseToURL = ptr.To(b.authURLSticky)