Add --allow-socks server flag and --proxy socks5 client support (v0.6.0) - #37
Merged
Merged
Conversation
Two new flags closing out items from the README roadmap: - `--allow-socks` on the server gates reverse-SOCKS5 (`R:socks`) at the control-plane handshake, default-deny. Mirrors the existing `--allow-reverse` semantics so a client can no longer make the server spin up a SOCKS listener exposing the server's network unless the operator explicitly opts in. Forward `socks` decomposes into per-target dynamic TCP/UDP on the wire and is intentionally not gated by this flag — see the new "Security & access control" roadmap section for the full ACL story. - `--proxy socks5://[user:pass@]host:port` on the client routes the QUIC connection through a SOCKS5 proxy via UDP ASSOCIATE (RFC 1928 §4). New `rusnel::common::proxy` module ships a `ProxyConfig` parser, the SOCKS5 control-plane handshake (no-auth + RFC 1929 user/pass), and a `Socks5UdpSocket` adapter implementing `quinn::AsyncUdpSocket` that wraps every outbound QUIC datagram in the SOCKS5 UDP framing and unwraps every inbound one. The TCP control connection is held open inside the socket for the lifetime of the relay (RFC 1928 §6); each reconnect opens a fresh association. The client bypasses Happy Eyeballs and the cross-attempt endpoint pool when proxied (the proxy owns routing). HTTP CONNECT is intentionally not supported here because it cannot carry UDP — that requires the WebSocket fallback transport tracked separately. Tests: 12 new unit tests (URL parser, SOCKS5 UDP wrap/unwrap, fragment and ATYP rejection paths) plus tests/proxy.rs — an integration test that stands up an in-process SOCKS5 UDP relay and asserts a real Rusnel client/server pair completes the QUIC handshake through it and round-trips bytes over a tunneled TCP echo. Co-authored-by: Cursor <cursoragent@cursor.com>
5 tasks
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.
Summary
Two new flags from the README roadmap, both gated behind explicit opt-in for safety:
--allow-socks(server) — default-deny gate for reverse-SOCKS5 (R:socks/R:port:socks). Without it the server now refuses reverse-SOCKS at the control-plane handshake instead of silently exposing its network. Mirrors--allow-reversesemantics. Forwardsocksdecomposes into per-target dynamic TCP/UDP on the wire and is intentionally not gated by this flag — see the new "Security & access control" roadmap section in the README for the full ACL story.--proxy socks5://[user:pass@]host:port(client) — routes the QUIC connection through a SOCKS5 proxy via UDP ASSOCIATE (RFC 1928 §4). Newrusnel::common::proxymodule with:ProxyConfigURL parser (socks5://,socks://alias, barehost:port, optionaluser:pass@per RFC 1929).Socks5UdpSocketadapter implementingquinn::AsyncUdpSocket, wrapping every outbound QUIC datagram inRSV/FRAG/ATYP/DST.ADDR/DST.PORTframing and unwrapping every inbound one. The TCP control connection is held open inside the socket for the lifetime of the relay (RFC 1928 §6).HTTP CONNECT is intentionally not supported in this release — it cannot carry UDP/QUIC. The path that would unlock HTTP/SOCKS-CONNECT proxies is the WebSocket-fallback transport tracked separately in the README roadmap.
Test plan
src/common/proxy.rs(URL parser corner cases, SOCKS5 UDP wrap/unwrap roundtrips, fragment/ATYP rejection paths).tests/proxy.rsintegration test stands up an in-process SOCKS5 UDP relay and asserts a real Rusnel client + server pair completes the QUIC handshake through it and round-trips bytes over a tunneled TCP echo.cargo test --all).cargo fmt --all -- --checkclean.cargo clippy --all -- -D warningsclean.0.6.0; CHANGELOG updated.--proxyREADME TODO bullet checked.Notes for downstream embedders
ServerConfiggainspub allow_socks: bool(default-deny — set totrueif you previously relied on reverse-SOCKS without the flag).ClientConfiggainspub proxy: Option<ProxyConfig>(None= direct connect, existing behaviour).server_receive_remote_requestgains anallow_socks: boolparameter alongsideallow_reverse. Wire format unchanged.Made with Cursor