aboutsummaryrefslogtreecommitdiff
path: root/rsh
diff options
context:
space:
mode:
authorLena <lena@omega>2026-07-01 00:00:00 +0000
committerLena <lena@omega>2026-07-01 00:00:00 +0000
commita6640c603b7a15d3531980116fdce15d1743c865 (patch)
tree64559109ced762369d190105833e3294993d4d40 /rsh
parent8141ea0b4e29644327e3ba579e2caf083c50f6f6 (diff)
downloadrsend-a6640c603b7a15d3531980116fdce15d1743c865.tar.gz
rsh: bound the SSH handshake
ssh.Dial applies its Timeout only to the TCP connect, so a host that accepts the connection and then stalls the SSH handshake hangs the sync forever. Dial with a timeout, run the handshake under a deadline, and clear the deadline once the connection is established.
Diffstat (limited to 'rsh')
-rw-r--r--rsh/main.go19
1 files changed, 18 insertions, 1 deletions
diff --git a/rsh/main.go b/rsh/main.go
index dfcea0b..68b6e49 100644
--- a/rsh/main.go
+++ b/rsh/main.go
@@ -203,7 +203,24 @@ func dial(user, host string, hostKey ssh.HostKeyCallback) (*ssh.Client, error) {
Timeout: dialTimeout,
}
addr := net.JoinHostPort(host, strconv.Itoa(port))
- return ssh.Dial("tcp", addr, cfg)
+ conn, err := net.DialTimeout("tcp", addr, dialTimeout)
+ if err != nil {
+ return nil, err
+ }
+ if err := conn.SetDeadline(time.Now().Add(dialTimeout)); err != nil {
+ conn.Close()
+ return nil, err
+ }
+ clientConn, chans, reqs, err := ssh.NewClientConn(conn, addr, cfg)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+ if err := conn.SetDeadline(time.Time{}); err != nil {
+ clientConn.Close()
+ return nil, err
+ }
+ return ssh.NewClient(clientConn, chans, reqs), nil
}
// parseTransport extracts the user, host, and remote command from the argument