Files
alksocks/tasks/implementation/vendor-wire-vocabulary.md
T
glm-5.3-flash 7497b79c05 vendor: the wire vocabulary — consts, commands, codecs, errors, macros
Extract fast-socks5 v1.0.0's non-net lib.rs region into
src/vendor/mod.rs (scaffolding-pinned root; the task's lib.rs target
name corrected — a second root file would conflict, see task Notes):
consts, Socks5Command (as_u8/from_u8 made pub), AuthenticationMethod,
SocksError pruned to the extracted region's consumers (no anyhow/
Redaction/InvalidHeader/ReplySocks4Error/ArgumentInputError), the
Result alias, ReplyError codec, UdpHeaderError + new_udp_header/
parse_udp_request. util/target_addr.rs gains TargetAddr/AddrError
(minus resolve_dns + its two variants)/ToTargetAddr/Addr/read_address;
util/stream.rs gains the read_exact!/ready! macros (de-exported to
pub(crate) use) + ConnectError + to_reply_error. SocksServerError
lands verbatim in server.rs early — SocksError's #[from] needs it
before the typestate task. 16 first-party codec tests (round-trips,
mapping tables, garbage-RSV/unknown-ATYP); no sockets, no env_logger.
Newer-clippy style lints allowed at module level in vendored files
(verbatim diff posture, rationale recorded).

Verification: cargo test (16 pass) + --all-features; clippy
--all-targets -D warnings (native + wasm32); cargo check
--target wasm32-unknown-unknown; cargo fmt --check; cargo doc.
Negative sweeps: no anyhow/log/tokio::net/socket2/tokio-stream/
async-trait under src/vendor/; no #[macro_export]; resolve_dns and
the pruned error variants absent.
2026-09-21 13:13:56 +00:00

12 KiB
Raw Blame History

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
implementation/vendor-wire-vocabulary Vendor — the wire vocabulary (consts, commands, codecs, errors, macros) completed
implementation/vendor-crate-scaffolding
narrow low component implementation

Description

Extract the pure wire vocabulary from fast-socks5 v1.0.0 into src/vendor/ — the RFC 1928 codecs and error enums that everything else (typestate, client sessions, producer/consumer layers) consumes. This is the "codecs" row of vendor.md's extraction table plus the lib.rs non-net region. Copy from /workspace/fast-socks5 (read-only reference checkout) and apply the extraction-time adjustments; the result must be wasm-clean by construction (no tokio::net, no anyhow, no log).

