python-socks
Proxy (SOCKS4, SOCKS5, HTTP CONNECT) client for Python
Description
## python-socks [](https://github.com/romis2012/python-socks/actions/workflows/ci.yml) [](https://codecov.io/gh/romis2012/python-socks) [](https://pypi.python.org/pypi/python-socks) [](https://github.com/romis2012/python-socks) <!-- [](https://pepy.tech/project/python-socks) --> The `python-socks` package provides a core proxy client functionality for Python. Supports `SOCKS4(a)`, `SOCKS5(h)`, `HTTP CONNECT` proxy and provides sync and async (asyncio, trio, curio, anyio) APIs. You probably don't need to use `python-socks` directly. It is used internally by [aiohttp-socks](https://github.com/romis2012/aiohttp-socks) and [httpx-socks](https://github.com/romis2012/httpx-socks) packages. ## Requirements - Python >= 3.8 - async-timeout >= 4.0 (optional) - trio >= 0.24 (optional) - curio >= 1.4 (optional) - anyio >= 3.3.4 (optional) ## Installation only sync proxy support: ``` pip install python-socks ``` to include optional asyncio support: ``` pip install python-socks[asyncio] ``` to include optional trio support: ``` pip install python-socks[trio] ``` to include optional curio support: ``` pip install python-socks[curio] ``` to include optional anyio support: ``` pip install python-socks[anyio] ``` ## Simple usage We are making secure HTTP GET request via SOCKS5 proxy #### Sync ```python import ssl from python_socks.sync import Proxy proxy = Proxy.from_url('socks5://user:password@127.0.0.1:1080') # `connect` returns standard Python socket in blocking mode sock = proxy.connect(dest_host='check-host.net', dest_port=443) sock = ssl.create_default_context().wrap_socket( sock=sock, server_hostname='check-host.net' ) request = ( b'GET /ip HTTP/1.1\r\n' b'Host: check-host.net\r\n' b'Connection: close\r\n\r\n' ) sock.sendall(request) response = sock.recv(4096) print(response) ``` #### Async (asyncio) ```python import ssl import asyncio from python_socks.async_.asyncio import Proxy proxy = Proxy.from_url('socks5://user:password@127.0.0.1:1080') # `connect` returns standard Python socket in non-blocking mode # so we can pass it to asyncio.open_connection(...) sock = await proxy.connect(dest_host='check-host.net', dest_port=443) reader, writer = await asyncio.open_connection( host=None, port=None, sock=sock, ssl=ssl.create_default_context(), server_hostname='check-host.net', ) request = ( b'GET /ip HTTP/1.1\r\n' b'Host: check-host.net\r\n' b'Connection: close\r\n\r\n' ) writer.write(request) response = await reader.read(-1) print(response) ``` #### Async (trio) ```python import ssl import trio from python_socks.async_.trio import Proxy proxy = Proxy.from_url('socks5://user:password@127.0.0.1:1080') # `connect` returns trio socket # so we can pass it to trio.SocketStream sock = await proxy.connect(dest_host='check-host.net', dest_port=443) stream = trio.SocketStream(sock) stream = trio.SSLStream( stream, ssl.create_default_context(), server_hostname='check-host.net' ) await stream.do_handshake() request = ( b'GET /ip HTTP/1.1\r\n' b'Host: check-host.net\r\n' b'Connection: close\r\n\r\n' ) await stream.send_all(request) response = await stream.receive_some(4096) print(response) ``` #### Async (curio) ```python import curio.ssl as curiossl from python_socks.async_.curio import Proxy proxy = Proxy.from_url('socks5://user:password@127.0.0.1:1080') # `connect` returns curio.io.Socket sock = await proxy.connect( dest_host='check-host.net', dest_port=443 ) request = ( b'GET /ip HTTP/1.1\r\n' b'Host: check-host.net\r\n' b'Connection: close\r\n\r\n' ) ssl_context = curiossl.create_default_context() sock = await ssl_context.wrap_socket( sock, do_handshake_on_connect=False, server_hostname='check-host.net' ) await sock.do_handshake() stream = sock.as_stream() await stream.write(request) response = await stream.read(1024) print(response) ``` #### Async (anyio) ```python import ssl from python_socks.async_.anyio import Proxy proxy = Proxy.from_url('socks5://user:password@127.0.0.1:1080') # `connect` returns AnyioSocketStream stream = await proxy.connect( dest_host='check-host.net', dest_port=443, dest_ssl=ssl.create_default_context(), ) request = ( b'GET /ip HTTP/1.1\r\n' b'Host: check-host.net\r\n' b'Connection: close\r\n\r\n' ) await stream.write_all(request) response = await stream.read() print(response) ``` ## More complex example #### A urllib3 PoolManager that routes connections via the proxy ```python from urllib3 import PoolManager, HTTPConnectionPool, HTTPSConnectionPool from urllib3.connection import HTTPC
Release History
| Version | Changes | Urgency | Date |
|---|---|---|---|
| 2.8.1 | Imported from PyPI (2.8.1) | Low | 4/21/2026 |
| v2.8.1 | Fix socks5 reply reading by @rigens (#46) | Low | 2/16/2026 |
| v2.8.0 | Add `ProxyException` base class | Low | 12/9/2025 |
| v2.7.3 | Release v2.7.3 | Low | 11/10/2025 |
| v2.7.2 | Avoid leaking an open socket (trio) by @aaugustin (#44) | Low | 8/1/2025 |
| v2.7.1 | Close socket on loop.sock_connect(...) error by @aaugustin (#40) | Low | 2/1/2025 |
| v2.7.0 | Release v2.7.0 | Low | 1/28/2025 |
| v2.6.1 | Release v2.6.1 | Low | 12/27/2024 |
| v2.6.0 | Release v2.6.0 | Low | 12/26/2024 |
| v2.5.3 | Release v2.5.3 | Low | 10/6/2024 |
| v2.5.2 | Release v2.5.2 | Low | 9/25/2024 |
| v2.5.1 | Release v2.5.1 | Low | 8/21/2024 |
| v2.5.0 | Release v2.5.0 | Low | 6/25/2024 |
| v2.4.4 | Release v2.4.4 | Low | 12/8/2023 |
| v2.4.3 | Release v2.4.3 | Low | 9/26/2023 |
| v2.4.2 | Release v2.4.2 | Low | 9/11/2023 |
| v2.4.1 | Release v2.4.1 | Low | 9/8/2023 |
| v2.4.0 | Release v2.4.0 | Low | 9/8/2023 |
| v2.3.0 | Release v2.3.0 | Low | 5/8/2023 |
| v2.2.0 | Release v2.2.0 | Low | 3/13/2023 |
| v2.1.1 | Release v2.1.1 | Low | 12/19/2022 |
| v2.1.0 | Release v2.1.0 | Low | 12/18/2022 |
| v2.0.3 | Fix anyio exception handling | Low | 1/22/2022 |
| v2.0.2 | Fixed #14 anyio.BrokenResourceError has no attribute 'strerror' | Low | 1/13/2022 |
| v2.0.1 | Release v2.0.1 | Low | 12/17/2021 |
| v2.0.0 | - Added anyio backend - Added new (v2) API for sync and trio backends - The code base has been completely redesigned | Low | 11/23/2021 |
| v1.2.4 | Release v1.2.4 | Low | 3/30/2021 |
| v1.2.3 | Release v1.2.3 | Low | 3/23/2021 |
| v1.2.2 | Release v1.2.2 | Low | 3/1/2021 |
| v1.2.1 | Release v1.2.1 | Low | 2/16/2021 |
| v1.2.0 | Release v1.2.0 | Low | 1/17/2021 |
| v1.1.3 | Release v1.1.3 | Low | 1/16/2021 |
| v1.1.2 | Release v1.1.2 | Low | 12/16/2020 |
| v1.1.1 | Release v1.1.1 | Low | 11/22/2020 |
| v1.1.0 | Add curio backend support | Low | 9/21/2020 |
| v1.0.1 | Release v1.0.1 | Low | 9/20/2020 |
