# s5p SOCKS5 proxy server with Tor and proxy-chain support. Routes connections through configurable chains of SOCKS4, SOCKS5, and HTTP CONNECT proxies. ## Features - SOCKS5 server (RFC 1928) - Proxy chaining: tunnel through multiple hops in sequence - Supported hop protocols: SOCKS5, SOCKS4/4a, HTTP CONNECT - Per-hop authentication (username/password) - DNS leak prevention (domain names forwarded to proxies, never resolved locally) - Tor integration (SOCKS5 hop + control port NEWNYM for circuit rotation) - Multi-Tor round-robin (`tor_nodes` distributes traffic across Tor instances) - Multi-listener: different ports with different chain depths and pool assignments - Named proxy pools: independent sources, health testing, and state per pool - MITM source filter (`mitm: true/false` adds `?mitm=0/1` to API requests) - Per-proxy failure backoff (60s cooldown), stale proxy expiry, chain pre-flight - Fast warm start (seconds on restart vs minutes on cold start) - Connection retry with proxy rotation (configurable attempts) - Dead proxy reporting to upstream API (optional `report_url`) - SIGHUP hot reload (timeout, retries, log_level, pool config) - Connection metrics with per-listener latency and pool stats - Concurrent connection limit with backpressure (`max_connections`) - Async HTTP client for proxy source fetching (parallel, no threads) - First-hop TCP connection pool (pre-warmed, stale-evicted) - Built-in control API (runtime metrics, pool state, config reload via HTTP) - Container-ready (Alpine-based, podman/docker) - Graceful shutdown (SIGTERM/SIGINT) - Pure Python, asyncio-based, minimal dependencies ## Quick Start ```bash # Install locally cd ~/git/s5p python -m venv .venv && source .venv/bin/activate pip install -e . # Run with Tor s5p -C socks5://127.0.0.1:9050 # Run with config file cp config/example.yaml config/s5p.yaml # edit with your proxies s5p -c config/s5p.yaml # Test it curl --proxy socks5h://127.0.0.1:1080 https://check.torproject.org/api/ip ``` ## Container ```bash make build # podman-compose build make up # podman-compose up -d make logs # podman-compose logs -f make down # podman-compose down ``` Production images bake source into the image. Config and data are mounted at runtime. Pool state and profile output persist in `~/.cache/s5p/` (`/data` inside container). The compose.yaml volume mount overrides source for local dev. CI (Gitea Actions) runs lint + tests on push to `main`, then builds and pushes `harbor.mymx.me/s5p/s5p:latest`. ## Configuration Copy the example and edit with your proxy chain: ```bash cp config/example.yaml config/s5p.yaml ``` ```yaml timeout: 10 retries: 3 max_connections: 256 # concurrent connection limit pool_size: 8 # pre-warmed connections to first hop api_listen: 127.0.0.1:1081 # control API (disabled by default) # Named proxy pools (each with independent sources and health testing) proxy_pools: clean: sources: - url: http://10.200.1.250:8081/proxies/all mitm: false # filter: ?mitm=0 refresh: 300 test_interval: 120 max_fails: 3 mitm: sources: - url: http://10.200.1.250:8081/proxies/all mitm: true # filter: ?mitm=1 refresh: 300 test_interval: 120 max_fails: 3 # Multi-listener: each port gets a chain depth and pool assignment # Use "pool" for listener default, "pool:name" for explicit pool per hop, # or [pool:a, pool:b] for random choice from candidates per connection listeners: - listen: 0.0.0.0:1080 pool: clean chain: - socks5://127.0.0.1:9050 - pool # Tor + 2 clean proxies - pool - listen: 0.0.0.0:1081 chain: - socks5://127.0.0.1:9050 - [pool:clean, pool:mitm] # random choice per connection - [pool:clean, pool:mitm] # independent random choice - listen: 0.0.0.0:1082 chain: - socks5://127.0.0.1:9050 # Tor only # Singular proxy_pool: still works (becomes pool "default") tor: control_port: 9051 # Tor control port (NEWNYM) password: "" # or cookie_file for auth newnym_interval: 0 # periodic circuit rotation (0 = manual) ``` `config/s5p.yaml` is gitignored; `config/example.yaml` is the tracked template. ## CLI Reference ``` s5p [-c FILE] [-l [HOST:]PORT] [-C URL[,URL,...]] [-S URL] [-t SEC] [-r N] [-m N] [--api [HOST:]PORT] [-v|-q] Options: -c, --config FILE YAML config file -l, --listen [HOST:]PORT Listen address (default: 127.0.0.1:1080) -C, --chain URL[,URL] Comma-separated proxy chain -S, --proxy-source URL Proxy source API URL -t, --timeout SEC Per-hop timeout (default: 10) -r, --retries N Max attempts per connection (default: 3, proxy_source only) -m, --max-connections N Max concurrent connections (default: 256) --api [HOST:]PORT Enable control API (e.g. 127.0.0.1:1081) -v, --verbose Debug logging -q, --quiet Errors only --cprofile [FILE] Enable cProfile, dump to FILE (default: s5p.prof) --tracemalloc [N] Enable tracemalloc, show top N allocators on exit (default: 10) -V, --version Show version ``` ## How Chaining Works ``` :1080 Client -> s5p -> Tor -> [clean] -> [clean] -> Dest (2 clean hops) :1081 Client -> s5p -> Tor -> [clean|mitm] -> [clean|mitm] -> Dest (random) :1082 Client -> s5p -> Tor -> Dest (Tor only) ``` s5p connects to Hop1 via TCP, negotiates the hop protocol (SOCKS5/4/HTTP), then over that tunnel negotiates with Hop2, and so on. Each listener draws from its assigned named pool -- alive proxies are appended per-connection (one per `pool` entry), weighted toward those with the most recent successful health test. Each hop only sees its immediate neighbors.