What is extracted (upstream file → in-tree target):

  1. src/lib.rs → src/vendor/lib.rs (new file — upstream's lib.rs content minus the cut regions):
    • consts module verbatim (all SOCKS5_* constants).
    • Socks5Command enum + as_u8/from_u8 (make both pub — the producer's command dispatch and the consumer's request writer both need them; upstream keeps them private with #[allow(dead_code)]).
    • AuthenticationMethod enum + impls (consumed by the client session's use_stream path; keep as-is).
    • ReplyError enum + as_u8/from_u8 verbatim.
    • UdpHeaderError enum, new_udp_header, parse_udp_request verbatim (the ASSOCIATE datagram codec — vendor.md's codecs row).
    • Result<T, E = SocksError> type alias.
    • NOT extracted: the net-heavy test module (upstream lib.rs lines 345–520 — it binds real sockets; the crate's own test task covers these edge cases), the socks4 module declaration.
  2. src/util/target_addr.rs → src/vendor/util/target_addr.rs:
    • AddrError, TargetAddr (+ is_ip/is_domain/to_be_bytes/ into_string_and_port), ToSocketAddrs impl, Display impl, ToTargetAddr trait + all impls, Addr enum, read_address — verbatim.
    • NOT extracted: the resolve_dns method (POC #4's gate map — it is the one net-touching member; tokio::net::lookup_host is not in the wasm-clean graph). Delete the method; AddrError:: DNSResolutionFailed/NoDNSRecords go with it (see adjustments).
    • Drop the debug! log calls (upstream log → dropped or re-pointed at tracing; these are per-octet debug traces — drop them).
  3. src/util/stream.rs → src/vendor/util/stream.rs:
    • read_exact! and ready! macros verbatim. Adjustment: they are #[macro_export] upstream (crate-root exported, which would pollute the alksocks public API); convert to plain macro_rules! with pub(crate) use scoping inside the vendor module so they stay internal (the wrapper's own code gets its own macros; the vendor's are implementation detail).
    • ConnectError enum + to_reply_error verbatim (the reply-code mapping vocabulary — consumed by the dial seam's error mapping).
    • NOT extracted: tcp_connect/tcp_connect_with_timeout (the tokio::net::TcpStream dialers — POC #4's gate map; the crate's local backend is first-party tokio code, ADR-008).
  4. SocksError (in src/vendor/lib.rs) — the error vocabulary, pruned to what the extracted region + the crate's error surface actually consumes (vendor.md: "the vendored SocksError/ SocksServerError stay the wire-level vocabulary"):
    • Keep: Io, AuthMethodUnacceptable, UnsupportedSocksVersion, ExceededMaxDomainLen, AuthenticationRejected(String), ServerError(#[from] SocksServerError), UdpHeaderError(#[from] UdpHeaderError), AddrError(#[from] AddrError), ReplyError(#[from] ReplyError).
    • Drop: Redaction, InvalidHeader (dead upstream — no consumer in the extracted region), ConnectError(#[from] ConnectError) (its only producer was the cut tcp_connect*; ConnectError itself stays — the dial seam maps it), ReplySocks4Error (socks4 is cut), ArgumentInputError (no consumer), Other(#[from] anyhow::Error) (anyhow is dropped — vendor.md's adjustments).
    • Note: AuthenticationRejected(String) on SocksError is the client-side variant (client.rs uses it with a message); SocksServerError::AuthenticationRejected (unit) is the server-side one — both stay, each in its own enum.

Extraction-time adjustments (mechanical, per ADR-011 §Amendment + vendor.md): drop anyhow wrapping, drop log calls, prune error variants whose only producers/consumers were cut, keep thiserror derives. No behavior change: every kept codec's wire behavior is byte-identical to upstream v1.0.0.

Acceptance Criteria

  • src/vendor/lib.rs, src/vendor/util/{mod,stream,target_addr}.rs exist with the inventory above; cargo test compiles (boundary note: the vocabulary lives in src/vendor/mod.rs, not a second root file src/vendor/lib.rs — the completed scaffolding task pinned the vendor root as mod.rs with upstream file names preserved; a second root file would be an E0758 conflict. Upstream's lib.rs content minus the cut regions is what mod.rs now carries.)
  • cargo check --target wasm32-unknown-unknown clean
  • cargo check (native, default features) clean
  • No anyhow, log, tokio::net, socket2, tokio-stream, async-trait anywhere under src/vendor/
  • Socks5Command::as_u8/from_u8 are pub (the wrapper needs them; upstream had them private)
  • read_exact!/ready! are not exported at the crate root (no #[macro_export]); they resolve inside the vendor module
  • TargetAddr has no resolve_dns method; AddrError has no DNSResolutionFailed/NoDNSRecords variants
  • SocksError has no Other(anyhow::Error), no Redaction, no InvalidHeader, no ReplySocks4Error, no ArgumentInputError variants
  • cargo clippy --all-targets -- -D warnings and cargo fmt --check clean
  • Unit tests for the codecs pass: to_be_bytes/read_address round-trip (v4/v6/domain), new_udp_header/parse_udp_request round-trip, ReplyError::as_u8/from_u8 mapping table — ported from upstream's non-net test regions where extractable (vendor.md's "non-net test modules" row), adjusted to the crate's test layout (no env_logger, no real sockets)

References

  • docs/architecture/vendor.md (the extraction table + the cut table)
  • docs/architecture/decisions/011-inline-vendor.md §Amendment (the mechanical adjustments)
  • docs/architecture/decisions/002-protocol-base.md (the codecs are the wire vocabulary; "no second codec, ever")
  • Upstream: /workspace/fast-socks5/src/lib.rs, /workspace/fast-socks5/src/util/target_addr.rs, /workspace/fast-socks5/src/util/stream.rs
  • POC #4 gate map: docs/research/poc-connect-wasm-findings.md (lib.rs/util rows)

Notes

  • Module placement correction: the task text says src/vendor/lib.rs, but the completed scaffolding task pinned the vendor root as src/vendor/mod.rs (skeleton with mod + submodule declarations already committed, 57b107b). A second root file (lib.rs alongside mod.rs) is an E0758 conflict, so the vocabulary landed in mod.rs — upstream's lib.rs content minus the cut regions, appended after the scaffolding module doc. The review task's file-by-file diff vs upstream is unaffected (the upstream lib.rs region maps to mod.rs; noted here for the reviewer).
  • SocksServerError lands early: SocksError keeps ServerError(#[from] server::SocksServerError) per the task's keep-list, but server.rs was a stub — a #[from] needs the type now. Upstream defines SocksServerError at the top of server.rs; it landed there verbatim (enum + to_reply_error, including UnexpectedUdpControlGarbage) as the first item of the server-typestate task's inventory, with a module doc noting the early landing. The server task's remaining inventory is unchanged.
  • Verbatim-code lint posture: the copied upstream regions trip newer-clippy style lints (match_like_matches_macro, legacy_numeric_constants for u8::max_value(), io_other_error for io::Error::new(Other), needless_lifetimes, redundant_closure). Churning vendored code to satisfy a newer clippy would break the mechanical per-file diff posture (vendor.md §Maintenance Posture; review task criterion 1), so the lints are allowed at module level with the rationale recorded. Behavior is untouched.
  • AuthenticationMethod::as_u8/from_u8 stay private with upstream's #[allow(dead_code)]: the client session task's send_version_and_methods consumes them when it lands. Making them pub now would be ahead of need (the task pins pub only for Socks5Command).
  • ready! macro: upstream's server typestate consumes it (the transfer/wait_on_tcp region); nothing in the vocabulary region does. It rides with #[allow(unused_macros)]/#[allow(unused_imports)] until the typestate lands — kept verbatim now so the util diff stays complete.
  • Tests: the vocabulary region's unit tests are first-party (upstream's lib.rs test module is the cut net-heavy region — none of its tests are extractable); the codec tests here follow the crate's test layout (tokio duplex for read_address, plain slice parsing for parse_udp_request, no env_logger, no sockets). ConnectError::to_reply_error and AddrError:: to_reply_error mappings are pinned too (the dial seam + the address-type reply mapping are wire-adjacent behavior). Vendored enums keep upstream's derives (no PartialEq was added), so tests compare via as_u8()/matches! rather than adding derives.
  • The ToSocketAddrs impl's error string still names TargetAddr::resolve_dns() (upstream text preserved verbatim) even though the method is cut — noted in the module doc; a future consumer hitting that path gets the explicit-resolution message exactly as upstream produced it.

Summary

Extracted the wire vocabulary from fast-socks5 v1.0.0 per ADR-011 §Amendment + vendor.md: upstream lib.rs's non-net region (consts, Socks5Command with pub as_u8/from_u8, AuthenticationMethod, the pruned SocksError (no anyhow/Redaction/InvalidHeader/ ConnectError-from/ReplySocks4Error/ArgumentInputError), the Result alias, ReplyError codec, UdpHeaderError + new_udp_header/parse_udp_request) into src/vendor/mod.rs (the scaffolding-pinned root; the task's lib.rs target name corrected — see Notes), AddrError/TargetAddr/ToTargetAddr/Addr/ read_address minus resolve_dns into util/target_addr.rs, and the read_exact!/ready! macros (de-exported to pub(crate) use)

  • ConnectError + to_reply_error into util/stream.rs. SocksServerError (enum + to_reply_error) landed verbatim in server.rs early — SocksError's #[from] needs it before the typestate task lands. 16 first-party unit tests cover the codecs (v4/v6/domain round-trips, UDP header/parse incl. frag/payload/garbage RSV/unknown ATYP, reply-code mapping table, command mapping, to_reply_error mappings, ToTargetAddr conversions, domain-length cap). Verified: cargo test (16 pass), --all-features, clippy --all-targets -- -D warnings native + wasm32, cargo check --target wasm32-unknown-unknown, cargo fmt --check, cargo doc, and the negative sweeps (no anyhow/log/tokio::net/socket2/ tokio-stream/async-trait in vendor code; no #[macro_export]; resolve_dns + the five pruned error variants absent).