From 504b58fa84d31c1fde398342fde9550389e26b8d Mon Sep 17 00:00:00 2001 From: Nalin Goel Date: Mon, 20 Dec 2021 09:11:04 -0800 Subject: [PATCH 1/2] Adding a protocol to connect to a remote host via HTTP Connect --- asyncssh/connection.py | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/asyncssh/connection.py b/asyncssh/connection.py index 8d0aa625..ff72fcab 100644 --- a/asyncssh/connection.py +++ b/asyncssh/connection.py @@ -27,6 +27,7 @@ import os import shlex import socket +import ssl import sys import tempfile import time @@ -195,6 +196,49 @@ async def create_connection( Tuple[SSHTCPChannel[bytes], SSHTCPSession[bytes]]: """Create an outbound tunnel connection""" +class HTTPConnectorProtocol: + """Protocol to open a HTTP Connect session to tunnel an SSH connection over""" + + def __init__( + self, proxy_host: str, proxy_port: int, ssl_context: Optional[ssl.SSLContext] = None + ) -> None: + self._proxy_host = proxy_host + self._proxy_port = proxy_port + self._ssl_context = ssl_context + + async def create_connection( + self, session_factory: SSHTCPSessionFactory[bytes], + remote_host: str, remote_port: int) -> \ + Tuple[SSHTCPChannel[bytes], SSHTCPSession[bytes]]: + + # making an ssl connection to proxy host + reader, writer = await asyncio.open_connection( + self._proxy_host, + self._proxy_port, + ssl=self._ssl_context, + ) + + # HTTP Connect request to the target host + cmd_connect = f"CONNECT {remote_host}:{remote_port} HTTP/1.1\r\n\r\n".encode("ASCII") + writer.write(cmd_connect) + + line = await reader.readline() + if not line.startswith(b"HTTP/1.1 200 "): + raise ChannelOpenError( + OPEN_CONNECT_FAILED, + f"Unexpected response: {line.decode('utf-8', errors='ignore')}" + ) + + async for line in reader: + if line == b"\r\n": + break + transport = writer.transport + protocol = protocol_factory() + transport.set_protocol(protocol) + protocol.connection_made(transport) + return transport, protocol + + class _TunnelListenerProtocol(_TunnelProtocol, Protocol): """Protocol to open a listener to tunnel SSH connections over""" From 4bc0d0205513222180cd700f83ba4e400e806835 Mon Sep 17 00:00:00 2001 From: Nalin Goel Date: Mon, 20 Dec 2021 09:11:04 -0800 Subject: [PATCH 2/2] Adding a protocol to connect to a remote host via HTTP Connect --- asyncssh/connection.py | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/asyncssh/connection.py b/asyncssh/connection.py index 8d0aa625..6a7a0563 100644 --- a/asyncssh/connection.py +++ b/asyncssh/connection.py @@ -27,6 +27,7 @@ import os import shlex import socket +import ssl import sys import tempfile import time @@ -195,6 +196,49 @@ async def create_connection( Tuple[SSHTCPChannel[bytes], SSHTCPSession[bytes]]: """Create an outbound tunnel connection""" +class HTTPConnectorTunnel: + """Protocol to open a HTTP Connect session to tunnel an SSH connection over""" + + def __init__( + self, proxy_host: str, proxy_port: int, ssl_context: Optional[ssl.SSLContext] = None + ) -> None: + self._proxy_host = proxy_host + self._proxy_port = proxy_port + self._ssl_context = ssl_context + + async def create_connection( + self, session_factory: SSHTCPSessionFactory[bytes], + remote_host: str, remote_port: int) -> \ + Tuple[SSHTCPChannel[bytes], SSHTCPSession[bytes]]: + + # making an ssl connection to proxy host + reader, writer = await asyncio.open_connection( + self._proxy_host, + self._proxy_port, + ssl=self._ssl_context, + ) + + # HTTP Connect request to the target host + cmd_connect = f"CONNECT {remote_host}:{remote_port} HTTP/1.1\r\n\r\n".encode("ASCII") + writer.write(cmd_connect) + + line = await reader.readline() + if not line.startswith(b"HTTP/1.1 200 "): + raise ChannelOpenError( + OPEN_CONNECT_FAILED, + f"Unexpected response: {line.decode('utf-8', errors='ignore')}" + ) + + async for line in reader: + if line == b"\r\n": + break + transport = writer.transport + protocol = protocol_factory() + transport.set_protocol(protocol) + protocol.connection_made(transport) + return transport, protocol + + class _TunnelListenerProtocol(_TunnelProtocol, Protocol): """Protocol to open a listener to tunnel SSH connections over"""