Hi golangbride community, I have a simple ssh client in go and I’m trying to detect when an active ssh.Client loses its connection to the ssh server.
Here is a minimal example:
func main() {
quit := make(chan bool)
config := &ssh.ClientConfig{
User: "user",
Auth: []ssh.AuthMethod{
ssh.Password("password"),
},
}
client, err := ssh.Dial("tcp", "localhost:22", config)
if err != nil {
log.Fatal(err)
}
go func() {
// check if connection is still alive
// client.Wait() does not return if the network of the
// client is down or if the server is turned of
err := client.Wait()
if err != nil {
log.Print(err)
}
quit <- true
}()
<-quit
}
I also tried to create and close new sessions periodicly on the client with:
A long time ago I monkey patched the ssh package with this for the purpose:
package ssh
func (c *ClientConn) CheckServerAlive() error {
_, err := c.sendGlobalRequest(globalRequestMsg{"keepalive@openssh.com", true})
if err == nil || err.Error() == "request failed" {
// Any response is a success.
return nil
}
return err
}
The package has evolved a bit since then so maybe that doesn’t fit as is, but the concept should be the same.
The unusual error handling is because a server that does not support keepalives may result in that error, but they are still alive. I’m sure it could be made more robust, this was years ago when I was writing my first lines of Go.
(Also, your sessions from the second loop above don’t get closed, as defer only runs as the function exits. Otherwise you could probably still do that, but combine with a timeout.)
Hello and thank you calmh, but unfortunately the go ssh package seems to have changed since your solution. CientConn is no more and if possible i need a working solution without touching the ssh package.
I tried send a request via ssh.Client.Conn.sendRequest() but this also blocks endlessly if the network goes down.
The general approach, not just with the ssh package, is the best way to tell if a connection is alive is to use it. If you do some kind of probe, then use the connection, an unknown amount of time has passed between those two operations, so the previous value may be out of date.
Yeah. The reason for my keepalives above was mostly to keep the connection alive through NAT boxes when it wasn’t being used, as the usage was for tunneling that may or may not be in use from time to time.