siosocks
[(https://github.com/pohmelie/siosocks/actions)
Sans-io socks 4/5 client/server library/framework.
Reasons
- No one-shot socks servers
- Sans-io
- asyncio-ready
twunnel3is dead aiosocksdo not mimicasyncio.open_connectionarguments (maybe dead too)- Fun
Features
- Only tcp connect (no bind, no udp)
- Both client and server
- Socks versions: 4, 4a, 5
- Socks5 auth: no auth, username/password
- Couple io backends: asyncio, trio, socketserver
- One-shot socks server (
python -m siosocks)
License
siosocks is offered under MIT license.
Requirements
- python 3.8+
IO implementation matrix
| Framework | Client | Server |
|---|---|---|
| asyncio | + | + |
| trio | + | + |
| socket | + |
Feel free to make it bigger :wink:
Usage
End user implementations mimic «parent» library api.
Client
- asyncio:
open_connection - trio:
open_tcp_stream
Extra keyword-only arguments:
socks_host: stringsocks_port: integersocks_version: integer (4 or 5)username: optional string (default:None)password: optional string (default:None)encoding: optional string (default:"utf-8")socks4_extras: optional dictionarysocks5_extras: optional dictionary
Extras:
- socks4
user_id: string (default:"")
- socks5
- None at this moment, added for uniform api
Server
End user implementations mimic «parent» library server request handlers.
- asyncio:
start_server - trio:
serve_tcp - socketserver:
ThreadingTCPServer
You should use partial to bind socks specific arguments:
allowed_versions: set of integers (default:{4, 5})username: optional string (default:None)password: optional string (default:None)strict_security_policy: boolean, ifTrueexception will be raised if authentication required and 4 is in allowed versions set (default:True)encoding: optional string (default:"utf-8")
Nothing to say more. Typical usage can be found at __main__.py
Examples
High-level
This section will use asyncio as backend, since it is main target/reason for siosocks
Client
import asyncio
from siosocks.io.asyncio import open_connection
HOST = "api.ipify.org"
REQ = """GET /?format=json HTTP/1.1
Host: api.ipify.org
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en,en-US;q=0.7,ru;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
"""
async def main():
# assume we have tor started
r, w = await open_connection(HOST, 80, socks_host="localhost", socks_port=9050, socks_version=5)
w.write(REQ.replace("\n", "\r\n").encode())
await w.drain()
print(await r.read(8192))
w.close()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Server
import socket
import asyncio
import contextlib
from siosocks.io.asyncio import socks_server_handler
loop = asyncio.get_event_loop()
server = loop.run_until_complete(asyncio.start_server(socks_server_handler, port=1080))
addresses = []
for sock in server.sockets:
if sock.family in (socket.AF_INET, socket.AF_INET6):
host, port, *_ = sock.getsockname()
addresses.append(f"{host}:{port}")
print(f"Socks4/5 proxy serving on {', '.join(addresses)}")
with contextlib.suppress(KeyboardInterrupt):
loop.run_forever()
But if you just want one-shot socks server then try:
python -m siosocks
This will start socks 4, 5 server on all interfaces on 1080 port. For more information try --help
python -m siosocks --help
usage: siosocks [-h] [--backend {asyncio,socketserver,trio}] [--host HOST]
[--port PORT] [--family {ipv4,ipv6,auto}] [--socks SOCKS]
[--username USERNAME] [--password PASSWORD]
[--encoding ENCODING] [--no-strict] [-v]
Socks proxy server
optional arguments:
-h, --help show this help message and exit
--backend {asyncio,socketserver,trio}
Socks server backend [default: asyncio]
--host HOST Socks server host [default: None]
--port PORT Socks server port [default: 1080]
--family {ipv4,ipv6,auto}
Socket family [default: auto]
--socks SOCKS Socks protocol version [default: []]
--username USERNAME Socks auth username [default: None]
--password PASSWORD Socks auth password [default: None]
--encoding ENCODING String encoding [default: utf-8]
--no-strict Allow multiversion socks server, when socks5 used with
username/password auth [default: False]
-v, --version Show siosocks version
Exceptions
siosocks have unified exception for all types of socks-related errors:
import asyncio
from siosocks.exceptions import SocksException
from siosocks.io.asyncio import open_connection
async def main():
try:
r, w = await open_connection("127.0.0.1", 80, socks_host="localhost", socks_port=9050, socks_version=5)
except SocksException:
...
else:
# at this point all socks-related tasks done and returned reader and writer
# are just plain asyncio objects without any siosocks proxies
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Low-level
Shadowsocks-like client/server. Shadowsocks-like built on top of socks5 and encryption. It have «client», which is actually socks server and «server». So, precisely there are two servers: client side and server side. Purpose of shadowsocks is to encrypt data between «incoming» and «outgoing» servers. In common this looks like:
client (non-encrypted socks) «incoming» socks server (encrypted socks) «outgoing» socks server (non-socks connection) target server
Example above use Caesar cipher for simplicity (and security of course).
Roadmap/contibutions
- add more backends (average)
- speed up
passthroughimplementation (seems hard) - add client redirection
Metadata
Release files for siosocks 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| siosocks-0.3.0.tar.gz | 17.7 kB | Without provenance | Details for siosocks-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| siosocks-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for siosocks-0.3.0-py3-none-any.whl |
Total release size: 32.0 kB
Release files / siosocks-0.3.0.tar.gz
| Download URL | siosocks-0.3.0.tar.gz |
|---|---|
| Size | 17.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ba36bbf6f5a13d83a1853501221f97a52e069eb609cb4fd7a435d74239f21d63
|
|
BLAKE2b-256 checksum How to use checksums |
d86329311fe4bed90e6dfd902a87c6d0fb77244d5abfb9b876344693b40d5c53
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/4.0.1 CPython/3.10.6
|
Release files / siosocks-0.3.0-py3-none-any.whl
| Download URL | siosocks-0.3.0-py3-none-any.whl |
|---|---|
| Size | 14.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3f4bfca9a9b925d8cd13eb850eaf66263936a3c7a3a2fccd44cc9d8632d62709
|
|
BLAKE2b-256 checksum How to use checksums |
edcea97f3580cad9f2d159886b1c903402ae0cb45dfd232fd8fdaf9afa25775b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/4.0.1 CPython/3.10.6
|
Security for siosocks 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.