What's New
Correctness pass on the rotating proxy: rotation, chain mode, and health checks.
🎛️ New Proxy Flags
--health-fail-threshold <n>— consecutive health-check failures before the active config takes a strike (default3).--chain-attempts <n>— random chain combinations to try per rotation cycle (default5).
🩺 Better Health Checks
- Health probe now runs through the live local listener (SOCKS5 / HTTP), so it tests both the inbound and the outbound — not just the outbound.
- A single failure no longer counts; it takes
--health-fail-thresholdfailures in a row. - Single-config mode (
--config <link>) also runs health checks now and rebuilds the instance on repeated failure.
🐛 Bug Fixes
--drain > 0broke rotation: the new and old instances tried to bind the same port at the same time, so Start failed. Old listener is now closed before the new one binds;--drainbecomes the wait before the switch.- Chain rotation had the same port conflict — fixed the same way.
- Timer deadlock on Go 1.23+: the legacy
if !timer.Stop() { <-timer.C }drain blocked forever becauseStopalready empties the channel. Removed in all six rotation loops. - Chain mode ignored in app mode:
--chainwas silently dropped, fell through to rotation. App mode now picks the right runner. - Short chains:
selectChainFromPoolreturned fewer hops than requested when some pool entries failed to parse. Now walks the whole pool until it has enough valid hops. - Configs that failed instance Start were left untracked and kept getting picked again. Now striked like any other failure.
--rotate 0tight loop: zero or very small rotation values are clamped to a minimum.- Bad listen port was silently ignored, leaving the namespace tunnel on port 0. Now validated up front.
- Stdin EOF spam: closing stdin (
< /dev/null, daemonized) turned EOF into an endless force-rotate stream. Watcher exits cleanly on EOF. - System mode + non-HTTP/SOCKS inbound is rejected up front instead of pointing the OS proxy at something browsers can't speak.
--bindnot honored at test time: examiner now inherits--bindso test results match runtime.- Current outbound wasted a test slot per rotation. It's now removed from the candidate set before the batch is picked.
⚡ Improvements
- Rotation state collapsed to a single
rotatingvalue so the web UI no longer flickers betweentestingandswitchingmid-cycle. - Auto-generated SOCKS username/password bumped from 4 to 16 chars (app mode binds on
0.0.0.0). - Pool shuffles use a per-call rand source instead of the global one, reducing contention from the web service.
Migration note: --drain is no longer asynchronous. With a non-zero value, rotation now waits that many seconds on the current outbound, closes it, then brings the next one up. There is a brief gap on the inbound port during the handover. Set --drain 0 (the default) for an immediate switch.