dlzht_socks5/
lib.rs

1#![feature(io_error_more)]
2
3//! ### Run server without any authorization
4//!
5//! ```
6//! use dlzht_socks5::server::SocksServerBuilder;
7//!
8//! #[tokio::main]
9//! async fn main() {
10//!     let server = SocksServerBuilder::new()
11//!         .allow_auth_skip(true)
12//!         .build().unwrap();
13//!     let _ = server.start().await;
14//! }
15//! ```
16//!
17//! Invoking `allow_auth_skip(true)`, server will support auth method `NO AUTHENTICATION REQUIRED`,
18//! which means auth phase can be skipped.
19//!
20//!
21//! ### Run server with password authorization
22//!
23//! ```
24//! use dlzht_socks5::server::SocksServerBuilder;
25//!
26//! #[tokio::main]
27//! async fn main() {
28//!     let server = SocksServerBuilder::new()
29//!         .credential(b"username", b"password")
30//!         .build().unwrap();
31//!     let _ = server.start().await;
32//! }
33//! ```
34//!
35//! Invoking `allow_auth_skip(true)`, server will support auth method `USERNAME/PASSWORD`,
36//! `allow_auth_pass` will auto be set true(we can set false back to disable password auth).
37//!
38//! If we hava multiple username/password, then we can invoke `credential(...)` repeatedly,
39//! or invoke `credentials(...)` for convenience.
40//!
41//! ### Custom validate username/password
42//!
43//! Will support soon
44//!
45//! ### Run client without any authorization
46//! ```
47//! use dlzht_socks5::client::SocksClientBuilder;
48//! use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
49//!
50//! #[tokio::main]
51//! async fn main() {
52//!     let address = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080));
53//!     let mut client = SocksClientBuilder::new()
54//!         .server_address(address)
55//!         .allow_auth_skip(true)
56//!         .build()
57//!         .unwrap();
58//!     let mut stream = client
59//!         .connect(("127.0.0.1".to_string(), 9000))
60//!         .await
61//!         .unwrap();
62//! }
63//! ```
64//!
65//! ### Run client with password authorization
66//!
67//! ```
68//! use dlzht_socks5::client::SocksClientBuilder;
69//! use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
70//!
71//! #[tokio::main]
72//! async fn main() {
73//!     let address = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080));
74//!     let mut client = SocksClientBuilder::new()
75//!         .server_address(address)
76//!         .credential(b"username", b"password")
77//!         .build()
78//!         .unwrap();
79//!     let mut stream = client
80//!         .connect(("127.0.0.1".to_string(), 9000))
81//!         .await
82//!         .unwrap();
83//! }
84//! ```
85
86use crate::errors::{InvalidPackageKind, SocksError, SocksResult};
87use std::io::ErrorKind;
88use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
89
90pub(crate) const SOCKS5_RSV_BYTE: u8 = 0x00;
91pub(crate) const SOCKS5_VERSION: u8 = 0x05;
92pub(crate) const SUB_NEG_VERSION: u8 = 0x01;
93
94pub(crate) const DEFAULT_SERVER_ADDR: SocketAddr =
95    SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
96
97#[derive(Debug, Copy, Clone)]
98pub(crate) struct PrivateStruct;
99
100#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Copy, Clone)]
101pub(crate) struct AuthMethod(u8);
102
103impl AuthMethod {
104    pub const SKIP: AuthMethod = AuthMethod(0x00);
105    pub const PASS: AuthMethod = AuthMethod(0x02);
106    pub const FAIL: AuthMethod = AuthMethod(0xFF);
107}
108
109impl AuthMethod {
110    fn from_byte(byte: u8) -> SocksResult<AuthMethod> {
111        match byte {
112            0x00 => Ok(AuthMethod::SKIP),
113            0x02 => Ok(AuthMethod::PASS),
114            _ => Ok(AuthMethod(byte)),
115        }
116    }
117
118    pub fn to_byte(&self) -> u8 {
119        self.0
120    }
121}
122
123#[derive(Debug, Clone)]
124pub(crate) struct AuthMethods {
125    methods: Vec<AuthMethod>,
126    _private: PrivateStruct,
127}
128
129impl AuthMethods {
130    pub fn new() -> AuthMethods {
131        return AuthMethods {
132            methods: Vec::with_capacity(2),
133            _private: PrivateStruct,
134        };
135    }
136
137    pub fn insert(&mut self, method: AuthMethod) -> bool {
138        return match self.methods.binary_search(&method) {
139            Ok(_) => false,
140            Err(index) => {
141                self.methods.insert(index, method);
142                true
143            }
144        };
145    }
146
147    pub fn contains(&self, method: &AuthMethod) -> bool {
148        return self.methods.binary_search(method).is_ok();
149    }
150
151    pub fn len(&self) -> usize {
152        return self.methods.len();
153    }
154
155    pub fn iter(&self) -> std::slice::Iter<'_, AuthMethod> {
156        return self.methods.iter();
157    }
158}
159
160#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Copy, Clone)]
161pub(crate) struct RequestCmd(u8);
162
163impl RequestCmd {
164    pub const CONNECT: RequestCmd = RequestCmd(0x01);
165    pub const BIND: RequestCmd = RequestCmd(0x02);
166    pub const UDP: RequestCmd = RequestCmd(0x03);
167}
168
169impl RequestCmd {
170    fn from_byte(byte: u8) -> SocksResult<RequestCmd> {
171        match byte {
172            0x01 => Ok(RequestCmd::CONNECT),
173            0x02 => Ok(RequestCmd::BIND),
174            0x03 => Ok(RequestCmd::UDP),
175            _ => Err(SocksError::InvalidPackageErr(
176                InvalidPackageKind::InvalidRequestsCmd(byte),
177            )),
178        }
179    }
180
181    fn to_byte(&self) -> u8 {
182        self.0
183    }
184}
185
186#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Copy, Clone)]
187pub(crate) struct RepliesRep(u8);
188
189impl RepliesRep {
190    pub const SUCCESS: RepliesRep = RepliesRep(0x00);
191    pub const SOCKS_SERVER_FAILURE: RepliesRep = RepliesRep(0x01);
192    pub const NOT_ALLOWED_BY_RULESET: RepliesRep = RepliesRep(0x02);
193    pub const NETWORK_UNREACHABLE: RepliesRep = RepliesRep(0x03);
194    pub const HOST_UNREACHABLE: RepliesRep = RepliesRep(0x04);
195    pub const CONNECTION_REFUSED: RepliesRep = RepliesRep(0x05);
196    pub const TTL_EXPIRED: RepliesRep = RepliesRep(0x06);
197    pub const COMMAND_NOT_SUPPORTED: RepliesRep = RepliesRep(0x07);
198    pub const ADDR_TYPE_NOT_SUPPORTED: RepliesRep = RepliesRep(0x08);
199}
200
201impl RepliesRep {
202    fn message(&self) -> &'static str {
203        match self {
204            &RepliesRep::SUCCESS => "succeeded",
205            &RepliesRep::SOCKS_SERVER_FAILURE => "general SOCKS server failure",
206            &RepliesRep::NOT_ALLOWED_BY_RULESET => "connection not allowed by ruleset",
207            &RepliesRep::NETWORK_UNREACHABLE => "network unreachable",
208            &RepliesRep::HOST_UNREACHABLE => "host unreachable",
209            &RepliesRep::CONNECTION_REFUSED => "connection refused",
210            &RepliesRep::TTL_EXPIRED => "TTL expired",
211            &RepliesRep::COMMAND_NOT_SUPPORTED => "command not supported",
212            &RepliesRep::ADDR_TYPE_NOT_SUPPORTED => "address type not supported",
213            _ => "unassigned",
214        }
215    }
216}
217
218impl From<&std::io::Error> for RepliesRep {
219    fn from(value: &std::io::Error) -> Self {
220        match value.kind() {
221            ErrorKind::NetworkUnreachable
222            | ErrorKind::AddrNotAvailable
223            | ErrorKind::NetworkDown => RepliesRep::NETWORK_UNREACHABLE,
224            ErrorKind::HostUnreachable => RepliesRep::HOST_UNREACHABLE,
225            ErrorKind::ConnectionReset
226            | ErrorKind::ConnectionAborted
227            | ErrorKind::ConnectionRefused => RepliesRep::CONNECTION_REFUSED,
228            ErrorKind::TimedOut => RepliesRep::TTL_EXPIRED,
229            _ => RepliesRep::SOCKS_SERVER_FAILURE,
230        }
231    }
232}
233
234impl RepliesRep {
235    fn from_byte(byte: u8) -> SocksResult<RepliesRep> {
236        match byte {
237            0x00 => Ok(RepliesRep::SUCCESS),
238            0x01 => Ok(RepliesRep::SOCKS_SERVER_FAILURE),
239            0x02 => Ok(RepliesRep::NOT_ALLOWED_BY_RULESET),
240            0x03 => Ok(RepliesRep::NETWORK_UNREACHABLE),
241            0x04 => Ok(RepliesRep::HOST_UNREACHABLE),
242            0x05 => Ok(RepliesRep::CONNECTION_REFUSED),
243            0x06 => Ok(RepliesRep::TTL_EXPIRED),
244            0x07 => Ok(RepliesRep::COMMAND_NOT_SUPPORTED),
245            0x08 => Ok(RepliesRep::ADDR_TYPE_NOT_SUPPORTED),
246            _ => Ok(RepliesRep(byte)),
247        }
248    }
249
250    pub fn to_byte(&self) -> u8 {
251        self.0
252    }
253}
254
255/// three type of address SOCKS5 support
256/// 1. 0x01: Ipv4Addr + port
257/// 2. 0x04: Ipv6Addr + port
258/// 3. 0x03: DomainName + port
259#[derive(Debug)]
260pub enum SocksAddr {
261    IPV4(SocketAddrV4),
262    IPV6(SocketAddrV6),
263    Domain(String, u16),
264}
265
266impl SocksAddr {
267    /// type of Ipv4Addr is 0x01
268    pub const KIND_IPV4: u8 = 0x01;
269
270    /// type of Ipv6Addr is 0x01
271    pub const KIND_IPV6: u8 = 0x04;
272
273    /// type of DomainName is 0x01
274    pub const KIND_DOMAIN: u8 = 0x03;
275
276    pub const UNSPECIFIED_ADDR: SocksAddr =
277        SocksAddr::IPV4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080));
278}
279
280impl SocksAddr {
281    pub fn addr_type(&self) -> u8 {
282        match self {
283            SocksAddr::IPV4(_) => 0x01,
284            SocksAddr::IPV6(_) => 0x04,
285            SocksAddr::Domain(_, _) => 0x03,
286        }
287    }
288}
289
290/// convert trait from `SocketAddr` to [`SocksAddr`]
291pub trait ToSocksAddress {
292    /// convert `std::net::SocketAddrV4`, `std::net::SocketAddrV4`, or `DomainName + Port` to Socks5Addr
293    fn to_socks_addr(self) -> SocksAddr;
294}
295
296impl ToSocksAddress for SocketAddrV4 {
297    fn to_socks_addr(self) -> SocksAddr {
298        return SocksAddr::IPV4(self);
299    }
300}
301
302impl ToSocksAddress for SocketAddrV6 {
303    fn to_socks_addr(self) -> SocksAddr {
304        return SocksAddr::IPV6(self);
305    }
306}
307
308impl ToSocksAddress for (String, u16) {
309    fn to_socks_addr(self) -> SocksAddr {
310        return SocksAddr::Domain(self.0, self.1);
311    }
312}
313
314impl ToSocksAddress for SocketAddr {
315    fn to_socks_addr(self) -> SocksAddr {
316        return match self {
317            SocketAddr::V4(addr) => SocksAddr::IPV4(addr),
318            SocketAddr::V6(addr) => SocksAddr::IPV6(addr),
319        };
320    }
321}
322
323pub(crate) fn is_invalid_username(username: &[u8]) -> bool {
324    return username.is_empty() || username.len() > 255;
325}
326
327pub(crate) fn is_invalid_password(password: &[u8]) -> bool {
328    return password.is_empty() || password.len() > 255;
329}
330
331pub mod client;
332pub mod errors;
333mod package;
334pub mod server;