feat: named proxy pools with per-listener assignment
Add proxy_pools: top-level config (dict of name -> pool config) so
listeners can draw from different proxy sources. Each pool has
independent sources, health testing, state persistence, and refresh
cycles.
- PoolSourceConfig gains mitm: bool|None for API ?mitm=0/1 filtering
- ListenerConfig gains pool_name for named pool assignment
- ProxyPool gains name param with prefixed log messages and
per-name state file derivation (pool-{name}.json)
- server.py replaces single proxy_pool with proxy_pools dict,
validates listener pool references at startup, per-listener closure
- API /pool merges all pools (with pool field on multi-pool entries),
/status and /config expose per-pool summaries
- Backward compat: singular proxy_pool: registers as "default"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
117
docs/USAGE.md
117
docs/USAGE.md
@@ -47,39 +47,35 @@ pool_size: 0 # pre-warmed TCP connections to first hop (0 = disable
|
||||
pool_max_idle: 30 # max idle time for pooled connections (seconds)
|
||||
api_listen: "" # control API bind address (empty = disabled)
|
||||
|
||||
# Multi-listener (each port gets its own chain depth)
|
||||
# Named proxy pools (each with its own sources and filters)
|
||||
proxy_pools:
|
||||
clean:
|
||||
sources:
|
||||
- url: http://10.200.1.250:8081/proxies/all
|
||||
mitm: false
|
||||
refresh: 300
|
||||
test_interval: 120
|
||||
test_timeout: 8
|
||||
max_fails: 3
|
||||
|
||||
# Multi-listener (each port gets its own chain depth and pool)
|
||||
listeners:
|
||||
- listen: 0.0.0.0:1080
|
||||
pool: clean
|
||||
chain:
|
||||
- socks5://127.0.0.1:9050
|
||||
- pool # Tor + 2 pool proxies
|
||||
- pool # Tor + 2 clean proxies
|
||||
- pool
|
||||
- listen: 0.0.0.0:1081
|
||||
pool: clean
|
||||
chain:
|
||||
- socks5://127.0.0.1:9050
|
||||
- pool # Tor + 1 pool proxy
|
||||
- pool # Tor + 1 clean proxy
|
||||
|
||||
# Or single-listener (old format):
|
||||
# listen: 127.0.0.1:1080
|
||||
# chain:
|
||||
# - socks5://127.0.0.1:9050
|
||||
|
||||
proxy_pool:
|
||||
sources:
|
||||
- url: http://10.200.1.250:8081/proxies
|
||||
proto: socks5
|
||||
limit: 1000
|
||||
- file: /etc/s5p/proxies.txt
|
||||
refresh: 300
|
||||
test_interval: 120
|
||||
test_targets: # TLS handshake targets (round-robin)
|
||||
- www.google.com
|
||||
- www.cloudflare.com
|
||||
- www.amazon.com
|
||||
test_timeout: 15
|
||||
test_concurrency: 25 # max parallel tests (auto-scales to ~10% of pool)
|
||||
max_fails: 3
|
||||
state_file: "" # empty = ~/.cache/s5p/pool.json
|
||||
```
|
||||
|
||||
## Multi-Tor Round-Robin
|
||||
@@ -112,42 +108,85 @@ curl -s http://127.0.0.1:1090/config | jq '.tor_nodes'
|
||||
curl -s http://127.0.0.1:1090/status | jq '.tor_nodes'
|
||||
```
|
||||
|
||||
## Named Proxy Pools
|
||||
|
||||
Define multiple proxy pools with different source filters. Each listener can
|
||||
reference a specific pool by name via the `pool:` key.
|
||||
|
||||
```yaml
|
||||
proxy_pools:
|
||||
clean:
|
||||
sources:
|
||||
- url: http://10.200.1.250:8081/proxies/all
|
||||
mitm: false
|
||||
state_file: /data/pool-clean.json
|
||||
refresh: 300
|
||||
test_interval: 120
|
||||
test_timeout: 8
|
||||
max_fails: 3
|
||||
mitm:
|
||||
sources:
|
||||
- url: http://10.200.1.250:8081/proxies/all
|
||||
mitm: true
|
||||
state_file: /data/pool-mitm.json
|
||||
refresh: 300
|
||||
test_interval: 120
|
||||
test_timeout: 8
|
||||
max_fails: 3
|
||||
```
|
||||
|
||||
Each pool has independent health testing, state persistence, and source
|
||||
refresh cycles. The `mitm` source filter adds `?mitm=0` or `?mitm=1` to
|
||||
API requests.
|
||||
|
||||
### Backward compatibility
|
||||
|
||||
The singular `proxy_pool:` key still works -- it registers as pool `"default"`.
|
||||
If both `proxy_pool:` and `proxy_pools:` are present, `proxy_pools:` wins;
|
||||
the singular is registered as `"default"` only when not already defined.
|
||||
|
||||
## Multi-Listener Mode
|
||||
|
||||
Run multiple listeners on different ports, each with a different number
|
||||
of proxy hops after the static chain. Config-file only (not available via CLI).
|
||||
of proxy hops and pool assignment. Config-file only (not available via CLI).
|
||||
|
||||
```yaml
|
||||
listeners:
|
||||
- listen: 0.0.0.0:1080
|
||||
pool: clean
|
||||
chain:
|
||||
- socks5://10.200.1.13:9050
|
||||
- pool # Tor + 2 pool proxies
|
||||
- pool # Tor + 2 clean proxies
|
||||
- pool
|
||||
|
||||
- listen: 0.0.0.0:1081
|
||||
pool: clean
|
||||
chain:
|
||||
- socks5://10.200.1.13:9050
|
||||
- pool # Tor + 1 pool proxy
|
||||
- pool # Tor + 1 clean proxy
|
||||
|
||||
- listen: 0.0.0.0:1082
|
||||
chain:
|
||||
- socks5://10.200.1.13:9050 # Tor only
|
||||
- socks5://10.200.1.13:9050 # Tor only (no pool)
|
||||
|
||||
proxy_pool:
|
||||
sources:
|
||||
- url: http://10.200.1.250:8081/proxies/all?mitm=0
|
||||
refresh: 300
|
||||
test_interval: 120
|
||||
max_fails: 3
|
||||
- listen: 0.0.0.0:1083
|
||||
pool: mitm
|
||||
chain:
|
||||
- socks5://10.200.1.13:9050
|
||||
- pool # Tor + 2 MITM proxies
|
||||
- pool
|
||||
```
|
||||
|
||||
The `pool` keyword in a chain means "append a random alive proxy from the
|
||||
shared pool". Multiple `pool` entries = multiple pool hops (deeper chaining).
|
||||
assigned pool". Multiple `pool` entries = multiple pool hops (deeper chaining).
|
||||
|
||||
When `pool:` is omitted on a listener with pool hops, it defaults to
|
||||
`"default"`. A listener referencing an unknown pool name causes a fatal
|
||||
error at startup. Listeners without pool hops ignore the `pool:` key.
|
||||
|
||||
| Resource | Scope | Notes |
|
||||
|----------|-------|-------|
|
||||
| ProxyPool | shared | All listeners draw from one pool |
|
||||
| ProxyPool | per name | Each named pool is independent |
|
||||
| TorController | shared | One Tor instance |
|
||||
| Metrics | shared | Aggregate stats across listeners |
|
||||
| Semaphore | shared | Global `max_connections` cap |
|
||||
@@ -202,6 +241,7 @@ proxy_pool:
|
||||
proto: socks5 # optional: filter by protocol
|
||||
country: US # optional: filter by country
|
||||
limit: 1000 # max proxies to fetch from API
|
||||
mitm: false # optional: filter by MITM status (true/false)
|
||||
- file: /etc/s5p/proxies.txt # text file, one proxy URL per line
|
||||
refresh: 300 # re-fetch sources every 300 seconds
|
||||
test_interval: 120 # health test cycle every 120 seconds
|
||||
@@ -212,7 +252,7 @@ proxy_pool:
|
||||
test_timeout: 15 # per-test timeout (seconds)
|
||||
test_concurrency: 25 # max parallel tests (auto-scales to ~10% of pool)
|
||||
max_fails: 3 # evict after N consecutive failures
|
||||
state_file: "" # empty = ~/.cache/s5p/pool.json
|
||||
state_file: "" # empty = ~/.cache/s5p/pool[-name].json
|
||||
report_url: "" # POST dead proxies here (optional)
|
||||
```
|
||||
|
||||
@@ -223,6 +263,17 @@ proxy_pool:
|
||||
| HTTP API | `url` | JSON: `{"proxies": [{"proto": "socks5", "proxy": "host:port"}, ...]}` |
|
||||
| Text file | `file` | One proxy URL per line, `#` comments, blank lines ignored |
|
||||
|
||||
### Source filters
|
||||
|
||||
| Filter | Values | Effect |
|
||||
|--------|--------|--------|
|
||||
| `proto` | `socks5`, `socks4`, `http` | Adds `?proto=...` to API URL |
|
||||
| `country` | ISO 3166-1 alpha-2 | Adds `?country=...` to API URL |
|
||||
| `limit` | integer | Adds `?limit=...` to API URL |
|
||||
| `mitm` | `true` / `false` | Adds `?mitm=1` / `?mitm=0` to API URL |
|
||||
|
||||
The `mitm` filter is silently ignored for file sources.
|
||||
|
||||
### Proxy file format
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user