honzasp / makiko

Asynchronous SSH client library in pure Rust
https://honzasp.github.io/makiko/
The Unlicense
39 stars 3 forks source link

SSH-level keep-alive support #6

Closed kyrias closed 2 months ago

kyrias commented 3 months ago

I'm trying to use makiko to do some remote automation work where I need SSH port forwarding, but I'm having the issue where sometimes there are long periods between when the SSH channel is actually used, and so sometimes they end up having timed out by the time I need to use them again, which would require some moderately complex abstraction to be able to work around.

It would be nice if makiko instead supported SSH-level keep-alive à la OpenSSH's ServerAliveInterval/ServerAliveCountMax which send null packets through the encrypted channel.

honzasp commented 3 months ago

Hi, thanks for filing an issue! :) I see that Makiko currently skips empty data packets, so if you call Tunnel::send_data() with empty data, nothing will be sent over the wire. Would your issue be solved if Makiko did send an explicit empty packet if you ask it to? Or would you need some additional API to send those keepalive packets automatically, without changing your code?

kyrias commented 2 months ago

Hey,

While I think it would be nice if there was built-in keep-alive support, it would probably be good enough if there was a way to trigger it manually. Tunnel::send_data doesn't quite work for us though because in the periods between API calls there is no active tunnel as they're established on-demand as the HTTP client decides to establish a connection (the HTTP client connects to a UNIX domain socket which then triggers a Client::connect_tunnel call), so we'd need some way to do it using the Client directly.

honzasp commented 2 months ago

Ok, so I had a look at how OpenSSH does this, and they periodically send a bogus global request of type keepalive@openssh.com, requesting a response (which should always be a failure).

Makiko exposes a low-level mechanism that you can use to send this global request manually (using GlobalReq with request_type = "keepalive@openssh.com", empty payload, and reply_tx set to Some(_)).

However, I'll add a high-level method that does this, to make this functionality more easily accessible without messing with details of the SSH protocol.

honzasp commented 2 months ago

Another option would be to send messages of type SSH_MSG_IGNORE, which will be ignored by the peer, but the safest choice is probably to follow the OpenSSH behavior.

honzasp commented 2 months ago

I published Makiko 0.2.3 which adds method Client::send_keepalive() which sends the keepalive@openssh.com request.