mirror of
https://github.com/henrygd/beszel.git
synced 2026-09-30 05:17:49 +02:00
fix(hub): bound SSH handshake so a silent peer can't hang the updater
ssh.ClientConfig.Timeout only covers the TCP connect. A peer that accepts the connection but never sends an SSH banner blocked ssh.NewClientConn forever, wedging the system's updater goroutine and leaking the socket. Set a deadline on the conn for the handshake and clear it afterward.
This commit is contained in:
@@ -992,6 +992,12 @@ func (s *System) createSSHClient() error {
|
||||
// per-operation timeout in runSSHOperation instead (see issue #2041).
|
||||
const sshKeepAliveInterval = 30 * time.Second
|
||||
|
||||
// sshHandshakeTimeout bounds the SSH handshake after the TCP connection is
|
||||
// established. ssh.ClientConfig.Timeout only covers the TCP connect, so a peer
|
||||
// that accepts the connection but never sends an SSH banner would otherwise
|
||||
// block the updater forever.
|
||||
var sshHandshakeTimeout = 10 * time.Second
|
||||
|
||||
// dialSSHWithKeepAlive dials an SSH connection like ssh.Dial, but enables TCP
|
||||
// keep-alive on the underlying connection so half-open connections are
|
||||
// eventually detected by the operating system.
|
||||
@@ -1004,11 +1010,14 @@ func dialSSHWithKeepAlive(network, addr string, config *ssh.ClientConfig) (*ssh.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = conn.SetDeadline(time.Now().Add(sshHandshakeTimeout))
|
||||
sshConn, chans, reqs, err := ssh.NewClientConn(conn, addr, config)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
// clear the handshake deadline so it doesn't apply to the long-lived connection
|
||||
_ = conn.SetDeadline(time.Time{})
|
||||
return ssh.NewClient(sshConn, chans, reqs), nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user