Repository navigation
feat: bring your own proxy (http, https, socks5), no account needed - #21
Merged
Merged
Conversation
cvl
commented
Oct 21, 2026
Contributor
- docs: keep the provider compatibility table to provider, scheme, endpoint, result and behaviour
- fix(upstream): keep SHELLROUTE_PROXY out of the child environment; plain-language probe failures
- docs: own-proxy examples use the your-proxy-name placeholder and say it is the user's alias; README covers every use case
- docs: Evomi https and socks5 rows and the SOCKS5 general-failure hint (completes the previous commit's docs)
- feat(upstream): password hint on SOCKS5 'general failure' after a credentials exchange; Evomi https and socks5 results
- docs: add the Webshare free-plan result to the provider compatibility table
- docs: start the own-proxy provider compatibility table with the Evomi datacenter result
- feat(upstream): show the observed exit country instead of a typed label
- test: run the Docker proxy layer from scripts/run-tests.sh; parse the colored summary
- feat: bring-your-own-proxy docs, status for own sessions, Docker upstream test layer
- feat(tui): /connect routes the interactive shell through an own upstream
- feat(cli): bring your own proxy with upstream add/list/remove/test, run , --proxy, proxy --upstream
- feat(proxy): upstream abstraction with hosted, HTTP(S) and SOCKS5 implementations
…lementations The local proxy now talks to an Upstream interface instead of the gateway fields. Three implementations: the hosted gateway (unchanged semantics for X-Exit-IP, 402, 407, X-Route-Dead), a user's own HTTP or HTTPS proxy with optional basic auth, and a hand-written SOCKS5 client with username/password auth and remote name resolution. Plain HTTP over SOCKS5 is rewritten to origin form. A user's own proxy never reports route death, so a credentials error marks the route dead at once and three consecutive connection failures mark it dead; a success resets the count. The hosted gateway keeps its explicit signalling and no counter. ParseUpstreamURL builds an upstream from http, https, socks5 or socks5h URLs with a required port; RedactURL and Describe never show the password. Probe and Check open one tunnel (one retry, 10 s each) and read the exit IP through the upstream, classifying failures as resolve, refused, timeout, credentials or proxy status. session.StartOwn starts the local proxy over an own upstream with no API call and no billing; Stop returns duration and bytes only. proxytest holds in-process HTTP, HTTPS and SOCKS5 fakes for tests. Signed-off-by: contra <vytautas@civilis.lt>
…un <name>, --proxy, proxy --upstream Saved upstreams live in config.toml as [[upstream]] tables (name, url, country label, note); names are 3 to 32 characters of [a-z0-9_-] so they never collide with a country code. The URL password is stored in the 0600 file and never printed: list, status and the session file show user:***. shellroute run resolves its target in this order: --proxy <url>, --country, a two-letter country before --, a saved upstream name before --, then SHELLROUTE_PROXY from the environment, then default_country. Own routes need no account: no login check, no API call, no version check, and they work with the API unreachable. The start of an own route checks the tunnel once with one retry (10 s each) and prints 'via work · exit IP … · N ms'; a failure names the cause (resolve, refused, timeout, credentials, proxy status). --no-check skips the probe. The end-of-run summary shows duration and bytes only. shellroute proxy --upstream <name|url> runs the persistent local proxy over an own upstream; proxy stop and the singleton guard show the upstream name. The interactive shell starts without login when saved upstreams exist. Signed-off-by: contra <vytautas@civilis.lt>
…n upstream The control port accepts /connect?upstream=<name>, starts the session with session.StartOwn and exports SHELLROUTE_UPSTREAM next to the usual variables; switching back to a hosted route clears it. Route checks for an own session use the local route state only, so a dead or unreachable Shellroute API never blocks the shell. Rotation is the provider's job: /rotate says so and the reconnect-on-death path reports the loss instead of rotating. /balance, /countries, /cities, /iptype and /sticky answer 'not applicable' while an own route is active. The prompt shows 'work (DE) · ip'; status shows the upstream and its redacted URL; disconnect prints duration and bytes only. The shell starts without a login when upstreams are saved. Signed-off-by: contra <vytautas@civilis.lt>
…ream test layer README gets a 'Use your own proxy' section; docs/bring-your-own-proxy.md covers URL formats, how run picks the route, what stays the same, what is different, failure behavior and troubleshooting by error message; docs/compatibility.md says the matrix applies to both route kinds; the changelog lists 0.2.0 as unreleased. shellroute status lists live own-proxy sessions from the session files and no longer needs a login when only those exist. A SOCKS5 'not allowed by ruleset' after a credentials exchange gets the hint '(check the username and password)': 3proxy answers a wrong password that way. scripts/test-upstreams.sh runs the layer-2 checks C-01 to C-10 and C-14 against 3proxy (HTTP with auth, SOCKS5 with and without auth), gost (SOCKS5 with auth; HTTPS with auth on Linux), squid (open and basic auth) and an ssh -D tunnel, all in Docker on one network with a marker container only the proxies can resolve. CI gets an 'upstreams' job for it. Signed-off-by: contra <vytautas@civilis.lt>
… colored summary run-tests.sh gets an 'Own proxies in Docker' stage that runs scripts/test-upstreams.sh when a Docker daemon is up and reports SKIP otherwise. The byte check (C-07) now strips terminal color codes before reading the 'Data used' line; on a terminal the reset code after the label contains a digit and broke the pattern, so the check failed although the download and its checksum were fine. Failure lines use the 'FAIL:' shape the gate's summary looks for. Signed-off-by: contra <vytautas@civilis.lt>
upstream add loses --country. A typed country was shown as 'work (DE)' as if Shellroute knew where the proxy exits; it does not. The start-up probe now asks the exit IP service for JSON (ipinfo.io/json, then ipify) and records the country it reports for the observed exit IP. upstream test, run, status, the shell prompt and the session file show it as 'DE (observed)', or nothing when the service does not report one. The session file is rewritten after the probe so status and stop see the observed values. Signed-off-by: contra <vytautas@civilis.lt>
… datacenter result Signed-off-by: contra <vytautas@civilis.lt>
… table Signed-off-by: contra <vytautas@civilis.lt>
…dentials exchange; Evomi https and socks5 results Evomi's SOCKS5 gateway answers a wrong password with reply 1 (general failure) at the CONNECT step after accepting the RFC 1929 exchange, as 3proxy does with reply 2. Both now carry the '(check the username and password)' hint when credentials were sent; without credentials the text is unchanged. The compatibility table gains the Evomi https (public certificate, no extra setup) and socks5 rows. Signed-off-by: contra <vytautas@civilis.lt>
… (completes the previous commit's docs) Signed-off-by: contra <vytautas@civilis.lt>
…it is the user's alias; README covers every use case Signed-off-by: contra <vytautas@civilis.lt>
…ain-language probe failures The command run through an own proxy inherited SHELLROUTE_PROXY, so a password passed that way reached the child process, contrary to the documented promise. buildProxyEnv now drops the variable. A probe that opened the tunnel but got no usable answer from the exit IP service showed the raw Go error (URL, "context deadline exceeded"). Probe now returns a ProbeError whose text is one of three plain sentences, and Cause knows it; the run, test and interactive paths all use that text. A local start failure (port, session file) no longer prints the raw error. StartOwn moves to session/own.go to keep session.go under 500 lines. Signed-off-by: contra <vytautas@civilis.lt>
…oint, result and behaviour Signed-off-by: contra <vytautas@civilis.lt>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.