websockets icon indicating copy to clipboard operation
websockets copied to clipboard

Add support for SOCKS proxies to connect()

Open aaugustin opened this issue 7 years ago • 12 comments

EDIT - until this is implemented, the workaround consists in creating a socket connected to a socks proxy e.g. with https://pypi.org/project/python-socks/, then connect(sock=...).

See https://github.com/python-websockets/websockets/issues/475#issuecomment-1268504779 for details.

aaugustin avatar Sep 23 '18 14:09 aaugustin

would be a great feature!

oliver-zehentleitner avatar Apr 22 '19 19:04 oliver-zehentleitner

The status of this is:

  • I'm not sure it's reasonable to write a custom SOCKS implementation (not sure what's involved exactly but I assume it isn't trivial).
  • I'm not finding a SOCKS implementation that I could easily graft into websockets and that I'm willing to add as a dependency.

aaugustin avatar Jun 30 '19 12:06 aaugustin

I looked at what a minimal client implementation of SOCKS v5 would involve.

  • SOCKS v5 - RFC 1928 looks doable.
  • Username / password authentication RFC 1928 is trivial.
  • GSS-API authententication RFC 1961 looks complicated.

RFC 1928 says that "compliant implementations MUST support GSSAPI" but perhaps a non-compliant implementation would still be useful :-)

I don't think SOCKS v4 is worth investigating at this point.

aaugustin avatar Jun 30 '19 13:06 aaugustin

I think that proxy/different transports should not have to be implemented as part of this library. The key point IMO is to support for it with an API that accepts a specific interface, for example by having a well-tailored way to strap the protocol on top of a different asyncio.StreamReader/asyncio.StreamWriter pair.

Edit: I would even go as far as to say that any different transport implementations (read: reader/writer pair) are out of scope for this library. Keep it simple. (However, that doesn't prevent you from writing a small SOCKS transport library and recommending it.)

lgrahl avatar Jul 01 '19 08:07 lgrahl

An asyncio protocol protocol can be layered on top of another protocol. WebSocketClientProtocol could connect to a SocksProtocol which connects to a transport. Then we need a developer-friendly way to (auto-)configure this.

aaugustin avatar Jul 01 '19 11:07 aaugustin

What is the current status regarding the support of socks5? Has there been any progress? I've checked the 3 points needed to have fully implement this. Are these points something that can be done easily (by myself even) or whether someone has checked whether a library can be used (like PySocks)?

Narzhan avatar May 18 '20 12:05 Narzhan

No progress.

aaugustin avatar May 19 '20 12:05 aaugustin

Hi, just wanted to write a bit about my experience trying to use a socks proxy with this library (it worked!)

Basically my code goes something like this (I'm connecting to an .onion service):

from urllib.parse import urlparse

import socks
import websockets

URL = "https://xxxxxxxxxxx.onion"

async def main():
    netloc = urlparse(URL).netloc
    ws_url = f"wss://{netloc}/ws"

    # Disable SSL verification (self-signed certificate)
    ssl_context = ssl.SSLContext()
    ssl_context.verify_mode = ssl.CERT_NONE
    ssl_context.check_hostname = False

    # Initialize the connection to the server through the proxy
    tor_proxy = socks.socksocket()
    tor_proxy.set_proxy(socks.SOCKS5, "localhost", 9050)
    tor_proxy.connect((netloc, 443))

    # No ping and high timeout since tor is slow
    websocket = await websockets.connect(
        ws_url, ssl=ssl_context,
        sock=tor_proxy,
        server_hostname=netloc,
        ping_interval=None,
        ping_timeout=None,
        open_timeout=60
    )

That was it!

Not really straightforward, but it works :)

[EDIT]: Forgot to mention it, the socks import is from the PySocks package.

cxs-kge avatar Oct 05 '22 14:10 cxs-kge

That's the most reasonable way to do it for your use case that I can think of.

aaugustin avatar Oct 05 '22 20:10 aaugustin

hi, How are we looking on this? is there any way to support HTTP TLS pass-through proxy? similarly to how AIOHTTP client does https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientSession.ws_connect

mattkoltun avatar Dec 01 '22 08:12 mattkoltun

@aaugustin hey, I created a package which exposes a subclass of connect with the additional proxy keyword argument. https://github.com/racinette/websockets_proxy

racinette avatar Dec 21 '23 10:12 racinette

Thank you for sharing! I'm glad that you provided a third party solution, as this is one of the few long-lasting feature gaps in websockets.

aaugustin avatar Dec 21 '23 14:12 aaugustin