Skip to content

Support SOCKS5 proxies and proxy authentication - #1768

Open
VIIII4 wants to merge 4 commits into
librespot-org:devfrom
VIIII4:socks5-proxy-support
Open

VIIII4 wants to merge 4 commits into
librespot-org:devfrom
VIIII4:socks5-proxy-support

Conversation

@VIIII4

@VIIII4 VIIII4 commented Sep 23, 2026

Copy link
Copy Markdown

Description

This adds SOCKS5 proxy support (and proxy authentication, which was missing
entirely) to both network paths that use SessionConfig::proxy:

  • the access point connection (socket.rs): previously every proxy URL was
    treated as an HTTP CONNECT proxy regardless of its scheme, and no
    Proxy-Authorization header was ever sent, so authenticated proxies
    answered 407;
  • the spclient HTTP client (http_client.rs): previously built on
    hyper-proxy2, which supports neither SOCKS nor proxy authentication.

What is supported after this PR

Proxy URL Behaviour
http://host:port HTTP CONNECT as before, now with Proxy-Authorization: Basic if credentials are present
https://host:port unchanged
socks5://, socks5://user:pass@host:port SOCKS5, hostname sent to the proxy for remote DNS resolution (curl's socks5h semantics — resolving Spotify hostnames locally is usually exactly what SOCKS users want to avoid)
socks5h://, socks:// same as socks5://
socks4://, socks4a:// explicit error, not supported

Both the access point tunnel and the spclient HTTP client share the same
handling. SOCKS5 credentials use RFC 1929 username/password authentication.
The new proxy_connector.rs implements a Service<Uri> that replaces
hyper-proxy2 for the HTTP client, layering TLS (native-tls or rustls,
whichever feature is selected) on top of the tunnel for https destinations.
No new external crates are required: the SOCKS5 handshake (RFC 1928/1929) is
implemented in proxytunnel.rs in the same style as the existing CONNECT
tunnelling, and the TLS crates were already in the dependency tree indirectly.

The vendored-in-spirit summary of the four commits:

  1. core: SOCKS5 + authenticated HTTP CONNECT for the access point connection
  2. core: unified proxy connector for the HTTP client (replaces hyper-proxy2 usage)
  3. oauth: enable reqwest's socks feature so the token exchange honours SOCKS proxy environment variables
  4. core: examples/proxy_check.rs to exercise all three paths against a real proxy

Testing

Tested end to end against a local SOCKS5 server (with and without RFC 1929
credentials, upstream-chained through an HTTP proxy) and against a plain
HTTP CONNECT proxy:

$ PROXY=socks5h://user:pass@127.0.0.1:1080 cargo run -p librespot-core --example proxy_check
[socket] tunnel to ap-gew4.spotify.com:443 established: TcpStream { .. }
[http/1 ] apresolve: {"accesspoint":["ap-gae2.spotify.com:443", ..]}
[https  ] spclient responded (expected auth error): .. 404 Not Found
ALL PROXY CHECKS PASSED

The proxy-side log confirms the client sends domain names (ATYP = 0x03) and
never pre-resolved addresses. cargo clippy and cargo fmt --check are
clean for both TLS backends (native-tls and rustls-tls-webpki-roots).

Downstream motivation: ncspot currently cannot route all of its traffic
through a SOCKS proxy (hrkfdn/ncspot#898) and fails to log in behind
authenticated proxies (hrkfdn/ncspot#531); a matching ncspot-side change
exposes this as a single configuration option.

@VIIII4
VIIII4 force-pushed the socks5-proxy-support branch from f7b862e to cebe05f Compare September 23, 2026 02:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant