ipn/ipnlocal,ssh/tailssh: reject c2n /update if SSH conns are active (#11820)

Since we already track active SSH connections, it's not hard to
proactively reject updates until those finish. We attempt to do the same
on the control side, but the detection latency for new connections is in
the minutes, which is not fast enough for common short sessions.

Handle a `force=true` query parameter to override this behavior, so that
control can still trigger an update on a server where some long-running
abandoned SSH session is open.

Updates https://github.com/tailscale/corp/issues/18556

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
pull/11693/merge
Andrew Lytvynov 7 months ago committed by GitHub
parent 5100bdeba7
commit b743b85dad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -300,6 +300,13 @@ func handleC2NUpdatePost(b *LocalBackend, w http.ResponseWriter, r *http.Request
return return
} }
// Do not update if we have active inbound SSH connections. Control can set
// force=true query parameter to override this.
if r.FormValue("force") != "true" && b.sshServer != nil && b.sshServer.NumActiveConns() > 0 {
res.Err = "not updating due to active SSH connections"
return
}
// Check if update was already started, and mark as started. // Check if update was already started, and mark as started.
if !b.trySetC2NUpdateStarted() { if !b.trySetC2NUpdateStarted() {
res.Err = "update already started" res.Err = "update already started"

@ -123,6 +123,10 @@ func getControlDebugFlags() []string {
type SSHServer interface { type SSHServer interface {
HandleSSHConn(net.Conn) error HandleSSHConn(net.Conn) error
// NumActiveConns returns the number of connections passed to HandleSSHConn
// that are still active.
NumActiveConns() int
// OnPolicyChange is called when the SSH access policy changes, // OnPolicyChange is called when the SSH access policy changes,
// so that existing sessions can be re-evaluated for validity // so that existing sessions can be re-evaluated for validity
// and closed if they'd no longer be accepted. // and closed if they'd no longer be accepted.

@ -143,6 +143,13 @@ func (srv *server) trackActiveConn(c *conn, add bool) {
delete(srv.activeConns, c) delete(srv.activeConns, c)
} }
// NumActiveConns returns the number of active SSH connections.
func (srv *server) NumActiveConns() int {
srv.mu.Lock()
defer srv.mu.Unlock()
return len(srv.activeConns)
}
// HandleSSHConn handles a Tailscale SSH connection from c. // HandleSSHConn handles a Tailscale SSH connection from c.
// This is the entry point for all SSH connections. // This is the entry point for all SSH connections.
// When this returns, the connection is closed. // When this returns, the connection is closed.

Loading…
Cancel
Save