Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SSH Connection Timeout

Tags:

ssh

go

I am trying to make SSH connections using golang.org/x/crypto/ssh and I am kinda surprised that I can't seem to find out how to timeout the NewSession function (I actually don't seen any way to timeout anything). When I try to connect to a server that is having issues, this just hangs for a very long time. I have written something to use select with a time.After but it just feels like a hack. Something I haven't tried yet is to keep the underlying net.Conn in my struct and just keep doing Conn.SetDeadline() calls. Haven't tried this yet because I don't know if the crypto/ssh library overrides this or anything like that.

Anyone have a good way to timeout dead servers with this library? Or does anyone know of a better library?

like image 500
user3591723 Avatar asked Jul 22 '15 05:07

user3591723


People also ask

How do I fix SSH connection timeout?

The user will require to increase the SSH connection timeout to solve this problem; It can be done in two ways. One way is to set the keep-alive options in the server configuration file, and another way is to set the keep-alive option in the client configuration file.

Why does my SSH connection timeout?

This error message comes from the SSH client. The error indicates that the server didn't respond to the client and the client program gave up (timed out). The following are common causes for this error: The security group or network ACL doesn't allow access.

How long is SSH timeout?

Some systems use a default as low as five seconds, and some go as high as two hours; the average is typically around three to five minutes. Your SSH connection, if it has not been modified to change the timeout on either the server or client end, will use this timeout.

How do I fix SSH port timed out connection 22?

Incorrect IP address or hostname – The error may be due to a simple typo. Before you check anything else, make sure you're trying to connect to the correct server. Incorrect SSH port number – By default, servers listen for SSH connections on port 22.


2 Answers

One way to handle this transparently with the ssh package, is to create a connection with an idle timeout via a custom net.Conn which sets deadlines for you. However, this will cause the background Reads on a connection to timeout, so we need to use ssh keepalives to keep the connection open. Depending on your use case, simply using ssh keepalives as an alert for a dead connection may suffice.

// Conn wraps a net.Conn, and sets a deadline for every read
// and write operation.
type Conn struct {
    net.Conn
    ReadTimeout  time.Duration
    WriteTimeout time.Duration
}

func (c *Conn) Read(b []byte) (int, error) {
    err := c.Conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))
    if err != nil {
        return 0, err
    }
    return c.Conn.Read(b)
}

func (c *Conn) Write(b []byte) (int, error) {
    err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
    if err != nil {
        return 0, err
    }
    return c.Conn.Write(b)
}

You can then use net.DialTimeout or a net.Dialer to get the connection, wrap it in your Conn with timeouts, and pass it into ssh.NewClientConn.

func SSHDialTimeout(network, addr string, config *ssh.ClientConfig, timeout time.Duration) (*ssh.Client, error) {
    conn, err := net.DialTimeout(network, addr, timeout)
    if err != nil {
        return nil, err
    }

    timeoutConn := &Conn{conn, timeout, timeout}
    c, chans, reqs, err := ssh.NewClientConn(timeoutConn, addr, config)
    if err != nil {
        return nil, err
    }
    client := ssh.NewClient(c, chans, reqs)

    // this sends keepalive packets every 2 seconds
    // there's no useful response from these, so we can just abort if there's an error
    go func() {
        t := time.NewTicker(2 * time.Second)
        defer t.Stop()
        for range t.C {
            _, _, err := client.Conn.SendRequest("[email protected]", true, nil)
            if err != nil {
                return
            }
        }
    }()
    return client, nil
}
like image 171
JimB Avatar answered Oct 21 '22 09:10

JimB


Set the timeout on the ssh.ClientConfig.

cfg := ssh.ClientConfig{
    User: "root",
    Auth: []ssh.AuthMethod{
        ssh.PublicKeys(signer),
    },
    HostKeyCallback: ssh.FixedHostKey(hostKey),
    Timeout:         15 * time.Second, // max time to establish connection
}

ssh.Dial("tcp", ip+":22", &cfg)

When you call ssh.Dial, the timeout will be passed to net.DialTimeout.

like image 29
ryboe Avatar answered Oct 21 '22 07:10

ryboe