From 0275e8158325e1fe83ccfa90225582e93995e88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20K=C3=B6tter?= Date: Sat, 7 Feb 2026 15:07:40 +0100 Subject: [PATCH 1/3] tunnel - reload config --- asyncssh/connection.py | 2 +- tests/test_forward.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/asyncssh/connection.py b/asyncssh/connection.py index e81a92c..362c4b6 100644 --- a/asyncssh/connection.py +++ b/asyncssh/connection.py @@ -438,7 +438,7 @@ async def _open_tunnel(tunnels: object, options: _Options, last_conn = conn conn = await connect(host, port, username=username, passphrase=options.passphrase, tunnel=conn, - config=config) + config=config, reload=True) conn.set_tunnel(last_conn) if options.canonicalize_hostname != 'always': diff --git a/tests/test_forward.py b/tests/test_forward.py index fa9ee24..a49ace9 100644 --- a/tests/test_forward.py +++ b/tests/test_forward.py @@ -379,6 +379,30 @@ async def test_proxy_jump(self): finally: os.remove('.ssh/config') + @asynctest + async def test_proxy_jump_user(self): + """Test connecting a tunnneled SSH connection using ProxyJump + with a User + """ + + write_file('.ssh/config', 'Host target\n' + ' Hostname localhost\n' + f' Port {self._server_port}\n' + f' ProxyJump jump\n' + '\n' + f'Host jump\n' + f' Hostname localhost\n' + f' Port {self._server_port}\n' + f' User jumper\n' + 'IdentityFile ckey\n', + 'w') + try: + async with self.connect(host='target', username='ckey'): + pass + finally: + os.remove('.ssh/config') + + @asynctest async def test_proxy_jump_multiple(self): """Test connecting a tunnneled SSH connection using ProxyJump""" From 7b2baa7416b7dbe20a6e7133533e5fa15c7d6eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20K=C3=B6tter?= Date: Sun, 8 Feb 2026 08:42:46 +0100 Subject: [PATCH 2/3] tests/forwarding using a dedicated Server for ProxyJump --- tests/test_forward.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/tests/test_forward.py b/tests/test_forward.py index a49ace9..db1d67a 100644 --- a/tests/test_forward.py +++ b/tests/test_forward.py @@ -247,6 +247,17 @@ def unix_connection_requested(self, dest_path): return self._upstream_conn +class _JumpServer(Server): + def __init__(self, remote_port): + self._remote_port = remote_port + + def begin_auth(self, username): + """user jumper is allowed to use this server""" + return username != "jumper" + + def connection_requested(self, dest_host, dest_port, orig_host, orig_port): + return dest_port == self._remote_port + class _CheckForwarding(ServerTestCase): """Utility functions for AsyncSSH forwarding unit tests""" @@ -384,6 +395,12 @@ async def test_proxy_jump_user(self): """Test connecting a tunnneled SSH connection using ProxyJump with a User """ + def jump_server(): + return _JumpServer(self._server_port) + + + jump_listener = await self.create_server(jump_server) + jump_port = jump_listener.get_port() write_file('.ssh/config', 'Host target\n' ' Hostname localhost\n' @@ -392,7 +409,7 @@ async def test_proxy_jump_user(self): '\n' f'Host jump\n' f' Hostname localhost\n' - f' Port {self._server_port}\n' + f' Port {jump_port}\n' f' User jumper\n' 'IdentityFile ckey\n', 'w') @@ -401,7 +418,8 @@ async def test_proxy_jump_user(self): pass finally: os.remove('.ssh/config') - + jump_listener.close() + await jump_listener.wait_closed() @asynctest async def test_proxy_jump_multiple(self): From da3306b6b0fbf368bef810c2d0e8a3e31b6177fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20K=C3=B6tter?= Date: Sun, 8 Feb 2026 09:14:41 +0100 Subject: [PATCH 3/3] Hostname is picked up from jump Port is not INFO:asyncssh:Opening SSH connection to 127.0.0.3, port 22 --- asyncssh/connection.py | 2 +- tests/test_forward.py | 30 +++++++++++++++++++----------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/asyncssh/connection.py b/asyncssh/connection.py index 362c4b6..22bcdaa 100644 --- a/asyncssh/connection.py +++ b/asyncssh/connection.py @@ -438,7 +438,7 @@ async def _open_tunnel(tunnels: object, options: _Options, last_conn = conn conn = await connect(host, port, username=username, passphrase=options.passphrase, tunnel=conn, - config=config, reload=True) + config=config, reload=False) conn.set_tunnel(last_conn) if options.canonicalize_hostname != 'always': diff --git a/tests/test_forward.py b/tests/test_forward.py index db1d67a..2f139da 100644 --- a/tests/test_forward.py +++ b/tests/test_forward.py @@ -395,6 +395,10 @@ async def test_proxy_jump_user(self): """Test connecting a tunnneled SSH connection using ProxyJump with a User """ + import logging + logging.basicConfig(level=logging.DEBUG, stream=sys.stdout) + asyncssh.set_log_level('DEBUG') + def jump_server(): return _JumpServer(self._server_port) @@ -402,17 +406,21 @@ def jump_server(): jump_listener = await self.create_server(jump_server) jump_port = jump_listener.get_port() - write_file('.ssh/config', 'Host target\n' - ' Hostname localhost\n' - f' Port {self._server_port}\n' - f' ProxyJump jump\n' - '\n' - f'Host jump\n' - f' Hostname localhost\n' - f' Port {jump_port}\n' - f' User jumper\n' - 'IdentityFile ckey\n', - 'w') + + write_file('.ssh/config', +f""" +Host jump + HostName 127.0.0.3 + Port {jump_port} + User jumper + +Host target + Hostname 127.0.0.2 + Port {self._server_port} + +Match final host 127.0.0.2 + ProxyJump jump +""".encode()) try: async with self.connect(host='target', username='ckey'): pass