From e01afcbf0de00af52fe90959ba77288679e3303d Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:40:00 +0200 Subject: SOCKS5 upstream proxy chaining Extends -upstream-proxy to accept a socks5://[user:pass@]host:port prefix, using golang.org/x/net/proxy (already an indirect dependency via http2, so no new module) rather than hand-rolling the client side of RFC 1928/1929. parseSOCKS5 is the single place that decides which kind of upstream a given UpstreamProxy string names; dialViaProxy (CONNECT/TLS path) and dialUpstreamPlain (plain-HTTP path) both check it first and fall through to the existing HTTP CONNECT behavior otherwise. SOCKS5 needs no absolute-form request adjustment on the plain-HTTP path the way HTTP-proxy chaining does, since it tunnels straight to the target rather than expecting a proxy-aware request. Tested against a real, minimal SOCKS5 server built for the test suite (exercises dialSOCKS5's actual wire behavior, not a mock of the client library), plus live against a real standalone SOCKS5 relay process: both a plain HTTP and an HTTPS request through mitmux were confirmed, via the relay's own log, to have actually traversed it. --- PLAN.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'PLAN.md') diff --git a/PLAN.md b/PLAN.md index 16a8599..073c52e 100644 --- a/PLAN.md +++ b/PLAN.md @@ -190,7 +190,17 @@ Upstream proxy chaining: `-upstream-proxy host:port` (optional `http://` prefix, stripped) routes every outbound connection through another HTTP CONNECT proxy instead of dialing origins directly - chaining mitmux into Burp, a corporate proxy, or any other -CONNECT-speaking proxy. SOCKS5 upstreams aren't implemented. For the +CONNECT-speaking proxy. A `socks5://[user:pass@]host:port` prefix +routes through a SOCKS5 proxy instead (Tor, `ssh -D`, any other SOCKS5 +relay), via golang.org/x/net/proxy - already an indirect dependency +through http2, so no new module. parseSOCKS5 is the single place that +decides which kind of upstream a given UpstreamProxy string names; +dialViaProxy (CONNECT/TLS path) and dialUpstreamPlain (plain-HTTP +path) both check it first and fall through to the existing HTTP-proxy +behavior otherwise. SOCKS5 is transport-level and protocol-agnostic - +the tunnel it hands back behaves exactly like a direct connection to +the target, so unlike HTTP-proxy chaining it needs no absolute-form +request adjustment on the plain-HTTP path either. For the CONNECT/HTTPS path, chaining is transparent below the tunnel: once the CONNECT handshake to the upstream proxy succeeds, TLS and the request/response on top of it are identical to a direct connection, so @@ -210,7 +220,11 @@ genuine passthrough CONNECT proxy (tunnels raw bytes, no MITM) works correctly for both plain HTTP and HTTPS; chaining through a second mitmuxd instance correctly fails with a clear "certificate signed by unknown authority" error recorded in history, -rather than hanging or crashing. +rather than hanging or crashing. SOCKS5 chaining verified the same +way, live, against a real standalone SOCKS5 relay process (not an +in-test mock): both a plain HTTP request and an HTTPS request through +mitmux were confirmed - via the relay's own log, not just mitmux's +success response - to have actually traversed it end to end. This closes every item from the original "worth considering" list. -- cgit v1.2.3