1#![warn(missing_docs)]
4
5use std::{
6 net::{Ipv4Addr, Ipv6Addr},
7 str::FromStr,
8};
9
10use bytes::{Buf, BufMut, BytesMut};
11
12#[cfg(feature = "async")]
13mod async_;
14#[cfg(feature = "async")]
15pub use async_::*;
16
17#[cfg(feature = "sync")]
18mod sync;
19#[cfg(feature = "sync")]
20pub use sync::*;
21
22pub const VERS: u8 = 0x05;
24pub type IOResult<T> = std::io::Result<T>;
26
27pub struct AuthMethod;
29
30impl AuthMethod {
31 pub fn none() -> u8 {
33 0
34 }
35
36 pub fn is_none(m: u8) -> bool {
38 m == 0
39 }
40
41 pub fn gssapi() -> u8 {
43 1
44 }
45
46 pub fn is_gssapi(m: u8) -> bool {
48 m == 1
49 }
50
51 pub fn basic() -> u8 {
53 2
54 }
55
56 pub fn is_basic(m: u8) -> bool {
58 m == 2
59 }
60
61 pub fn is_iana_reserved(m: u8) -> bool {
63 m >= 0x3 && m <= 0x7f
64 }
65
66 pub fn is_reserved(m: u8) -> bool {
68 m >= 0x8 && m <= 0xfe
69 }
70
71 pub fn is_unavailable(m: u8) -> bool {
73 m == 0xff
74 }
75
76 pub fn unavailable() -> u8 {
78 0xff
79 }
80}
81
82fn build_init_req(methods: Vec<u8>) -> BytesMut {
83 assert!(methods.len() <= 255);
84 let mut buf = BytesMut::with_capacity(2 + methods.len());
85 buf.put_u8(VERS);
86 buf.put_u8(methods.len() as u8);
87 buf.extend_from_slice(&methods);
88 buf
89}
90
91fn parse_init_resp(data: [u8; 2]) -> u8 {
92 assert_eq!(data[0], VERS);
93 data[1]
94}
95
96fn build_auth_basic_req(username: String, password: String) -> BytesMut {
97 assert!(username.as_bytes().len() <= 255);
98 assert!(password.as_bytes().len() <= 255);
99 let mut data = BytesMut::new();
100 data.put_u8(1);
101 data.put_u8(username.as_bytes().len() as u8);
102 data.extend_from_slice(username.as_bytes());
103 data.put_u8(password.as_bytes().len() as u8);
104 data.extend_from_slice(password.as_bytes());
105 data
106}
107
108fn parse_auth_basic_resp(data: [u8; 2]) -> bool {
109 assert_eq!(data[0], 01);
110 data[1] == 0
111}
112
113pub enum Addr {
115 V4(Ipv4Addr),
117 Host(String),
119 V6(Ipv6Addr),
121}
122
123impl From<&str> for Addr {
124 fn from(addr: &str) -> Self {
125 Ipv4Addr::from_str(addr)
126 .map(Addr::V4)
127 .or_else(|_| Ipv6Addr::from_str(addr).map(Addr::V6))
128 .unwrap_or(Addr::Host(addr.to_string()))
129 }
130}
131
132impl Addr {
133 pub fn serde(&self, buf: &mut BytesMut) {
135 match self {
136 Addr::V4(addr) => {
137 buf.put_u8(1);
138 buf.extend_from_slice(&addr.octets());
139 }
140 Addr::Host(host) => {
141 buf.put_u8(03);
142 let data = host.as_bytes();
143 assert!(data.len() <= 255);
144 buf.put_u8(data.len() as u8);
145 buf.extend_from_slice(data);
146 }
147 Addr::V6(addr) => {
148 buf.put_u8(04);
149 buf.extend_from_slice(&addr.octets());
150 }
151 }
152 }
153
154 pub fn de_serde(buf: &mut BytesMut) -> Result<Self, String> {
156 let ty = buf.get_u8();
157 match ty {
158 1 => {
159 let mut addr = [0u8; 4];
160 for i in 0..4 {
161 addr[i] = buf.get_u8();
162 }
163 Ok(Self::V4(Ipv4Addr::from(addr)))
164 }
165 3 => {
166 let len = buf.get_u8() as usize;
167 let data = buf[..len].to_vec();
168 String::from_utf8(data)
169 .map(Self::Host)
170 .map_err(|_| "invalid utf8 hostname".to_string())
171 }
172 4 => {
173 let mut addr = [0u8; 16];
174 for i in 0..16 {
175 addr[i] = buf.get_u8();
176 }
177 Ok(Self::V6(Ipv6Addr::from(addr)))
178 }
179 _ => Err(format!("invalid addr type {}", ty)),
180 }
181 }
182}
183
184#[derive(Debug, Clone)]
186pub enum Command {
187 Connect,
189 Bind,
191 UdpAssociate,
193}
194
195impl Command {
196 pub fn as_u8(&self) -> u8 {
198 match self {
199 Command::Connect => 1,
200 Command::Bind => 2,
201 Command::UdpAssociate => 3,
202 }
203 }
204
205 pub fn from_u8(cmd: u8) -> Result<Self, u8> {
207 match cmd {
208 1 => Ok(Self::Connect),
209 2 => Ok(Self::Bind),
210 3 => Ok(Self::UdpAssociate),
211 _ => Err(cmd),
212 }
213 }
214}
215
216fn build_cmd_req(cmd: Command, addr: Addr, port: u16) -> BytesMut {
217 let mut data = BytesMut::new();
218 data.put_u8(VERS);
219 data.put_u8(cmd.as_u8());
220 data.put_u8(0);
221 addr.serde(&mut data);
222 data.put_u16(port);
223 data
224}
225
226#[derive(Debug, Clone)]
228pub enum Reply {
229 Succeeded,
231 ProxyServerFail,
233 RuleReject,
235 NetworkUnreachable,
237 HostUnreachable,
239 ConnectRefuse,
241 TTLExpired,
243 CommandNotSupported,
245 AddrTypeNotSupported,
247 Unassigned(u8),
249}
250
251impl Reply {
252 pub fn as_u8(&self) -> u8 {
254 match self {
255 Reply::Succeeded => 0,
256 Reply::ProxyServerFail => 1,
257 Reply::RuleReject => 2,
258 Reply::NetworkUnreachable => 3,
259 Reply::HostUnreachable => 4,
260 Reply::ConnectRefuse => 5,
261 Reply::TTLExpired => 6,
262 Reply::CommandNotSupported => 7,
263 Reply::AddrTypeNotSupported => 8,
264 Reply::Unassigned(x) => *x,
265 }
266 }
267
268 pub fn from_u8(x: u8) -> Self {
270 match x {
271 0 => Self::Succeeded,
272 1 => Self::ProxyServerFail,
273 2 => Self::RuleReject,
274 3 => Self::NetworkUnreachable,
275 4 => Self::HostUnreachable,
276 5 => Self::ConnectRefuse,
277 6 => Self::TTLExpired,
278 7 => Self::CommandNotSupported,
279 8 => Self::AddrTypeNotSupported,
280 _ => Self::Unassigned(x),
281 }
282 }
283}
284
285fn parse_cmd_resp(mut data: BytesMut) -> Result<(Reply, Addr, u16), String> {
286 let ver = data.get_u8();
287 assert_eq!(ver, VERS);
288 let reply = Reply::from_u8(data.get_u8());
289 let rsv = data.get_u8();
290 assert_eq!(rsv, 0);
291 let addr = Addr::de_serde(&mut data)?;
292 let port = data.get_u16();
293 Ok((reply, addr, port))
294}
295
296#[derive(Debug, Clone)]
298#[cfg_attr(feature = "ser", derive(serde::Serialize, serde::Deserialize))]
299pub struct ProxyConfig {
300 pub host: String,
303 pub port: u16,
305
306 pub auth: Option<AuthCredential>,
308}
309
310#[derive(Debug, Clone)]
312#[cfg_attr(feature = "ser", derive(serde::Serialize, serde::Deserialize))]
313pub struct AuthCredential {
314 user: String,
316 passwd: String,
318}