163 lines
5.8 KiB
Markdown
163 lines
5.8 KiB
Markdown
# 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.
|