Skip to content
4 changes: 3 additions & 1 deletion asyncssh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from .config import ConfigParseError

from .forward import SSHForwarder
from .forward import SSHPathForwardTracker, SSHPortForwardTracker

from .connection import SSHAcceptor, SSHClientConnection, SSHServerConnection
from .connection import SSHClientConnectionOptions, SSHServerConnectionOptions
Expand Down Expand Up @@ -148,7 +149,8 @@
'SSHClientChannel', 'SSHClientConnection', 'SSHClientConnectionOptions',
'SSHClientProcess', 'SSHClientSession', 'SSHCompletedProcess',
'SSHForwarder', 'SSHKey', 'SSHKeyPair', 'SSHKnownHosts',
'SSHLineEditorChannel', 'SSHListener', 'SSHReader', 'SSHServer',
'SSHLineEditorChannel', 'SSHListener', 'SSHPathForwardTracker',
'SSHPortForwardTracker', 'SSHReader', 'SSHServer',
'SSHServerChannel', 'SSHServerConnection',
'SSHServerConnectionOptions', 'SSHServerProcess',
'SSHServerProcessFactory', 'SSHServerSession',
Expand Down
72 changes: 51 additions & 21 deletions asyncssh/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
from .encryption import get_encryption_params, get_encryption

from .forward import SSHForwarder
from .forward import SSHPortForwardTrackerFactory, SSHPathForwardTrackerFactory

from .gss import GSSBase, GSSClient, GSSServer, GSSError

Expand Down Expand Up @@ -3210,7 +3211,9 @@ async def forward_unix_connection(self, dest_path: str) -> SSHForwarder:
async def forward_local_port(
self, listen_host: str, listen_port: int,
dest_host: str, dest_port: int,
accept_handler: Optional[SSHAcceptHandler] = None) -> SSHListener:
accept_handler: Optional[SSHAcceptHandler] = None,
tracker_factory:
Optional[SSHPortForwardTrackerFactory] = None) -> SSHListener:
"""Set up local port forwarding

This method is a coroutine which attempts to set up port
Expand All @@ -3233,11 +3236,17 @@ async def forward_local_port(
or not to allow connection forwarding, returning `True` to
accept the connection and begin forwarding or `False` to
reject and close it.
:param tracker_factory:
An optional callable invoked once per accepted connection
which returns a new :class:`SSHPortForwardTracker` for observing
that connection's lifecycle. `None` (default) disables tracking
with no overhead.
:type listen_host: `str`
:type listen_port: `int`
:type dest_host: `str`
:type dest_port: `int`
:type accept_handler: `callable` or coroutine
:type tracker_factory: :class:`SSHPortForwardTrackerFactory`

:returns: :class:`SSHListener`

Expand Down Expand Up @@ -3278,10 +3287,9 @@ async def tunnel_connection(
(dest_host, dest_port))

try:
listener = await create_tcp_forward_listener(self, self._loop,
tunnel_connection,
listen_host,
listen_port)
listener = await create_tcp_forward_listener(
self, self._loop, tunnel_connection, listen_host, listen_port,
tracker_factory)
except OSError as exc:
self.logger.debug1('Failed to create local TCP listener: %s', exc)
raise
Expand All @@ -3297,8 +3305,10 @@ async def tunnel_connection(
return listener

@async_context_manager
async def forward_local_path(self, listen_path: str,
dest_path: str) -> SSHListener:
async def forward_local_path(
Comment thread
ronf marked this conversation as resolved.
self, listen_path: str, dest_path: str,
tracker_factory:
Optional[SSHPathForwardTrackerFactory] = None) -> SSHListener:
"""Set up local UNIX domain socket forwarding

