Discussion:
How should my libssh2-based client handle gratuitous keepalives from the ssh server?
Jeremy Friesner
2018-01-17 20:22:37 UTC
Permalink
Hi all,

I’ve got a GUI client program that uses libssh2 to connect via SSH to a vanilla sshd server (i.e. the one that ships with Debian Linux). Once it connects, it opens an ssh channel to send a few shell commands that collect some data from the server, and when it gets the responses back it closes the channel while keeping the SSH session open, and waits for the user to do something. This is all implemented using the non-blocking model, with an event loop based around select().

This is all working fine (and has been working fine for a number of years), but I’ve noticed that with some newer servers we connect to, after about 15 seconds of connected idle time, the sshd server starts spontaneously sending unrequested keepalive messages to the client. These messages are 68 bytes long each, and the server sends four of them, and then closes the connection (presumably because my client didnt’ respond to the keepalives).

If I look in the server’s /etc/ssh/sshd_config file, sure enough there is this:

ClientAliveInterval 15
ClientAliveCountMax 4

… so one work-around for the problem would probably be to change the server’s settings to disable this behavior, but I’d prefer to have a client that can handle keepalives properly, since I might not always be have permission to change settings on the server.

So my question is, how can my non-blocking client correctly handle (and respond to) these keepalive packets? Currently it just goes into a spinloop (because select() sees the bytes available-for-read on the socket, but I don’t know what libssh2 function to call in order to absorb them). I can recv() the bytes directly and throw them away myself, but that risks messing up libssh2’s internal state machines if I accidentally read any non-keepalive data, and in any case it doesn’t send a response back to the server, so the server will still hang up on me after a minute. I tried calling libssh2_poll() to see if that would allow the libssh2 code to read and handle the keepalives, but that didn’t seem to have any effect.

Is there a recommended way to handle this issue?

Thanks,
Jeremy

_______________________________________________
libssh2-devel https://cool.haxx.se
Peter Stuge
2018-01-20 00:45:14 UTC
Permalink
Post by Jeremy Friesner
ClientAliveInterval 15
..
Post by Jeremy Friesner
Is there a recommended way to handle this issue?
No. I don't think libssh2 supports dealing with packet when idle at all.

The real solution is to add a generic protocol handler function, which
will need a fair bit of work, but I think not a lot of rework.


//Peter
_______________________________________________
libssh2-devel https://cool.hax
Jeremy Friesner
2018-01-22 18:50:19 UTC
Permalink
Hi Peter,

Thanks for the information.

For the record, I worked around the problem by adding code such that when my libssh socket starts select()-ing as read-for-read during what should be an idle period, my program responds by setting up a command channel and sending a dummy ssh command (e.g. “echo hello”) to the server. That appears to be sufficient to cause libssh2 to aborb the received keepalive-ping-data and to keep the sshd server happy that my client is still alive.

-Jeremy
Post by Peter Stuge
Post by Jeremy Friesner
ClientAliveInterval 15
..
Post by Jeremy Friesner
Is there a recommended way to handle this issue?
No. I don't think libssh2 supports dealing with packet when idle at all.
The real solution is to add a generic protocol handler function, which
will need a fair bit of work, but I think not a lot of rework.
//Peter
_______________________________________________
libssh2-devel https://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel
_______________________________________________
libssh2-devel https://cool.haxx.se/cgi-bin/mailman/listin

Loading...