ipn: add no-disconnect in-process bus subscribers

Add NotifyInProcessNoDisconnect for in-process IPN bus subscribers that
must apply every bus update. When such a subscriber falls behind, block
Notify production instead of sending the terminal fell-behind message and
closing the watch.

This is intentionally not available over LocalAPI, where a slow or stuck
out-of-process client should still be disconnected rather than allowed to
stall tailscaled. In-process callers that use the bit must keep their
callbacks fast and must not call back into LocalBackend from the callback.

Updates #20062

Change-Id: I730ad61a07475243bb226fba2262c1a3ded211ae
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2026-06-09 12:51:38 -07:00
committed by Brad Fitzpatrick
parent 913df7e6ea
commit 1deb6a8449
6 changed files with 124 additions and 3 deletions
+4
View File
@@ -902,6 +902,10 @@ func (h *Handler) serveWatchIPNBus(w http.ResponseWriter, r *http.Request) {
}
mask = ipn.NotifyWatchOpt(v)
}
if mask&ipn.NotifyInProcessNoDisconnect != 0 {
http.Error(w, "NotifyInProcessNoDisconnect is only valid for in-process IPN bus subscribers", http.StatusBadRequest)
return
}
if err := ipn.ValidateNotifyWatchOpt(mask); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
+6
View File
@@ -661,6 +661,12 @@ func TestServeWatchIPNBus(t *testing.T) {
mask: ipn.NotifyRateLimit | ipn.NotifyPeerChanges,
wantStatus: http.StatusBadRequest,
},
{
desc: "in-process-no-disconnect-forbidden",
permitRead: true,
mask: ipn.NotifyInProcessNoDisconnect,
wantStatus: http.StatusBadRequest,
},
}
for _, tt := range tests {