feat(forward): ForwardTracker Protocol for local-forward lifecycle hooks#807
feat(forward): ForwardTracker Protocol for local-forward lifecycle hooks#807AlexMKX wants to merge 1 commit into
Conversation
Adds optional tracker kwarg to SSHClientConnection.forward_local_port that accepts a ForwardTracker (typing.Protocol) with two hooks: connection_made(orig_host, orig_port) -> None connection_lost(orig_host, orig_port, exc) -> None The hooks fire on every client connect/disconnect on the local listener. Hook exceptions are swallowed so a buggy tracker cannot break the forwarder. Backward compatible: tracker defaults to None, preserving existing behavior with no overhead. Use case: passive observation of local-forward activity (idle-based auto-shutdown, byte counters, etc.) without modifying transport code.
|
Thanks for the PR. Could you say a little more about the use case you have in mind for this? I'm not really seeing how this would be able to do things like byte counts or idle tracking if you are only sending connection_made and connection_lost messages through the tracker. I'm wondering if some of this could be handled by using the existing accept_handler. It only runs right now on a new client connection coming in, giving you the client IP address and port and even lets you decide based on that whether to allow the forwarded connection or not. It doesn't currently run when a connection closes (either cleanly or with an error), but that could be added as something like an error_handler. In the future, support for a progress_handler could also be added here to report on bytes transferred, much like what exists in AsyncSSH right now for the SFTP/SCP file copy functions. |
|
Hello @ronf, thank you for the questions. The main use case I have in mind is handling idle forwarded connections. This came from a practical need in this tool: https://github.com/AlexMKX/garuda-tunnel It is basically a “poor man's Teleport” for automating Kubernetes access through Terraform or an Ansible Kubernetes inventory source. It runs as a daemon, exposes local ports through a bastion, and uses AsyncSSH under the hood. For safety and operational visibility, I would like to track the number of live forwarded connections and apply an idle timeout to traffic going through the mapped ports. A per-byte counter would be better, of course, but for this use case an active connection count is a reasonable first approximation without inviting a whole committee of extra machinery into the room. I agree that accept_handler is close to this area. The main gap is that it currently only covers the beginning of the connection. Having something symmetrical for connection close, perhaps an error_handler or close_handler, would probably solve a good part of this. A future progress_handler for byte counts would also be useful and would fit nicely with what AsyncSSH already does for SFTP/SCP transfers. So I am not strongly attached to the exact tracker API shape from the PR. The important part for me is having a lightweight way to observe connection lifecycle events for forwarded connections, and later possibly traffic progress, without each user of port forwarding having to rebuild that logic around AsyncSSH internals. |
|
Thanks for the added context... I'm in the middle of some other feature work at the moment, but once that's wrapped up I'll take a closer look at this, probably in the next couple of weeks. I'm thinking that you could still have a In fact, you could probably have a factory method on |
Adds optional tracker kwarg to SSHClientConnection.forward_local_port that accepts a ForwardTracker (typing.Protocol) with two hooks:
connection_made(orig_host, orig_port) -> None
connection_lost(orig_host, orig_port, exc) -> None
The hooks fire on every client connect/disconnect on the local listener. Hook exceptions are swallowed so a buggy tracker cannot break the forwarder.
Backward compatible: tracker defaults to None, preserving existing behavior with no overhead.
Use case: passive observation of local-forward activity (idle-based auto-shutdown, byte counters, etc.) without modifying transport code.