ADR-013 supersedes ADR-011's maintenance posture (not its mechanics):
the extracted T-generic subset is fully owned code, the vendor
framing is retired. Module renamed src/vendor/ -> src/rfc1928/
(naming decided in the ADR: 'vendor' names an ownership relation
now gone; 'socks5' would stutter and collide with the future
producer/consumer layers). Fork point = the tree as of the
extraction-review commit (5b18d4d); provenance stays permanent
(module docs + the extended LICENSE notice).
- ADR-013: fork posture, license mechanics (notice extended, not
replaced; post-fork modifications under the crate license),
hand-port replaces re-vendor, lint-allow posture dissolved
- ADR-011 marked Superseded (extraction mechanics remain
authoritative); ADR-002 references re-pointed
- vendor.md -> rfc1928.md rewritten as the owned-core spec (the cut
table re-read as the hand-port map)
- spec sweep: README index (ADR-013 row, doc table, principle 8),
overview (module map, deps, ADR table), producer/consumer/wire/
bast reference vocabulary, open-questions OQ-SK-04 resolution,
AGENTS.md conventions 4/17 + verification note + context bullet,
Cargo.toml description
Verification: cargo doc --no-deps clean; no stale vendor.md/src-vendor
references outside the ADR-011 historical text.
65 lines
3.0 KiB
Markdown
65 lines
3.0 KiB
Markdown
# ADR-002: Protocol Base — the Vendored fast-socks5 Typestate Subset
|
|
|
|
## Status
|
|
|
|
Accepted (2026-09-20, Phase 1; the extracted-and-forked posture is
|
|
OQ-SK-04's resolution — the extraction mechanics in
|
|
[ADR-011](011-inline-vendor.md), the ownership posture in
|
|
[ADR-013](013-targeted-fork.md))
|
|
|
|
## Context
|
|
|
|
Phase 0 evaluated the protocol-base candidates: fast-socks5 (the
|
|
full-fidelity RFC 1928 implementation, explicit typestate server API,
|
|
generic over `T`), iroh-socks5 (structurally the closest sibling, but
|
|
iroh-coupled and an RFC subset), and a hand-rolled codec (rejected as
|
|
anti-prior-art — alknet's client hand-rolls and it is the known
|
|
weakness). POC #1 confirmed the load-bearing property: fast-socks5's
|
|
`Socks5ServerProtocol<T, states::*>` accepts a channels `BiStream`
|
|
directly (`T: AsyncRead + AsyncWrite + Unpin`), and POC #4 measured
|
|
the wasm gating at ~120 cfg lines with the wasm-clean subset
|
|
functionally complete (a full RFC 1928 CONNECT conversation passes
|
|
`--no-default-features`).
|
|
|
|
## Decision
|
|
|
|
- **The protocol layer is built on fast-socks5's explicit typestate
|
|
API** — `Socks5ServerProtocol<T, …>` (negotiate/finish_auth/
|
|
read_command/reply_success/reply_error), the client side
|
|
`Socks5Stream<S>::use_stream` / the associate session, and the
|
|
pure codecs (`new_udp_header`/`parse_udp_request`).
|
|
- **Only the explicit API is used.** The legacy
|
|
`Socks5Server`/`Socks5Socket`/`Incoming` bind-based API is
|
|
deprecated upstream and is out — never forked into the default
|
|
path.
|
|
- **Base = v1.0.0, extracted in-tree and forked** (ADR-011 for the
|
|
extraction mechanics and the two carried changes; ADR-013 for the
|
|
targeted-fork ownership posture).
|
|
`/workspace/fast-socks5` remains the read-only reference for
|
|
differential testing of RFC edge cases; the fork point is noted
|
|
in the module docs and the bundled license notice.
|
|
- **Refusals map faithfully per RFC 1928** — `ReplyError` codes
|
|
(`as_u8`/`from_u8`) are the error vocabulary at the command plane;
|
|
refusals are never collapsed into generic errors (AGENTS.md
|
|
convention 2). POC #1 validated the mapping (dial refusal → 0x05).
|
|
|
|
## Consequences
|
|
|
|
- The crate owns its protocol code in-tree (the fork), so BIND and
|
|
the `new_reply` publication ride the same tree — no upstream waits.
|
|
- The typestate's interception points are the layering seams:
|
|
command-read (the dial/accept dispatch), `transfer` (the raw
|
|
two-pump), and — where the default handlers are unusable (UDP
|
|
ASSOCIATE's unconditional bind) — direct typestate driving. The
|
|
interception-point map is spec'd in [producer.md](../producer.md).
|
|
- iroh-socks5's design ideas (the `{addr, data}` frame, control-EOF
|
|
association lifetime, FRAG≠0 refusal) were adopted at the design
|
|
level, not the code level (`docs/research/iroh-socks5-eval.md`).
|
|
|
|
## References
|
|
|
|
- OQ-SK-04 (resolved: the extracted-and-forked base), OQ-SK-03 (the
|
|
`run_udp_proxy_custom` caveat)
|
|
- `docs/research/iroh-socks5-eval.md` (the base comparison),
|
|
POC #1 + POC #4 (`poc-connect-wasm-findings.md`)
|
|
- Sibling precedent: alktunnels ADR-002 (one-ALPN option A) |