From 8b929f079e5bd888f0c99e1065424e05a9ef06dd Mon Sep 17 00:00:00 2001 From: Abhinav Singh <126065+abhinavsingh@users.noreply.github.com> Date: Fri, 26 Apr 2024 12:00:35 +0530 Subject: [PATCH] Fix ssh tunnel use case (#1400) * Fix for `--enable-ssh-tunnel` use case * Update readme with correct instructions * Update readme --- README.md | 65 +++++++++++++++++++-------------------- proxy/core/ssh/handler.py | 12 ++++++-- proxy/proxy.py | 11 ++++--- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 83b68c6486..f147249d04 100644 --- a/README.md +++ b/README.md @@ -1303,17 +1303,16 @@ See [requirements-tunnel.txt](https://github.com/abhinavsingh/proxy.py/blob/deve | +------------+ | +----------+ | LOCAL | | | REMOTE | - | HOST | <== SSH ==== :8900 == | SERVER | + | HOST | <== SSH ==== :8900 == | PROXY | +------------+ | +----------+ :8899 proxy.py | | FIREWALL (allow tcp/22) -## What +### What -Proxy HTTP(s) requests made on a `remote` server through `proxy.py` server -running on `localhost`. +Proxy HTTP(s) requests made on a `remote` proxy server through `proxy.py` server running on `localhost`. ### How @@ -1335,7 +1334,7 @@ Start `proxy.py` as: ```console ❯ # On localhost -❯ proxy --enable-tunnel \ +❯ proxy --enable-ssh-tunnel \ --tunnel-username username \ --tunnel-hostname ip.address.or.domain.name \ --tunnel-port 22 \ @@ -2341,19 +2340,19 @@ To run standalone benchmark for `proxy.py`, use the following command from repo ```console ❯ proxy -h -usage: -m [-h] [--threadless] [--threaded] [--num-workers NUM_WORKERS] - [--enable-events] [--local-executor LOCAL_EXECUTOR] - [--backlog BACKLOG] [--hostname HOSTNAME] - [--hostnames HOSTNAMES [HOSTNAMES ...]] [--port PORT] - [--ports PORTS [PORTS ...]] [--port-file PORT_FILE] - [--unix-socket-path UNIX_SOCKET_PATH] - [--num-acceptors NUM_ACCEPTORS] [--tunnel-hostname TUNNEL_HOSTNAME] - [--tunnel-port TUNNEL_PORT] [--tunnel-username TUNNEL_USERNAME] +usage: -m [-h] [--tunnel-hostname TUNNEL_HOSTNAME] [--tunnel-port TUNNEL_PORT] + [--tunnel-username TUNNEL_USERNAME] [--tunnel-ssh-key TUNNEL_SSH_KEY] [--tunnel-ssh-key-passphrase TUNNEL_SSH_KEY_PASSPHRASE] - [--tunnel-remote-port TUNNEL_REMOTE_PORT] [--version] - [--log-level LOG_LEVEL] [--log-file LOG_FILE] - [--log-format LOG_FORMAT] [--open-file-limit OPEN_FILE_LIMIT] + [--tunnel-remote-port TUNNEL_REMOTE_PORT] [--threadless] + [--threaded] [--num-workers NUM_WORKERS] [--enable-events] + [--local-executor LOCAL_EXECUTOR] [--backlog BACKLOG] + [--hostname HOSTNAME] [--hostnames HOSTNAMES [HOSTNAMES ...]] + [--port PORT] [--ports PORTS [PORTS ...]] [--port-file PORT_FILE] + [--unix-socket-path UNIX_SOCKET_PATH] + [--num-acceptors NUM_ACCEPTORS] [--version] [--log-level LOG_LEVEL] + [--log-file LOG_FILE] [--log-format LOG_FORMAT] + [--open-file-limit OPEN_FILE_LIMIT] [--plugins PLUGINS [PLUGINS ...]] [--enable-dashboard] [--basic-auth BASIC_AUTH] [--enable-ssh-tunnel] [--work-klass WORK_KLASS] [--pid-file PID_FILE] [--openssl OPENSSL] @@ -2379,10 +2378,25 @@ usage: -m [-h] [--threadless] [--threaded] [--num-workers NUM_WORKERS] [--filtered-client-ips FILTERED_CLIENT_IPS] [--filtered-url-regex-config FILTERED_URL_REGEX_CONFIG] -proxy.py v2.4.4rc6.dev164+g73497f30 +proxy.py v2.4.4rc6.dev172+ge1879403.d20240425 options: -h, --help show this help message and exit + --tunnel-hostname TUNNEL_HOSTNAME + Default: None. Remote hostname or IP address to which + SSH tunnel will be established. + --tunnel-port TUNNEL_PORT + Default: 22. SSH port of the remote host. + --tunnel-username TUNNEL_USERNAME + Default: None. Username to use for establishing SSH + tunnel. + --tunnel-ssh-key TUNNEL_SSH_KEY + Default: None. Private key path in pem format + --tunnel-ssh-key-passphrase TUNNEL_SSH_KEY_PASSPHRASE + Default: None. Private key passphrase + --tunnel-remote-port TUNNEL_REMOTE_PORT + Default: 8899. Remote port which will be forwarded + locally for proxy. --threadless Default: True. Enabled by default on Python 3.8+ (mac, linux). When disabled a new thread is spawned to handle each client connection. @@ -2419,21 +2433,6 @@ options: --host and --port flags are ignored --num-acceptors NUM_ACCEPTORS Defaults to number of CPU cores. - --tunnel-hostname TUNNEL_HOSTNAME - Default: None. Remote hostname or IP address to which - SSH tunnel will be established. - --tunnel-port TUNNEL_PORT - Default: 22. SSH port of the remote host. - --tunnel-username TUNNEL_USERNAME - Default: None. Username to use for establishing SSH - tunnel. - --tunnel-ssh-key TUNNEL_SSH_KEY - Default: None. Private key path in pem format - --tunnel-ssh-key-passphrase TUNNEL_SSH_KEY_PASSPHRASE - Default: None. Private key passphrase - --tunnel-remote-port TUNNEL_REMOTE_PORT - Default: 8899. Remote port which will be forwarded - locally for proxy. --version, -v Prints proxy.py version. --log-level LOG_LEVEL Valid options: DEBUG, INFO (default), WARNING, ERROR, @@ -2506,7 +2505,7 @@ options: Default: None. Signing certificate to use for signing dynamically generated HTTPS certificates. If used, must also pass --ca-key-file and --ca-signing-key-file - --ca-file CA_FILE Default: /Users/abhinavsingh/Dev/proxy.py/.venv31010/l + --ca-file CA_FILE Default: /Users/abhinavsingh/Dev/proxy.py/.venv31013/l ib/python3.10/site-packages/certifi/cacert.pem. Provide path to custom CA bundle for peer certificate verification diff --git a/proxy/core/ssh/handler.py b/proxy/core/ssh/handler.py index ed6ea789ff..1281d4675e 100644 --- a/proxy/core/ssh/handler.py +++ b/proxy/core/ssh/handler.py @@ -8,9 +8,14 @@ :copyright: (c) 2013-present by Abhinav Singh and contributors. :license: BSD, see LICENSE for more details. """ +import logging import argparse from typing import TYPE_CHECKING +from .base import BaseSshTunnelHandler + + +logger = logging.getLogger(__name__) if TYPE_CHECKING: # pragma: no cover from ...common.types import HostPort @@ -20,7 +25,7 @@ pass -class SshHttpProtocolHandler: +class SshHttpProtocolHandler(BaseSshTunnelHandler): """Handles incoming connections over forwarded SSH transport.""" def __init__(self, flags: argparse.Namespace) -> None: @@ -32,4 +37,7 @@ def on_connection( origin: 'HostPort', server: 'HostPort', ) -> None: - pass + logger.debug('handle proxy request') + + def shutdown(self) -> None: + logger.debug('ssh handler shutdown') diff --git a/proxy/proxy.py b/proxy/proxy.py index 2350f4e88f..233893f15f 100644 --- a/proxy/proxy.py +++ b/proxy/proxy.py @@ -18,6 +18,7 @@ import threading from typing import TYPE_CHECKING, Any, List, Type, Optional, cast +from .core.ssh import SshTunnelListener, SshHttpProtocolHandler from .core.work import ThreadlessPool from .core.event import EventManager from .common.flag import FlagParser, flags @@ -284,13 +285,15 @@ def setup(self) -> None: @staticmethod def _setup_tunnel( flags: argparse.Namespace, - ssh_handler_klass: Type['BaseSshTunnelHandler'], - ssh_listener_klass: Any, + ssh_handler_klass: Optional[Type['BaseSshTunnelHandler']] = None, + ssh_listener_klass: Optional[Any] = None, **kwargs: Any, ) -> BaseSshTunnelListener: - tunnel = cast(Type[BaseSshTunnelListener], ssh_listener_klass)( + listener_klass = ssh_listener_klass or SshTunnelListener + handler_klass = ssh_handler_klass or SshHttpProtocolHandler + tunnel = cast(Type[BaseSshTunnelListener], listener_klass)( flags=flags, - handler=ssh_handler_klass(flags=flags), + handler=handler_klass(flags=flags), **kwargs, ) tunnel.setup()