From 53ef7f92cb08ff60985624263bf004eb43c493b3 Mon Sep 17 00:00:00 2001 From: Gesa Stupperich Date: Fri, 19 Jun 2026 10:33:50 +0100 Subject: [PATCH] sessionrecording: close idle connections after upload If we don't close the connection between SSH server and recorder explicitly once it's idle after the upload stream is closed, the connection stays open and holds on to a port on the server. This leads to port exhaustion on the server in the medium to long run. To avoid this, close the idle connections explicitly. As an extra step of precaution, set an idleConnTimeout of 30 seconds on both the HTTP1 and HTTP2 recorder clients. Updates tailscale/corp#43742 Signed-off-by: Gesa Stupperich --- sessionrecording/connect.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sessionrecording/connect.go b/sessionrecording/connect.go index 927ba7d30..6154c4e8d 100644 --- a/sessionrecording/connect.go +++ b/sessionrecording/connect.go @@ -39,6 +39,9 @@ // in tests. var uploadAckWindow = 30 * time.Second +// idleConnTimeout is the idle timeout for connections to the recorder. +var idleConnTimeout = 30 * time.Second + // ConnectToRecorder connects to the recorder at any of the provided addresses. // It returns the first successful response, or a multierr if all attempts fail. // @@ -234,6 +237,7 @@ func connectV1(ctx context.Context, hc *http.Client, ap netip.AddrPort) (io.Writ // errChan is used to indicate the result of the request. errChan := make(chan error, 1) go func() { + defer hc.CloseIdleConnections() defer close(errChan) resp, err := hc.Do(req) if err != nil { @@ -292,6 +296,7 @@ func connectV2(ctx context.Context, hc *http.Client, ap netip.AddrPort) (io.Writ acks := make(chan int64) // Read acks from the response and send them to the acks channel. go func() { + defer hc.CloseIdleConnections() defer close(errChan) defer close(acks) defer resp.Body.Close() @@ -394,6 +399,7 @@ func clientHTTP1(dialCtx context.Context, dial netx.DialFunc) *http.Client { }() return dial(perAttemptCtx, network, addr) } + tr.IdleConnTimeout = idleConnTimeout return &http.Client{Transport: tr} } @@ -418,6 +424,7 @@ func clientHTTP2(dialCtx context.Context, dial netx.DialFunc) *http.Client { }() return dial(perAttemptCtx, network, addr) }, + IdleConnTimeout: idleConnTimeout, }, } }