rfc1928: the targeted fork — rename + convention pass (ADR-013)
The mechanical half of the posture change: src/vendor/ ->
src/rfc1928/ (module alksocks::rfc1928), tests/vendor-differential.rs
-> tests/rfc1928-differential.rs (git mv — history preserved).
- Fork point pinned: the tree as of 5b18d4d (the extraction review's
gate commit); provenance permanent in the module docs and the
extended LICENSE notice (upstream MIT preserved, fork-point +
post-fork modification statement added — extend, never replace)
- The lint-allow posture dissolved: all module-level #[allow]s
removed and the suppressed smells fixed (u8::max_value() ->
u8::MAX, needless lifetimes elided, match_like_matches_macro
applied, io::Error::new(Other) -> io::Error::other, the
AuthMethod::new self-taking signature renamed
into_starting_state, the F-4 ToSocketAddrs string re-worded — it
no longer names the cut resolve_dns(), the unused ready! macro
and dead AuthenticationMethod::from_u8 removed, the upstream
commented-out async-std note folded into the impl doc)
- Module docs rewritten: ownership statement (project conventions
apply unconditionally), extraction provenance (ADR-011) +
ownership (ADR-013) + maintenance posture (behavioral reference,
hand-port path)
- Differential suite survives the rename untouched (32 tests pin
bytes, not upstream text)
Verification: cargo test (38+32 green), cargo clippy --all-targets
-D warnings, cargo fmt --check, cargo check/clippy
--target wasm32-unknown-unknown, cargo test --all-features, cargo
doc --no-deps — all pass.
This commit is contained in:
1 parent
001aac1fd5
commit
f8c34444fb
10 files changed
+151
-192
No files matched your search
+4
-4
@@ -10,14 +10,14 @@
|
||||
//! assembly shapes (`local`), never in the protocol layer.
|
||||
//!
|
||||
//! The RFC wire vocabulary and the explicit typestate live in
|
||||
//! [`vendor`]: an extraction of fast-socks5 v1.0.0's `T`-generic
|
||||
//! [`rfc1928`]: a targeted fork of fast-socks5 v1.0.0's `T`-generic
|
||||
//! subset (MIT, third-party upstream) carrying two deliberate changes
|
||||
//! (BIND support, `new_reply` publication) — see
|
||||
//! `docs/architecture/vendor.md` and ADR-011.
|
||||
//! `docs/architecture/rfc1928.md`, ADR-013, and ADR-011.
|
||||
//!
|
||||
//! Architecture: `docs/architecture/overview.md` (spec set:
|
||||
//! wire.md, producer.md, consumer.md, vendor.md).
|
||||
//! wire.md, producer.md, consumer.md, rfc1928.md).
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod vendor;
|
||||
pub mod rfc1928;
|
||||
@@ -4,13 +4,23 @@ https://github.com/dizda/fast-socks5
|
||||
|
||||
Copyright (c) 2025 Jonathan Dizdarevic
|
||||
|
||||
The files under this `src/vendor/` directory are an extraction of
|
||||
fast-socks5 v1.0.0 (https://github.com/dizda/fast-socks5), carried
|
||||
in-tree by alksocks under ADR-011 (docs/architecture/decisions/
|
||||
011-inline-vendor.md). Upstream has no per-file license headers; this
|
||||
bundled notice is the license obligation's carrier. The extraction
|
||||
cut and the carried changes are recorded in
|
||||
docs/architecture/vendor.md.
|
||||
The files under this `src/rfc1928/` directory were extracted from
|
||||
fast-socks5 v1.0.0 (https://github.com/dizda/fast-socks5) and are
|
||||
carried in-tree by alksocks (extraction per ADR-011,
|
||||
docs/architecture/decisions/011-inline-vendor.md; extraction range
|
||||
git 57b107b..5b18d4d; fork point = the tree as of commit 5b18d4d,
|
||||
the extraction review's gate commit — ownership per ADR-013,
|
||||
docs/architecture/decisions/013-targeted-fork.md). Upstream has no
|
||||
per-file license headers; this bundled notice is the license
|
||||
obligation's carrier. The extraction cut and the fork's deliberate
|
||||
modifications are recorded in docs/architecture/rfc1928.md.
|
||||
|
||||
Modifications after the fork point are Copyright (c) 2026 the
|
||||
alksocks developers, licensed under the crate license
|
||||
(MIT OR Apache-2.0, per alksocks' Cargo.toml); the upstream MIT
|
||||
notice above is preserved per its terms. The upstream project is
|
||||
third-party and unmodified in place — see the ADRs for what was
|
||||
changed after the fork point.
|
||||
|
||||
---
|
||||
|
||||
@@ -32,4 +42,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Vendored from fast-socks5 v1.0.0 (extraction — see the module doc
|
||||
//! in `mod.rs`; filled by the client-session extraction task).
|
||||
//! Forked from fast-socks5 v1.0.0 (upstream `src/client.rs` —
|
||||
//! extraction; ownership per ADR-013, see the crate root's `mod.rs`).
|
||||
//!
|
||||
//! Upstream file: `src/client.rs`. Extracted region: the `T`-generic
|
||||
//! Extracted region: the `T`-generic
|
||||
//! client session — [`Socks5Stream<S>`] with the `use_stream` path
|
||||
//! (the version/method greeting, the method-choice read, the
|
||||
//! password-auth sub-handshake, the request encoder `request_header`,
|
||||
@@ -12,7 +12,8 @@
|
||||
//! `pump_bidi`-shaped consumers and the front doors can pipe through
|
||||
//! it.
|
||||
//!
|
||||
//! Not extracted (vendor.md's cut table row 2): `Socks5Datagram`
|
||||
//! Not forked (rfc1928.md's not-forked inventory row 2):
|
||||
//! `Socks5Datagram`
|
||||
//! (struct + impl — the kernel `UdpSocket` associate client; the
|
||||
//! crate's associate session is first-party per ADR-003's handle
|
||||
//! swap) and the `Socks5Stream<TcpStream>` convenience impl
|
||||
@@ -41,17 +42,11 @@
|
||||
//! Tests are first-party (upstream's client test module rides the cut
|
||||
//! net region): raw-byte mock servers over tokio duplex streams, the
|
||||
//! pinned byte sequences written directly — keeping the client's wire
|
||||
//! expectations uncorrelated from the vendored server typestate.
|
||||
//!
|
||||
//! Verbatim-code lint posture: the copied regions are upstream
|
||||
//! v1.0.0 code (minus the cut + adjustments), so newer-clippy style
|
||||
//! lints on upstream style are allowed at module level rather than
|
||||
//! churned per-line — the diff vs the reference checkout stays
|
||||
//! mechanical (review task).
|
||||
//! expectations uncorrelated from the forked server typestate.
|
||||
|
||||
use crate::vendor::util::stream::read_exact;
|
||||
use crate::vendor::util::target_addr::{read_address, TargetAddr};
|
||||
use crate::vendor::{consts, AuthenticationMethod, ReplyError, Result, Socks5Command, SocksError};
|
||||
use crate::rfc1928::util::stream::read_exact;
|
||||
use crate::rfc1928::util::target_addr::{read_address, TargetAddr};
|
||||
use crate::rfc1928::{consts, AuthenticationMethod, ReplyError, Result, Socks5Command, SocksError};
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
@@ -1,44 +1,45 @@
|
||||
//! The inline vendor: an extraction of fast-socks5 v1.0.0's
|
||||
//! The RFC 1928 core: a targeted fork of fast-socks5 v1.0.0's
|
||||
//! `T`-generic subset (MIT, third-party upstream —
|
||||
//! github.com/dizda/fast-socks5; `/workspace/fast-socks5` is the
|
||||
//! read-only reference checkout, kept for differential testing of RFC
|
||||
//! edge cases).
|
||||
//! read-only reference checkout, kept for differential testing of
|
||||
//! RFC edge cases).
|
||||
//!
|
||||
//! Extracted per ADR-011 §Amendment (docs/architecture/decisions/
|
||||
//! 011-inline-vendor.md): only the code already generic over
|
||||
//! `T: AsyncRead + AsyncWrite + Unpin` rides in-tree — the kernel-net
|
||||
//! handlers, the `socks4` module, and the legacy `Config`/
|
||||
//! `Authentication` layer are **not** copied. The extraction cut, the
|
||||
//! two carried changes (BIND support, `new_reply` publication), and
|
||||
//! the extraction-time adjustments (no `anyhow`, no `log`, no
|
||||
//! `async-trait`) are recorded in `docs/architecture/vendor.md`.
|
||||
//! Arrived by extraction (ADR-011 §Amendment, docs/architecture/
|
||||
//! decisions/011-inline-vendor.md): only the code already generic
|
||||
//! over `T: AsyncRead + AsyncWrite + Unpin` was copied in-tree — the
|
||||
//! kernel-net handlers, the `socks4` module, and the legacy `Config`/
|
||||
//! `Authentication` layer were **not** copied. The extraction cut,
|
||||
//! the fork's two carried changes (BIND support, `new_reply`
|
||||
//! publication), and the extraction-time adjustments (no `anyhow`,
|
||||
//! no `log`, no `async-trait`) are recorded in
|
||||
//! `docs/architecture/rfc1928.md`.
|
||||
//!
|
||||
//! Ownership (ADR-013, docs/architecture/decisions/013-targeted-fork.md):
|
||||
//! this is fully owned code — project conventions apply
|
||||
//! unconditionally (no vendor carve-outs, no verbatim preservation,
|
||||
//! no lint-allow posture). Fork point: the tree as of the
|
||||
//! extraction-review commit (`5b18d4d`); extraction provenance in
|
||||
//! git history (`57b107b..5b18d4d`). A future upstream fix that
|
||||
//! matters is hand-ported against the reference checkout and guarded
|
||||
//! by the differential suite.
|
||||
//!
|
||||
//! This file is upstream's `src/lib.rs` vocabulary region (the
|
||||
//! wire-vocabulary extraction task): the `consts`, the command/auth
|
||||
//! enums, the reply-code codec, the UDP datagram codec, and the error
|
||||
//! vocabulary pruned to the extracted region's consumers. The
|
||||
//! typestate (upstream `server.rs`, minus the cut regions) lives in
|
||||
//! vocabulary pruned to the region's consumers. The typestate
|
||||
//! (upstream `server.rs`, minus the cut regions) lives in
|
||||
//! [`server`]; the client session (upstream `client.rs`, the
|
||||
//! `use_stream` path + the `AsyncRead`/`AsyncWrite` impls) lives in
|
||||
//! [`client`].
|
||||
//!
|
||||
//! License: upstream is MIT with no per-file headers — the bundled
|
||||
//! notice in `this module's LICENSE file` (`src/vendor/LICENSE`, v1.0.0
|
||||
//! attribution) is the license obligation's carrier.
|
||||
//! notice (`LICENSE`, this module's directory, v1.0.0 attribution +
|
||||
//! the fork-point statement) is the license obligation's carrier.
|
||||
//!
|
||||
//! Maintenance posture: the vendored code is first-class, co-evolves
|
||||
//! with the wrapper, and is the crate's only RFC 1928 wire vocabulary
|
||||
//! ("no second codec, ever" — ADR-011). A future upstream release is
|
||||
//! re-based against deliberately, never absorbed silently.
|
||||
//!
|
||||
//! Verbatim-code lint posture: the copied regions are upstream
|
||||
//! v1.0.0 code (minus the cut + adjustments), so newer-clippy style
|
||||
//! lints on upstream style are allowed at module level rather than
|
||||
//! churned per-line — the diff vs the reference checkout stays
|
||||
//! mechanical (review task).
|
||||
|
||||
#![allow(clippy::needless_lifetimes)]
|
||||
#![allow(clippy::redundant_closure)]
|
||||
//! Maintenance posture: this code co-evolves with the wrapper and is
|
||||
//! the crate's only RFC 1928 wire vocabulary ("no second codec,
|
||||
//! ever" — ADR-011's rationale, carried). Nothing is absorbed
|
||||
//! silently from upstream; nothing waits on upstream.
|
||||
|
||||
pub mod client;
|
||||
pub mod server;
|
||||
@@ -119,7 +120,6 @@ pub enum AuthenticationMethod {
|
||||
Password { username: String, password: String },
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl AuthenticationMethod {
|
||||
#[inline]
|
||||
#[rustfmt::skip]
|
||||
@@ -130,16 +130,6 @@ impl AuthenticationMethod {
|
||||
consts::SOCKS5_AUTH_METHOD_PASSWORD
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[rustfmt::skip]
|
||||
fn from_u8(code: u8) -> Option<AuthenticationMethod> {
|
||||
match code {
|
||||
consts::SOCKS5_AUTH_METHOD_NONE => Some(AuthenticationMethod::None),
|
||||
consts::SOCKS5_AUTH_METHOD_PASSWORD => Some(AuthenticationMethod::Password { username: "test".to_string(), password: "test".to_string()}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for AuthenticationMethod {
|
||||
@@ -299,9 +289,7 @@ pub fn new_udp_header<T: ToTargetAddr>(target_addr: T) -> Result<Vec<u8>, UdpHea
|
||||
}
|
||||
|
||||
/// Parse data from UDP client on raw buffer, return (frag, target_addr, payload).
|
||||
pub async fn parse_udp_request<'a>(
|
||||
mut req: &'a [u8],
|
||||
) -> Result<(u8, TargetAddr, &'a [u8]), UdpHeaderError> {
|
||||
pub async fn parse_udp_request(mut req: &[u8]) -> Result<(u8, TargetAddr, &[u8]), UdpHeaderError> {
|
||||
let rsv = read_exact!(req, [0u8; 2]).map_err(UdpHeaderError::ReadingError)?;
|
||||
|
||||
if !rsv.eq(&[0u8; 2]) {
|
||||
@@ -1,24 +1,24 @@
|
||||
//! Vendored from fast-socks5 v1.0.0 (extraction — see the module doc
|
||||
//! in `mod.rs`; filled by the server-typestate extraction task).
|
||||
//! Forked from fast-socks5 v1.0.0 (upstream `src/server.rs` —
|
||||
//! extraction; ownership per ADR-013, see the crate root's `mod.rs`).
|
||||
//!
|
||||
//! Upstream file: `src/server.rs`. Extracted region: the explicit
|
||||
//! Extracted region: the explicit
|
||||
//! typestate (`states`, `Socks5ServerProtocol<T, S>`, auth
|
||||
//! negotiation with the `AuthMethod<T>` machinery, `read_command`,
|
||||
//! `reply_success`, `reply_error`, `transfer`, `wait_on_tcp`,
|
||||
//! `ErrorContext<T>`), `SocksServerError`, and the published reply
|
||||
//! encoder `new_reply` (carried change #2 — upstream's is private,
|
||||
//! `fn new_reply` at `server.rs:1380`; in-tree it is `pub` so the
|
||||
//! `fn new_reply` at `server.rs:1380`; here it is `pub` so the
|
||||
//! BIND reply#2 writer and consumer reply readers reuse the
|
||||
//! 10/22-byte reply form instead of re-encoding it). The cut regions
|
||||
//! (the legacy `Socks5Server`/`Socks5Socket`/`Config`/`Authentication`
|
||||
//! layer, the `run_*` kernel-net handlers, `DnsResolveHelper`, the
|
||||
//! net-only tests) stay in `/workspace/fast-socks5` — the cut table
|
||||
//! row 1 in `docs/architecture/vendor.md`.
|
||||
//! net-only tests) stay in `/workspace/fast-socks5` — the not-forked
|
||||
//! inventory row 1 in `docs/architecture/rfc1928.md`.
|
||||
//!
|
||||
//! Extraction-time adjustments (mechanical, ADR-011 §Amendment):
|
||||
//! `log` calls dropped; `anyhow::Context` dropped; the
|
||||
//! `#[macro_export]` on `auth_method_enums!` converted to
|
||||
//! `pub(crate) use` scoping (same adjustment as `read_exact!`);
|
||||
//! `#[macro_export]` on `auth_method_enums!` converted to `pub`
|
||||
//! scoping within this module (same adjustment as `read_exact!`);
|
||||
//! `reply_error`'s `"0.0.0.0:0".parse().unwrap()` replaced with a
|
||||
//! `const` parsed at compile time (no `unwrap` outside tests).
|
||||
//! The upstream `Config<A>`/`Authentication` impls that consumed
|
||||
@@ -30,24 +30,16 @@
|
||||
//! `reply_success(sock_addr)` carries reply#1's BND.ADDR, and
|
||||
//! reply#2 is written with the published `new_reply`. No BIND code
|
||||
//! lives here; this file only guarantees the surface is present.
|
||||
//!
|
||||
//! Verbatim-code lint posture: the copied regions are upstream
|
||||
//! v1.0.0 code (minus the cut + adjustments), so newer-clippy style
|
||||
//! lints on upstream style are allowed at module level rather than
|
||||
//! churned per-line — the diff vs the reference checkout stays
|
||||
//! mechanical (review task).
|
||||
|
||||
#![allow(clippy::wrong_self_convention)] // AuthMethod::new(self, ..) is upstream
|
||||
|
||||
use crate::vendor::consts;
|
||||
use crate::vendor::util::stream::read_exact;
|
||||
use crate::vendor::util::stream::ConnectError;
|
||||
use crate::vendor::util::target_addr::read_address;
|
||||
use crate::vendor::util::target_addr::TargetAddr;
|
||||
use crate::vendor::AddrError;
|
||||
use crate::vendor::ReplyError;
|
||||
use crate::vendor::Socks5Command;
|
||||
use crate::vendor::UdpHeaderError;
|
||||
use crate::rfc1928::consts;
|
||||
use crate::rfc1928::util::stream::read_exact;
|
||||
use crate::rfc1928::util::stream::ConnectError;
|
||||
use crate::rfc1928::util::target_addr::read_address;
|
||||
use crate::rfc1928::util::target_addr::TargetAddr;
|
||||
use crate::rfc1928::AddrError;
|
||||
use crate::rfc1928::ReplyError;
|
||||
use crate::rfc1928::Socks5Command;
|
||||
use crate::rfc1928::UdpHeaderError;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::Ipv4Addr;
|
||||
@@ -249,7 +241,7 @@ pub trait AuthMethodSuccessState<T> {
|
||||
pub trait AuthMethod<T>: Copy {
|
||||
type StartingState;
|
||||
fn method_id(self) -> u8;
|
||||
fn new(self, inner: T) -> Self::StartingState;
|
||||
fn into_starting_state(self, inner: T) -> Self::StartingState;
|
||||
}
|
||||
|
||||
pub struct NoAuthenticationImpl<T>(T);
|
||||
@@ -278,7 +270,7 @@ impl<T> AuthMethod<T> for NoAuthentication {
|
||||
0x00
|
||||
}
|
||||
|
||||
fn new(self, inner: T) -> Self::StartingState {
|
||||
fn into_starting_state(self, inner: T) -> Self::StartingState {
|
||||
NoAuthenticationImpl(inner)
|
||||
}
|
||||
}
|
||||
@@ -384,7 +376,7 @@ impl<T> AuthMethod<T> for PasswordAuthentication {
|
||||
0x02
|
||||
}
|
||||
|
||||
fn new(self, inner: T) -> Self::StartingState {
|
||||
fn into_starting_state(self, inner: T) -> Self::StartingState {
|
||||
PasswordAuthenticationImpl::new(inner)
|
||||
}
|
||||
}
|
||||
@@ -428,18 +420,15 @@ macro_rules! auth_method_enums {
|
||||
}
|
||||
}
|
||||
|
||||
fn new(self, inner: T) -> Self::StartingState {
|
||||
fn into_starting_state(self, inner: T) -> Self::StartingState {
|
||||
match self {
|
||||
$($enum::$method(auth) => $state_enum::$method(auth.new(inner))),+
|
||||
$($enum::$method(auth) => $state_enum::$method(auth.into_starting_state(inner))),+
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use auth_method_enums;
|
||||
|
||||
auth_method_enums! {
|
||||
/// The combination of all authentication methods supported by this crate out of the box,
|
||||
/// as an enum appropriate for static dispatch.
|
||||
@@ -503,7 +492,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin> Socks5ServerProtocol<T, states::Opened>
|
||||
.write_all(&[consts::SOCKS5_VERSION, *client_method_id])
|
||||
.await
|
||||
.err_when("replying with auth method")?;
|
||||
return Ok(server_method.new(self.inner));
|
||||
return Ok(server_method.into_starting_state(self.inner));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -660,9 +649,9 @@ mod tests {
|
||||
use super::states;
|
||||
use super::Socks5ServerProtocol;
|
||||
use super::SocksServerError;
|
||||
use crate::vendor::util::target_addr::TargetAddr;
|
||||
use crate::vendor::ReplyError;
|
||||
use crate::vendor::Socks5Command;
|
||||
use crate::rfc1928::util::target_addr::TargetAddr;
|
||||
use crate::rfc1928::ReplyError;
|
||||
use crate::rfc1928::Socks5Command;
|
||||
use std::net::SocketAddr;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Vendored from fast-socks5 v1.0.0 (extraction — see the module doc
|
||||
//! in the vendor root's `mod.rs`).
|
||||
//! The RFC 1928 core's utility modules (upstream `src/util/` —
|
||||
//! extraction; see the fork statement in the crate root's `mod.rs`
|
||||
//! and ADR-013 for ownership).
|
||||
//!
|
||||
//! Upstream layout: `stream.rs` (the `read_exact!`/`ready!` macros +
|
||||
//! `ConnectError`) and `target_addr.rs` (`TargetAddr` + the address
|
||||
@@ -1,14 +1,16 @@
|
||||
//! Vendored from fast-socks5 v1.0.0 (extraction — see the module doc
|
||||
//! in the vendor root's `mod.rs`).
|
||||
//! Forked from fast-socks5 v1.0.0 (upstream `src/util/stream.rs` —
|
||||
//! extraction; ownership per ADR-013, see the crate root's `mod.rs`).
|
||||
//!
|
||||
//! Upstream carries the `read_exact!`/`ready!` macros, `ConnectError`,
|
||||
//! and the `tcp_connect*` dialers; only the macros + `ConnectError`
|
||||
//! ride the extraction (the dialers are the cut kernel-net region —
|
||||
//! the crate's local backend is first-party tokio code, ADR-008).
|
||||
//! Extraction-time adjustment: upstream exports both macros at the
|
||||
//! crate root via `#[macro_export]`; in-tree they are plain
|
||||
//! `macro_rules!` scoped by `pub(crate) use` so they stay internal to
|
||||
//! the vendor (implementation detail, not alksocks public API).
|
||||
//! and the `tcp_connect*` dialers; only the `read_exact!` macro +
|
||||
//! `ConnectError` rode the extraction (the dialers and the `ready!`
|
||||
//! macro are the cut kernel-net region — the crate's local backend is
|
||||
//! first-party tokio code, ADR-008, and nothing in the extracted
|
||||
//! region used `ready!`). Extraction-time adjustment: upstream
|
||||
//! exports the macro at the crate root via `#[macro_export]`; here it
|
||||
//! is a plain `macro_rules!` scoped by `pub(crate) use` so it stays
|
||||
//! internal to the RFC 1928 core (implementation detail, not alksocks
|
||||
//! public API).
|
||||
|
||||
/// Easy to destructure bytes buffers by naming each fields:
|
||||
///
|
||||
@@ -36,21 +38,9 @@ macro_rules! read_exact {
|
||||
}};
|
||||
}
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! ready {
|
||||
($e:expr $(,)?) => {
|
||||
match $e {
|
||||
std::task::Poll::Ready(t) => t,
|
||||
std::task::Poll::Pending => return std::task::Poll::Pending,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use read_exact;
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use ready;
|
||||
|
||||
use crate::vendor::ReplyError;
|
||||
use crate::rfc1928::ReplyError;
|
||||
use std::io;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
@@ -86,7 +76,7 @@ impl ConnectError {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ConnectError;
|
||||
use crate::vendor::ReplyError;
|
||||
use crate::rfc1928::ReplyError;
|
||||
use std::io::ErrorKind;
|
||||
|
||||
#[test]
|
||||
@@ -1,29 +1,18 @@
|
||||
//! Vendored from fast-socks5 v1.0.0 (extraction — see the module doc
|
||||
//! in the vendor root's `mod.rs`).
|
||||
//! Forked from fast-socks5 v1.0.0 (upstream `src/util/target_addr.rs`
|
||||
//! — extraction; ownership per ADR-013, see the crate root's
|
||||
//! `mod.rs`).
|
||||
//!
|
||||
//! Upstream carries `TargetAddr`, the address codec (`read_address`),
|
||||
//! and the `resolve_dns` helper; only the codec rides the extraction
|
||||
//! and the `resolve_dns` helper; only the codec rode the extraction
|
||||
//! (DNS resolution is the cut net region — `tokio::net::lookup_host`
|
||||
//! is not in the wasm-clean graph). The `resolve_dns` method is cut
|
||||
//! with its two `AddrError` variants (`DNSResolutionFailed`,
|
||||
//! `NoDNSRecords`); the `ToSocketAddrs` impl's error text referencing
|
||||
//! `resolve_dns` is preserved verbatim for fidelity.
|
||||
//!
|
||||
//! Verbatim-code lint posture: this file is upstream v1.0.0 code
|
||||
//! (minus the cut region), so newer-clippy style lints on upstream
|
||||
//! style are allowed at module level rather than churned per-line —
|
||||
//! the diff vs the reference checkout stays mechanical (review task).
|
||||
//! `NoDNSRecords`).
|
||||
|
||||
#![allow(clippy::match_like_matches_macro)] // upstream style
|
||||
#![allow(clippy::legacy_numeric_constants)] // u8::max_value() is upstream
|
||||
#![allow(clippy::io_other_error)] // io::Error::new(Other) is upstream
|
||||
#![allow(clippy::needless_lifetimes)]
|
||||
#![allow(clippy::redundant_closure)]
|
||||
|
||||
use crate::vendor::consts;
|
||||
use crate::vendor::consts::SOCKS5_ADDR_TYPE_IPV4;
|
||||
use crate::vendor::util::stream::read_exact;
|
||||
use crate::vendor::ReplyError;
|
||||
use crate::rfc1928::consts;
|
||||
use crate::rfc1928::consts::SOCKS5_ADDR_TYPE_IPV4;
|
||||
use crate::rfc1928::util::stream::read_exact;
|
||||
use crate::rfc1928::ReplyError;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
@@ -76,10 +65,7 @@ pub enum TargetAddr {
|
||||
|
||||
impl TargetAddr {
|
||||
pub fn is_ip(&self) -> bool {
|
||||
match self {
|
||||
TargetAddr::Ip(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, TargetAddr::Ip(_))
|
||||
}
|
||||
|
||||
pub fn is_domain(&self) -> bool {
|
||||
@@ -102,7 +88,7 @@ impl TargetAddr {
|
||||
buf.extend_from_slice(&addr.port().to_be_bytes()); // port
|
||||
}
|
||||
TargetAddr::Domain(ref domain, port) => {
|
||||
if domain.len() > u8::max_value() as usize {
|
||||
if domain.len() > u8::MAX as usize {
|
||||
return Err(AddrError::DomainLenTooLong(domain.len()));
|
||||
}
|
||||
buf.extend_from_slice(&[consts::SOCKS5_ADDR_TYPE_DOMAIN_NAME, domain.len() as u8]);
|
||||
@@ -122,17 +108,17 @@ impl TargetAddr {
|
||||
}
|
||||
}
|
||||
|
||||
// async-std ToSocketAddrs doesn't supports external trait implementation
|
||||
// @see https://github.com/async-rs/async-std/issues/539
|
||||
/// The blocking `ToSocketAddrs` form: IP targets resolve directly;
|
||||
/// domain targets cannot be resolved here (domain resolution is the
|
||||
/// egress's job — ADR-012) and error.
|
||||
impl std::net::ToSocketAddrs for TargetAddr {
|
||||
type Iter = IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> io::Result<IntoIter<SocketAddr>> {
|
||||
match *self {
|
||||
TargetAddr::Ip(addr) => Ok(vec![addr].into_iter()),
|
||||
TargetAddr::Domain(_, _) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Domain name has to be explicitly resolved, please use TargetAddr::resolve_dns().",
|
||||
TargetAddr::Domain(_, _) => Err(io::Error::other(
|
||||
"Domain name cannot be resolved by the blocking ToSocketAddrs interface; resolve it before constructing the target.",
|
||||
)),
|
||||
}
|
||||
}
|
||||
@@ -154,7 +140,7 @@ pub trait ToTargetAddr {
|
||||
fn to_target_addr(&self) -> io::Result<TargetAddr>;
|
||||
}
|
||||
|
||||
impl<'a> ToTargetAddr for (&'a str, u16) {
|
||||
impl ToTargetAddr for (&str, u16) {
|
||||
fn to_target_addr(&self) -> io::Result<TargetAddr> {
|
||||
// try to parse as an IP first
|
||||
if let Ok(addr) = self.0.parse::<Ipv4Addr>() {
|
||||
@@ -228,18 +214,17 @@ pub async fn read_address<T: AsyncRead + Unpin>(
|
||||
) -> Result<TargetAddr, AddrError> {
|
||||
let addr = match atyp {
|
||||
consts::SOCKS5_ADDR_TYPE_IPV4 => {
|
||||
Addr::V4(read_exact!(stream, [0u8; 4]).map_err(|err| AddrError::IPv4Unreadable(err))?)
|
||||
Addr::V4(read_exact!(stream, [0u8; 4]).map_err(AddrError::IPv4Unreadable)?)
|
||||
}
|
||||
consts::SOCKS5_ADDR_TYPE_IPV6 => {
|
||||
Addr::V6(read_exact!(stream, [0u8; 16]).map_err(|err| AddrError::IPv6Unreadable(err))?)
|
||||
Addr::V6(read_exact!(stream, [0u8; 16]).map_err(AddrError::IPv6Unreadable)?)
|
||||
}
|
||||
consts::SOCKS5_ADDR_TYPE_DOMAIN_NAME => {
|
||||
let len =
|
||||
read_exact!(stream, [0]).map_err(|err| AddrError::DomainLenUnreadable(err))?[0];
|
||||
let len = read_exact!(stream, [0]).map_err(AddrError::DomainLenUnreadable)?[0];
|
||||
let domain = read_exact!(stream, vec![0u8; len as usize])
|
||||
.map_err(|err| AddrError::DomainContentUnreadable(err))?;
|
||||
.map_err(AddrError::DomainContentUnreadable)?;
|
||||
// make sure the bytes are correct utf8 string
|
||||
let domain = String::from_utf8(domain).map_err(|err| AddrError::Utf8(err))?;
|
||||
let domain = String::from_utf8(domain).map_err(AddrError::Utf8)?;
|
||||
|
||||
Addr::Domain(domain)
|
||||
}
|
||||
@@ -247,7 +232,7 @@ pub async fn read_address<T: AsyncRead + Unpin>(
|
||||
};
|
||||
|
||||
// Find port number
|
||||
let port = read_exact!(stream, [0u8; 2]).map_err(|err| AddrError::PortNumberUnreadable(err))?;
|
||||
let port = read_exact!(stream, [0u8; 2]).map_err(AddrError::PortNumberUnreadable)?;
|
||||
// Convert (u8 * 2) into u16
|
||||
let port = (port[0] as u16) << 8 | port[1] as u16;
|
||||
|
||||
@@ -255,10 +240,10 @@ pub async fn read_address<T: AsyncRead + Unpin>(
|
||||
let addr: TargetAddr = match addr {
|
||||
Addr::V4([a, b, c, d]) => (Ipv4Addr::new(a, b, c, d), port)
|
||||
.to_target_addr()
|
||||
.map_err(|err| AddrError::AddrConversionFailed(err))?,
|
||||
.map_err(AddrError::AddrConversionFailed)?,
|
||||
Addr::V6(x) => (Ipv6Addr::from(x), port)
|
||||
.to_target_addr()
|
||||
.map_err(|err| AddrError::AddrConversionFailed(err))?,
|
||||
.map_err(AddrError::AddrConversionFailed)?,
|
||||
Addr::Domain(domain) => TargetAddr::Domain(domain, port),
|
||||
};
|
||||
|
||||
@@ -268,7 +253,7 @@ pub async fn read_address<T: AsyncRead + Unpin>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::vendor::consts;
|
||||
use crate::rfc1928::consts;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
async fn read_target_addr(bytes: &[u8]) -> Result<TargetAddr, AddrError> {
|
||||
Reference in new issue
Block a user