This method is a coroutine which attempts to set up UNIX domain
Expand All @@ -3311,8 +3321,14 @@ async def forward_local_path(self, listen_path: str,
The path on the local host to listen on
:param dest_path:
The path on the remote host to forward the connections to
:param tracker_factory:
An optional callable invoked once per accepted connection
which returns a new :class:`SSHPathForwardTracker` for observing
that connection's lifecycle. `None` (default) disables tracking
with no overhead.
:type listen_path: `str`
:type dest_path: `str`
:type tracker_factory: :class:`SSHPathForwardTrackerFactory`

:returns: :class:`SSHListener`

Expand All @@ -3332,9 +3348,9 @@ async def tunnel_connection(
listen_path, dest_path)

try:
listener = await create_unix_forward_listener(self, self._loop,
tunnel_connection,
listen_path)
listener = await create_unix_forward_listener(
self, self._loop, tunnel_connection, listen_path,
tracker_factory)
except OSError as exc:
self.logger.debug1('Failed to create local UNIX listener: %s', exc)
raise
Expand Down Expand Up @@ -5304,7 +5320,9 @@ async def open_tap(self, *args: object, **kwargs: object) -> \
@async_context_manager
async def forward_local_port_to_path(
Comment thread
ronf marked this conversation as resolved.
self, listen_host: str, listen_port: int, dest_path: str,
accept_handler: Optional[SSHAcceptHandler] = None) -> SSHListener:
accept_handler: Optional[SSHAcceptHandler] = None,
tracker_factory:
Optional[SSHPortForwardTrackerFactory] = None) -> SSHListener:
"""Set up local TCP port forwarding to a remote UNIX domain socket

This method is a coroutine which attempts to set up port
Expand All @@ -5325,10 +5343,16 @@ async def forward_local_port_to_path(
or not to allow connection forwarding, returning `True` to
accept the connection and begin forwarding or `False` to
reject and close it.
:param tracker_factory:
An optional callable invoked once per accepted connection
which returns a new :class:`SSHPortForwardTracker` for observing
that connection's lifecycle. `None` (default) disables tracking
with no overhead.
:type listen_host: `str`
:type listen_port: `int`
:type dest_path: `str`
:type accept_handler: `callable` or coroutine
:type tracker_factory: :class:`SSHPortForwardTrackerFactory`

:returns: :class:`SSHListener`

Expand Down Expand Up @@ -5362,10 +5386,9 @@ async def tunnel_connection(
(listen_host, listen_port), dest_path)

try:
listener = await create_tcp_forward_listener(self, self._loop,
tunnel_connection,
listen_host,
listen_port)
listener = await create_tcp_forward_listener(
self, self._loop, tunnel_connection, listen_host, listen_port,
tracker_factory)
except OSError as exc:
self.logger.debug1('Failed to create local TCP listener: %s', exc)
raise
Expand All @@ -5378,9 +5401,10 @@ async def tunnel_connection(
return listener

@async_context_manager
async def forward_local_path_to_port(self, listen_path: str,
dest_host: str,
dest_port: int) -> SSHListener:
async def forward_local_path_to_port(
Comment thread
ronf marked this conversation as resolved.
self, listen_path: str, dest_host: str, dest_port: int,
tracker_factory:
Optional[SSHPathForwardTrackerFactory] = None) -> SSHListener:
"""Set up local UNIX domain socket forwarding to a remote TCP port

This method is a coroutine which attempts to set up UNIX domain
Expand All @@ -5395,9 +5419,15 @@ async def forward_local_path_to_port(self, listen_path: str,
The hostname or address to forward the connections to
:param dest_port:
The port number to forward the connections to
:param tracker_factory:
An optional callable invoked once per accepted connection
which returns a new :class:`SSHPathForwardTracker` for observing
that connection's lifecycle. `None` (default) disables tracking
with no overhead.
:type listen_path: `str`
:type dest_host: `str`
:type dest_port: `int`
:type tracker_factory: :class:`SSHPathForwardTrackerFactory`

:returns: :class:`SSHListener`

Expand All @@ -5417,9 +5447,9 @@ async def tunnel_connection(
listen_path, (dest_host, dest_port))

try:
listener = await create_unix_forward_listener(self, self._loop,
tunnel_connection,
listen_path)
listener = await create_unix_forward_listener(
self, self._loop, tunnel_connection, listen_path,
tracker_factory)
except OSError as exc:
self.logger.debug1('Failed to create local UNIX listener: %s', exc)
raise
Expand Down
Loading