1use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
2use zeroize::Zeroizing;
3
4use crate::error::Socks5Error;
5
6pub const ATYP_IPV4: u8 = 0x01;
8pub const ATYP_DOMAIN: u8 = 0x03;
9pub const ATYP_IPV6: u8 = 0x04;
10
11pub const CMD_CONNECT: u8 = 0x01;
13pub const CMD_BIND: u8 = 0x02;
14pub const CMD_UDP_ASSOCIATE: u8 = 0x03;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum Socks5Command {
19 Connect,
20 Bind,
21 UdpAssociate,
22}
23
24pub fn parse_command(cmd: u8) -> Result<Socks5Command, Socks5Error> {
26 match cmd {
27 CMD_CONNECT => Ok(Socks5Command::Connect),
28 CMD_BIND => Ok(Socks5Command::Bind),
29 CMD_UDP_ASSOCIATE => Ok(Socks5Command::UdpAssociate),
30 _ => Err(Socks5Error::UnsupportedCommand(cmd)),
31 }
32}
33
34pub const REP_SUCCESS: u8 = 0x00;
36pub const REP_GENERAL_FAILURE: u8 = 0x01;
37pub const REP_NOT_ALLOWED: u8 = 0x02;
38pub const REP_COMMAND_NOT_SUPPORTED: u8 = 0x07;
39pub const REP_ADDRESS_TYPE_NOT_SUPPORTED: u8 = 0x08;
40
41const AUTH_NONE: u8 = 0x00;
43const AUTH_USERNAME_PASSWORD: u8 = 0x02;
44const AUTH_NO_ACCEPTABLE: u8 = 0xFF;
45
46const AUTH_VERSION: u8 = 0x01;
48
49const MAX_CRED_LEN: usize = 255;
51
52#[derive(Debug, Clone, PartialEq, Eq, Hash)]
54pub enum SocksAddr {
55 IPv4([u8; 4], u16),
56 Domain(String, u16),
57 IPv6([u8; 16], u16),
58}
59
60impl SocksAddr {
61 pub fn host_str(&self) -> String {
63 match self {
64 SocksAddr::IPv4(addr, _) => format!("{}.{}.{}.{}", addr[0], addr[1], addr[2], addr[3]),
65 SocksAddr::Domain(domain, _) => domain.clone(),
66 SocksAddr::IPv6(addr, _) => {
67 let segments: Vec<String> = addr
69 .chunks(2)
70 .map(|chunk| format!("{:02x}{:02x}", chunk[0], chunk[1]))
71 .collect();
72 format!("[{}]", segments.join(":"))
73 }
74 }
75 }
76
77 pub fn port(&self) -> u16 {
79 match self {
80 SocksAddr::IPv4(_, port) | SocksAddr::Domain(_, port) | SocksAddr::IPv6(_, port) => {
81 *port
82 }
83 }
84 }
85
86 pub fn encode_reply(&self) -> Result<Vec<u8>, Socks5Error> {
88 let mut buf = Vec::new();
89 match self {
90 SocksAddr::IPv4(addr, port) => {
91 buf.push(ATYP_IPV4);
92 buf.extend_from_slice(addr);
93 buf.extend_from_slice(&port.to_be_bytes());
94 }
95 SocksAddr::Domain(domain, port) => {
96 let byte_len = domain.len();
97 if byte_len > 255 {
98 return Err(Socks5Error::DomainTooLong(byte_len));
99 }
100 buf.push(ATYP_DOMAIN);
101 buf.push(byte_len as u8);
102 buf.extend_from_slice(domain.as_bytes());
103 buf.extend_from_slice(&port.to_be_bytes());
104 }
105 SocksAddr::IPv6(addr, port) => {
106 buf.push(ATYP_IPV6);
107 buf.extend_from_slice(addr);
108 buf.extend_from_slice(&port.to_be_bytes());
109 }
110 }
111 Ok(buf)
112 }
113}
114
115pub fn parse_method_negotiation(buf: &[u8]) -> Result<(Vec<u8>, &[u8]), Socks5Error> {
120 if buf.is_empty() {
121 return Err(Socks5Error::UnexpectedEof);
122 }
123 let version = buf[0];
124 if version != 0x05 {
125 return Err(Socks5Error::UnsupportedVersion(version));
126 }
127 if buf.len() < 2 {
128 return Err(Socks5Error::UnexpectedEof);
129 }
130 let nmethods = buf[1] as usize;
131 if buf.len() < 2 + nmethods {
132 return Err(Socks5Error::UnexpectedEof);
133 }
134 Ok((buf[2..2 + nmethods].to_vec(), &buf[2 + nmethods..]))
135}
136
137pub fn parse_connect_request(buf: &[u8]) -> Result<(SocksAddr, &[u8]), Socks5Error> {
141 if buf.len() < 4 {
142 return Err(Socks5Error::UnexpectedEof);
143 }
144 let version = buf[0];
145 if version != 0x05 {
146 return Err(Socks5Error::UnsupportedVersion(version));
147 }
148 let cmd = buf[1];
149 if cmd != CMD_CONNECT {
150 return Err(Socks5Error::UnsupportedCommand(cmd));
151 }
152 let rsv = buf[2];
153 if rsv != 0 {
154 return Err(Socks5Error::InvalidReservedByte(rsv));
155 }
156 let atyp = buf[3];
157
158 let (addr, rest) = match atyp {
159 ATYP_IPV4 => {
160 if buf.len() < 4 + 4 + 2 {
161 return Err(Socks5Error::UnexpectedEof);
162 }
163 let mut octets = [0u8; 4];
164 octets.copy_from_slice(&buf[4..8]);
165 let port = u16::from_be_bytes([buf[8], buf[9]]);
166 (SocksAddr::IPv4(octets, port), &buf[10..])
167 }
168 ATYP_DOMAIN => {
169 if buf.len() < 5 {
170 return Err(Socks5Error::UnexpectedEof);
171 }
172 let len = buf[4] as usize;
173 if buf.len() < 5 + len + 2 {
174 return Err(Socks5Error::UnexpectedEof);
175 }
176 let domain_bytes = &buf[5..5 + len];
177 let domain = String::from_utf8(domain_bytes.to_vec())
178 .map_err(|e| Socks5Error::MalformedMessage(format!("invalid domain: {e}")))?;
179 let port = u16::from_be_bytes([buf[5 + len], buf[5 + len + 1]]);
180 (SocksAddr::Domain(domain, port), &buf[5 + len + 2..])
181 }
182 ATYP_IPV6 => {
183 if buf.len() < 4 + 16 + 2 {
184 return Err(Socks5Error::UnexpectedEof);
185 }
186 let mut octets = [0u8; 16];
187 octets.copy_from_slice(&buf[4..20]);
188 let port = u16::from_be_bytes([buf[20], buf[21]]);
189 (SocksAddr::IPv6(octets, port), &buf[22..])
190 }
191 _ => return Err(Socks5Error::UnsupportedAddressType(atyp)),
192 };
193
194 Ok((addr, rest))
195}
196
197pub fn parse_socks5_request(buf: &[u8]) -> Result<(Socks5Command, SocksAddr, &[u8]), Socks5Error> {
201 if buf.len() < 4 {
202 return Err(Socks5Error::UnexpectedEof);
203 }
204 let version = buf[0];
205 if version != 0x05 {
206 return Err(Socks5Error::UnsupportedVersion(version));
207 }
208 let cmd = buf[1];
209 let command = parse_command(cmd)?;
210 let rsv = buf[2];
211 if rsv != 0 {
212 return Err(Socks5Error::InvalidReservedByte(rsv));
213 }
214 let atyp = buf[3];
215
216 let (addr, rest) = match atyp {
217 ATYP_IPV4 => {
218 if buf.len() < 4 + 4 + 2 {
219 return Err(Socks5Error::UnexpectedEof);
220 }
221 let mut octets = [0u8; 4];
222 octets.copy_from_slice(&buf[4..8]);
223 let port = u16::from_be_bytes([buf[8], buf[9]]);
224 (SocksAddr::IPv4(octets, port), &buf[10..])
225 }
226 ATYP_DOMAIN => {
227 if buf.len() < 5 {
228 return Err(Socks5Error::UnexpectedEof);
229 }
230 let len = buf[4] as usize;
231 if buf.len() < 5 + len + 2 {
232 return Err(Socks5Error::UnexpectedEof);
233 }
234 let domain_bytes = &buf[5..5 + len];
235 let domain = String::from_utf8(domain_bytes.to_vec())
236 .map_err(|e| Socks5Error::MalformedMessage(format!("invalid domain: {e}")))?;
237 let port = u16::from_be_bytes([buf[5 + len], buf[5 + len + 1]]);
238 (SocksAddr::Domain(domain, port), &buf[5 + len + 2..])
239 }
240 ATYP_IPV6 => {
241 if buf.len() < 4 + 16 + 2 {
242 return Err(Socks5Error::UnexpectedEof);
243 }
244 let mut octets = [0u8; 16];
245 octets.copy_from_slice(&buf[4..20]);
246 let port = u16::from_be_bytes([buf[20], buf[21]]);
247 (SocksAddr::IPv6(octets, port), &buf[22..])
248 }
249 _ => return Err(Socks5Error::UnsupportedAddressType(atyp)),
250 };
251
252 Ok((command, addr, rest))
253}
254
255pub async fn read_method_negotiation<R: AsyncRead + Unpin>(
259 reader: &mut R,
260) -> Result<Vec<u8>, Socks5Error> {
261 let version = reader.read_u8().await?;
262 if version != 0x05 {
263 return Err(Socks5Error::UnsupportedVersion(version));
264 }
265
266 let nmethods = reader.read_u8().await?;
267 let mut methods = vec![0u8; nmethods as usize];
268 reader.read_exact(&mut methods).await?;
269
270 Ok(methods)
271}
272
273pub async fn send_method_selection<W: AsyncWrite + Unpin>(
281 writer: &mut W,
282 methods: &[u8],
283 password: Option<&str>,
284) -> Result<(), Socks5Error> {
285 let method = if let Some(_password) = password {
286 if methods.contains(&AUTH_USERNAME_PASSWORD) {
287 AUTH_USERNAME_PASSWORD
288 } else {
289 AUTH_NO_ACCEPTABLE
290 }
291 } else if methods.contains(&AUTH_NONE) {
292 AUTH_NONE
293 } else {
294 AUTH_NO_ACCEPTABLE
295 };
296
297 writer.write_all(&[0x05, method]).await?;
298 writer.flush().await?;
299
300 if method == AUTH_NO_ACCEPTABLE {
301 return Err(Socks5Error::MethodNegotiationFailed);
302 }
303
304 Ok(())
305}
306
307pub async fn read_auth_request<R: AsyncRead + Unpin>(
313 reader: &mut R,
314 expected_username: &str,
315 expected_password: &str,
316) -> Result<String, Socks5Error> {
317 let version = reader.read_u8().await?;
318 if version != AUTH_VERSION {
319 return Err(Socks5Error::UnsupportedVersion(version));
320 }
321
322 let ulen = reader.read_u8().await? as usize;
323 if ulen > MAX_CRED_LEN {
324 return Err(Socks5Error::CredentialsTooLong);
325 }
326 let mut username = Zeroizing::new(vec![0u8; ulen]);
327 reader.read_exact(&mut username).await?;
328
329 let plen = reader.read_u8().await? as usize;
330 if plen > MAX_CRED_LEN {
331 return Err(Socks5Error::CredentialsTooLong);
332 }
333 let mut password_bytes = Zeroizing::new(vec![0u8; plen]);
334 reader.read_exact(&mut password_bytes).await?;
335
336 use subtle::ConstantTimeEq;
339 let username_match: bool = username
340 .as_slice()
341 .ct_eq(expected_username.as_bytes())
342 .into();
343 let password_match: bool = password_bytes
344 .as_slice()
345 .ct_eq(expected_password.as_bytes())
346 .into();
347 if !username_match || !password_match {
348 return Err(Socks5Error::AuthFailed);
349 }
350
351 Ok(String::from_utf8_lossy(username.as_slice()).to_string())
352}
353
354pub async fn send_auth_response<W: AsyncWrite + Unpin>(
356 writer: &mut W,
357 success: bool,
358) -> Result<(), Socks5Error> {
359 let status = if success { 0x00 } else { 0x01 };
360 writer.write_all(&[AUTH_VERSION, status]).await?;
361 writer.flush().await?;
362 Ok(())
363}
364
365pub async fn read_connect_request<R: AsyncRead + Unpin>(
369 reader: &mut R,
370) -> Result<SocksAddr, Socks5Error> {
371 let version = reader.read_u8().await?;
372 if version != 0x05 {
373 return Err(Socks5Error::UnsupportedVersion(version));
374 }
375
376 let cmd = reader.read_u8().await?;
377 if cmd != CMD_CONNECT {
378 return Err(Socks5Error::UnsupportedCommand(cmd));
381 }
382
383 let rsv = reader.read_u8().await?;
384 if rsv != 0 {
385 return Err(Socks5Error::InvalidReservedByte(rsv));
386 }
387
388 let atyp = reader.read_u8().await?;
389
390 let addr = match atyp {
391 ATYP_IPV4 => {
392 let mut buf = [0u8; 4];
393 reader.read_exact(&mut buf).await?;
394 let port = reader.read_u16().await?;
395 SocksAddr::IPv4(buf, port)
396 }
397 ATYP_DOMAIN => {
398 let len = reader.read_u8().await? as usize;
399 let mut domain = vec![0u8; len];
400 reader.read_exact(&mut domain).await?;
401 let domain = String::from_utf8(domain)
402 .map_err(|e| Socks5Error::MalformedMessage(format!("invalid domain: {e}")))?;
403 let port = reader.read_u16().await?;
404 SocksAddr::Domain(domain, port)
405 }
406 ATYP_IPV6 => {
407 let mut buf = [0u8; 16];
408 reader.read_exact(&mut buf).await?;
409 let port = reader.read_u16().await?;
410 SocksAddr::IPv6(buf, port)
411 }
412 _ => return Err(Socks5Error::UnsupportedAddressType(atyp)),
413 };
414
415 Ok(addr)
416}
417
418pub async fn read_socks5_request<R: AsyncRead + Unpin>(
422 reader: &mut R,
423) -> Result<(Socks5Command, SocksAddr), Socks5Error> {
424 let version = reader.read_u8().await?;
425 if version != 0x05 {
426 return Err(Socks5Error::UnsupportedVersion(version));
427 }
428
429 let cmd = reader.read_u8().await?;
430 let command = parse_command(cmd)?;
431
432 let rsv = reader.read_u8().await?;
433 if rsv != 0 {
434 return Err(Socks5Error::InvalidReservedByte(rsv));
435 }
436
437 let atyp = reader.read_u8().await?;
438
439 let addr = match atyp {
440 ATYP_IPV4 => {
441 let mut buf = [0u8; 4];
442 reader.read_exact(&mut buf).await?;
443 let port = reader.read_u16().await?;
444 SocksAddr::IPv4(buf, port)
445 }
446 ATYP_DOMAIN => {
447 let len = reader.read_u8().await? as usize;
448 let mut domain = vec![0u8; len];
449 reader.read_exact(&mut domain).await?;
450 let domain = String::from_utf8(domain)
451 .map_err(|e| Socks5Error::MalformedMessage(format!("invalid domain: {e}")))?;
452 let port = reader.read_u16().await?;
453 SocksAddr::Domain(domain, port)
454 }
455 ATYP_IPV6 => {
456 let mut buf = [0u8; 16];
457 reader.read_exact(&mut buf).await?;
458 let port = reader.read_u16().await?;
459 SocksAddr::IPv6(buf, port)
460 }
461 _ => return Err(Socks5Error::UnsupportedAddressType(atyp)),
462 };
463
464 Ok((command, addr))
465}
466
467pub async fn send_udp_associate_reply<W: AsyncWrite + Unpin>(
469 writer: &mut W,
470 bind_addr: &SocksAddr,
471) -> Result<(), Socks5Error> {
472 send_connect_reply(writer, REP_SUCCESS, bind_addr).await
473}
474
475pub async fn send_connect_reply<W: AsyncWrite + Unpin>(
477 writer: &mut W,
478 rep: u8,
479 bind_addr: &SocksAddr,
480) -> Result<(), Socks5Error> {
481 let mut reply = vec![0x05, rep, 0x00]; reply.extend_from_slice(&bind_addr.encode_reply()?);
483 writer.write_all(&reply).await?;
484 writer.flush().await?;
485 Ok(())
486}
487
488pub async fn handle_socks5_handshake<R: AsyncRead + Unpin, W: AsyncWrite + Unpin>(
499 reader: &mut R,
500 writer: &mut W,
501 username: Option<&str>,
502 password: Option<&str>,
503) -> Result<SocksAddr, Socks5Error> {
504 let methods = read_method_negotiation(reader).await?;
506 send_method_selection(writer, &methods, password).await?;
507
508 if let Some(pwd) = password {
510 let user = username.unwrap_or("");
511 if let Err(e) = read_auth_request(reader, user, pwd).await {
512 let _ = send_auth_response(writer, false).await;
514 return Err(e);
515 }
516 send_auth_response(writer, true).await?;
517 }
518
519 match read_connect_request(reader).await {
521 Ok(target) => Ok(target),
522 Err(Socks5Error::UnsupportedCommand(cmd)) => {
523 let unspecified = SocksAddr::IPv4([0, 0, 0, 0], 0);
527 let _ = send_connect_reply(writer, REP_COMMAND_NOT_SUPPORTED, &unspecified).await;
528 Err(Socks5Error::UnsupportedCommand(cmd))
529 }
530 Err(e) => Err(e),
531 }
532}
533
534pub async fn reject_command<W: AsyncWrite + Unpin>(
536 writer: &mut W,
537 target: &SocksAddr,
538) -> Result<(), Socks5Error> {
539 send_connect_reply(writer, REP_COMMAND_NOT_SUPPORTED, target).await?;
540 Ok(())
541}
542
543pub const fn success_reply() -> u8 {
545 REP_SUCCESS
546}
547
548pub const fn general_failure_reply() -> u8 {
550 REP_GENERAL_FAILURE
551}
552
553pub const fn command_not_supported_reply() -> u8 {
555 REP_COMMAND_NOT_SUPPORTED
556}
557
558pub const fn address_type_not_supported_reply() -> u8 {
560 REP_ADDRESS_TYPE_NOT_SUPPORTED
561}
562
563#[cfg(test)]
564mod tests {
565 use super::*;
566 use tokio::io::duplex;
567
568 #[tokio::test]
569 async fn test_method_negotiation_no_auth() {
570 let (mut client, mut server) = duplex(1024);
571
572 client.write_all(&[0x05, 0x01, 0x00]).await.unwrap();
574
575 let methods = read_method_negotiation(&mut server).await.unwrap();
576 assert_eq!(methods, vec![0x00]);
577
578 send_method_selection(&mut server, &methods, None)
579 .await
580 .unwrap();
581
582 let mut response = [0u8; 2];
583 client.read_exact(&mut response).await.unwrap();
584 assert_eq!(response, [0x05, 0x00]); }
586
587 #[tokio::test]
588 async fn test_method_negotiation_username_password() {
589 let (mut client, mut server) = duplex(1024);
590
591 client.write_all(&[0x05, 0x02, 0x00, 0x02]).await.unwrap();
593
594 let methods = read_method_negotiation(&mut server).await.unwrap();
595 assert_eq!(methods, vec![0x00, 0x02]);
596
597 send_method_selection(&mut server, &methods, Some("secret"))
599 .await
600 .unwrap();
601
602 let mut response = [0u8; 2];
603 client.read_exact(&mut response).await.unwrap();
604 assert_eq!(response, [0x05, 0x02]); }
606
607 #[tokio::test]
608 async fn test_method_negotiation_no_acceptable() {
609 let (mut client, mut server) = duplex(1024);
610
611 client.write_all(&[0x05, 0x01, 0x01]).await.unwrap();
613
614 let methods = read_method_negotiation(&mut server).await.unwrap();
615 let result = send_method_selection(&mut server, &methods, None).await;
616 assert!(matches!(result, Err(Socks5Error::MethodNegotiationFailed)));
617 }
618
619 #[tokio::test]
620 async fn test_password_required_rejects_auth_none_only_client() {
621 let (mut client, mut server) = duplex(1024);
622
623 client.write_all(&[0x05, 0x01, 0x00]).await.unwrap();
625
626 let methods = read_method_negotiation(&mut server).await.unwrap();
627 let result = send_method_selection(&mut server, &methods, Some("secret")).await;
628 assert!(matches!(result, Err(Socks5Error::MethodNegotiationFailed)));
629
630 let mut response = [0u8; 2];
632 client.read_exact(&mut response).await.unwrap();
633 assert_eq!(response, [0x05, 0xFF]);
634 }
635
636 #[tokio::test]
637 async fn test_auth_success() {
638 let (mut client, mut server) = duplex(1024);
639
640 client
642 .write_all(&[0x01, 0x04, b'u', b's', b'e', b'r', 0x06])
643 .await
644 .unwrap();
645 client.write_all(b"secret").await.unwrap();
646
647 let username = read_auth_request(&mut server, "user", "secret")
648 .await
649 .unwrap();
650 assert_eq!(username, "user");
651
652 send_auth_response(&mut server, true).await.unwrap();
653
654 let mut response = [0u8; 2];
655 client.read_exact(&mut response).await.unwrap();
656 assert_eq!(response, [0x01, 0x00]); }
658
659 #[tokio::test]
660 async fn test_auth_failure() {
661 let (mut client, mut server) = duplex(1024);
662
663 client
665 .write_all(&[0x01, 0x04, b'u', b's', b'e', b'r', 0x05])
666 .await
667 .unwrap();
668 client.write_all(b"wrong").await.unwrap();
669
670 let result = read_auth_request(&mut server, "user", "secret").await;
671 assert!(matches!(result, Err(Socks5Error::AuthFailed)));
672 }
673
674 #[tokio::test]
675 async fn test_connect_ipv4() {
676 let (mut client, mut server) = duplex(1024);
677
678 client
680 .write_all(&[0x05, 0x01, 0x00, 0x01, 192, 168, 1, 1])
681 .await
682 .unwrap();
683 client.write_all(&8080u16.to_be_bytes()).await.unwrap();
684
685 let target = read_connect_request(&mut server).await.unwrap();
686 assert_eq!(target, SocksAddr::IPv4([192, 168, 1, 1], 8080));
687 }
688
689 #[tokio::test]
690 async fn test_connect_domain() {
691 let (mut client, mut server) = duplex(1024);
692
693 let domain = "example.com";
694 client
696 .write_all(&[0x05, 0x01, 0x00, 0x03, domain.len() as u8])
697 .await
698 .unwrap();
699 client.write_all(domain.as_bytes()).await.unwrap();
700 client.write_all(&443u16.to_be_bytes()).await.unwrap();
701
702 let target = read_connect_request(&mut server).await.unwrap();
703 assert_eq!(target, SocksAddr::Domain("example.com".to_string(), 443));
704 }
705
706 #[tokio::test]
707 async fn test_connect_ipv6() {
708 let (mut client, mut server) = duplex(1024);
709
710 let ipv6_addr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
712 client.write_all(&[0x05, 0x01, 0x00, 0x04]).await.unwrap();
713 client.write_all(&ipv6_addr).await.unwrap();
714 client.write_all(&443u16.to_be_bytes()).await.unwrap();
715
716 let target = read_connect_request(&mut server).await.unwrap();
717 assert_eq!(target, SocksAddr::IPv6(ipv6_addr, 443));
718 }
719
720 #[tokio::test]
721 async fn test_connect_reply_success() {
722 let (mut client, mut server) = duplex(1024);
723
724 let bind_addr = SocksAddr::IPv4([0, 0, 0, 0], 0);
725 send_connect_reply(&mut server, REP_SUCCESS, &bind_addr)
726 .await
727 .unwrap();
728
729 let mut response = [0u8; 10];
730 client.read_exact(&mut response).await.unwrap();
731 assert_eq!(response[0], 0x05); assert_eq!(response[1], 0x00); assert_eq!(response[2], 0x00); assert_eq!(response[3], 0x01); }
736
737 #[tokio::test]
738 async fn test_unsupported_version() {
739 let (mut client, mut server) = duplex(1024);
740
741 client.write_all(&[0x04, 0x01, 0x00]).await.unwrap();
743
744 let result = read_method_negotiation(&mut server).await;
745 assert!(matches!(result, Err(Socks5Error::UnsupportedVersion(0x04))));
746 }
747
748 #[tokio::test]
749 async fn test_unsupported_command() {
750 let (mut client, mut server) = duplex(1024);
751
752 let ipv4_addr = [192, 168, 1, 1];
754 client.write_all(&[0x05, 0x02, 0x00, 0x01]).await.unwrap();
755 client.write_all(&ipv4_addr).await.unwrap();
756 client.write_all(&80u16.to_be_bytes()).await.unwrap();
757
758 let result = read_connect_request(&mut server).await;
759 assert!(matches!(result, Err(Socks5Error::UnsupportedCommand(0x02))));
760 }
761
762 #[tokio::test]
763 async fn test_unsupported_address_type() {
764 let (mut client, mut server) = duplex(1024);
765
766 client.write_all(&[0x05, 0x01, 0x00, 0x05]).await.unwrap();
768
769 let result = read_connect_request(&mut server).await;
770 assert!(matches!(
771 result,
772 Err(Socks5Error::UnsupportedAddressType(0x05))
773 ));
774 }
775
776 #[tokio::test]
777 async fn test_reject_bind_command() {
778 let (mut client, mut server) = duplex(1024);
779
780 let target = SocksAddr::IPv4([192, 168, 1, 1], 80);
781 reject_command(&mut server, &target).await.unwrap();
782
783 let mut response = [0u8; 10];
784 client.read_exact(&mut response).await.unwrap();
785 assert_eq!(response[0], 0x05); assert_eq!(response[1], 0x07); }
788
789 #[tokio::test]
790 async fn test_reject_unknown_command() {
791 let (mut client, mut server) = duplex(1024);
792
793 let target = SocksAddr::IPv4([192, 168, 1, 1], 80);
794 reject_command(&mut server, &target).await.unwrap();
795
796 let mut response = [0u8; 10];
797 client.read_exact(&mut response).await.unwrap();
798 assert_eq!(response[0], 0x05); assert_eq!(response[1], 0x07); }
801
802 #[tokio::test]
803 async fn test_creds_too_long() {
804 }
807
808 #[tokio::test]
809 async fn test_boundary_credentials_length() {
810 let (mut client, mut server) = duplex(2048);
811
812 let username = "a".repeat(255);
813 let password = "b".repeat(255);
814
815 client.write_all(&[0x01, 255]).await.unwrap();
817 client.write_all(username.as_bytes()).await.unwrap();
818 client.write_all(&[255]).await.unwrap();
819 client.write_all(password.as_bytes()).await.unwrap();
820
821 let result = read_auth_request(&mut server, &username, &password).await;
822 assert!(result.is_ok());
823 assert_eq!(result.unwrap(), username);
824 }
825
826 #[tokio::test]
827 async fn test_full_handshake_no_auth() {
828 let (mut client, mut server) = duplex(1024);
829
830 client.write_all(&[0x05, 0x01, 0x00]).await.unwrap();
832
833 let methods = read_method_negotiation(&mut server).await.unwrap();
835 send_method_selection(&mut server, &methods, None)
836 .await
837 .unwrap();
838
839 let mut response = [0u8; 2];
841 client.read_exact(&mut response).await.unwrap();
842 assert_eq!(response, [0x05, 0x00]);
843
844 client
846 .write_all(&[0x05, 0x01, 0x00, 0x01, 10, 0, 0, 1])
847 .await
848 .unwrap();
849 client.write_all(&443u16.to_be_bytes()).await.unwrap();
850
851 let target = read_connect_request(&mut server).await.unwrap();
852 assert_eq!(target, SocksAddr::IPv4([10, 0, 0, 1], 443));
853
854 let bind_addr = SocksAddr::IPv4([0, 0, 0, 0], 0);
856 send_connect_reply(&mut server, REP_SUCCESS, &bind_addr)
857 .await
858 .unwrap();
859
860 let mut reply = [0u8; 10];
861 client.read_exact(&mut reply).await.unwrap();
862 assert_eq!(reply[0], 0x05);
863 assert_eq!(reply[1], 0x00);
864 }
865
866 #[tokio::test]
867 async fn test_full_handshake_with_auth() {
868 let (mut client, mut server) = duplex(2048);
869
870 client.write_all(&[0x05, 0x02, 0x00, 0x02]).await.unwrap();
872
873 let methods = read_method_negotiation(&mut server).await.unwrap();
875 send_method_selection(&mut server, &methods, Some("mypass"))
876 .await
877 .unwrap();
878
879 let mut response = [0u8; 2];
881 client.read_exact(&mut response).await.unwrap();
882 assert_eq!(response, [0x05, 0x02]);
883
884 client
886 .write_all(&[0x01, 0x04, b'u', b's', b'e', b'r'])
887 .await
888 .unwrap();
889 client
890 .write_all(&[0x06, b'm', b'y', b'p', b'a', b's', b's'])
891 .await
892 .unwrap();
893
894 let username = read_auth_request(&mut server, "user", "mypass")
895 .await
896 .unwrap();
897 assert_eq!(username, "user");
898 send_auth_response(&mut server, true).await.unwrap();
899
900 let mut auth_response = [0u8; 2];
902 client.read_exact(&mut auth_response).await.unwrap();
903 assert_eq!(auth_response, [0x01, 0x00]);
904
905 let domain = "example.com";
907 client
908 .write_all(&[0x05, 0x01, 0x00, 0x03, domain.len() as u8])
909 .await
910 .unwrap();
911 client.write_all(domain.as_bytes()).await.unwrap();
912 client.write_all(&443u16.to_be_bytes()).await.unwrap();
913
914 let target = read_connect_request(&mut server).await.unwrap();
915 assert_eq!(target, SocksAddr::Domain("example.com".to_string(), 443));
916 }
917
918 #[tokio::test]
919 async fn test_fragged_handshake() {
920 let (mut client, mut server) = duplex(1024);
921
922 client.write_all(&[0x05]).await.unwrap();
924 tokio::time::sleep(std::time::Duration::from_millis(10)).await;
926 client.write_all(&[0x01]).await.unwrap();
927 tokio::time::sleep(std::time::Duration::from_millis(10)).await;
928 client.write_all(&[0x00]).await.unwrap();
929
930 let methods = read_method_negotiation(&mut server).await.unwrap();
931 assert_eq!(methods, vec![0x00]);
932 }
933
934 #[tokio::test]
935 async fn test_socks_addr_display() {
936 let ipv4 = SocksAddr::IPv4([192, 168, 1, 1], 8080);
937 assert_eq!(ipv4.host_str(), "192.168.1.1");
938 assert_eq!(ipv4.port(), 8080);
939
940 let domain = SocksAddr::Domain("example.com".to_string(), 443);
941 assert_eq!(domain.host_str(), "example.com");
942 assert_eq!(domain.port(), 443);
943
944 let ipv6 = SocksAddr::IPv6([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 443);
945 assert_eq!(ipv6.port(), 443);
946 }
947
948 #[tokio::test]
949 async fn test_socks_addr_encode_reply() {
950 let ipv4 = SocksAddr::IPv4([192, 168, 1, 1], 8080);
951 let encoded = ipv4.encode_reply().unwrap();
952 assert_eq!(encoded[0], ATYP_IPV4);
953 assert_eq!(&encoded[1..5], &[192, 168, 1, 1]);
954 assert_eq!(&encoded[5..7], &8080u16.to_be_bytes());
955
956 let domain = SocksAddr::Domain("example.com".to_string(), 443);
957 let encoded = domain.encode_reply().unwrap();
958 assert_eq!(encoded[0], ATYP_DOMAIN);
959 assert_eq!(encoded[1], 11); assert_eq!(&encoded[2..13], b"example.com");
961 assert_eq!(&encoded[13..15], &443u16.to_be_bytes());
962 }
963
964 #[test]
965 fn test_parse_command() {
966 assert_eq!(parse_command(0x01).unwrap(), Socks5Command::Connect);
967 assert_eq!(parse_command(0x02).unwrap(), Socks5Command::Bind);
968 assert_eq!(parse_command(0x03).unwrap(), Socks5Command::UdpAssociate);
969 assert!(parse_command(0x04).is_err());
970 assert!(parse_command(0xFF).is_err());
971 }
972
973 #[tokio::test]
974 async fn test_udp_associate_ipv4() {
975 let (mut client, mut server) = duplex(1024);
976
977 client
979 .write_all(&[0x05, 0x03, 0x00, 0x01, 0, 0, 0, 0])
980 .await
981 .unwrap();
982 client.write_all(&0u16.to_be_bytes()).await.unwrap();
983
984 let (cmd, target) = read_socks5_request(&mut server).await.unwrap();
985 assert_eq!(cmd, Socks5Command::UdpAssociate);
986 assert_eq!(target, SocksAddr::IPv4([0, 0, 0, 0], 0));
987 }
988
989 #[tokio::test]
990 async fn test_udp_associate_ipv6() {
991 let (mut client, mut server) = duplex(1024);
992
993 let ipv6_addr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
994 client.write_all(&[0x05, 0x03, 0x00, 0x04]).await.unwrap();
995 client.write_all(&ipv6_addr).await.unwrap();
996 client.write_all(&0u16.to_be_bytes()).await.unwrap();
997
998 let (cmd, target) = read_socks5_request(&mut server).await.unwrap();
999 assert_eq!(cmd, Socks5Command::UdpAssociate);
1000 assert_eq!(target, SocksAddr::IPv6(ipv6_addr, 0));
1001 }
1002
1003 #[tokio::test]
1004 async fn test_udp_associate_domain() {
1005 let (mut client, mut server) = duplex(1024);
1006
1007 let domain = "example.com";
1008 client
1009 .write_all(&[0x05, 0x03, 0x00, 0x03, domain.len() as u8])
1010 .await
1011 .unwrap();
1012 client.write_all(domain.as_bytes()).await.unwrap();
1013 client.write_all(&0u16.to_be_bytes()).await.unwrap();
1014
1015 let (cmd, target) = read_socks5_request(&mut server).await.unwrap();
1016 assert_eq!(cmd, Socks5Command::UdpAssociate);
1017 assert_eq!(target, SocksAddr::Domain("example.com".to_string(), 0));
1018 }
1019
1020 #[tokio::test]
1021 async fn test_connect_still_works_via_read_socks5_request() {
1022 let (mut client, mut server) = duplex(1024);
1023
1024 client
1025 .write_all(&[0x05, 0x01, 0x00, 0x01, 192, 168, 1, 1])
1026 .await
1027 .unwrap();
1028 client.write_all(&8080u16.to_be_bytes()).await.unwrap();
1029
1030 let (cmd, target) = read_socks5_request(&mut server).await.unwrap();
1031 assert_eq!(cmd, Socks5Command::Connect);
1032 assert_eq!(target, SocksAddr::IPv4([192, 168, 1, 1], 8080));
1033 }
1034
1035 #[tokio::test]
1036 async fn test_reject_bind_only_not_udp_associate() {
1037 let (mut client, mut server) = duplex(1024);
1038
1039 let target = SocksAddr::IPv4([192, 168, 1, 1], 80);
1040 reject_command(&mut server, &target).await.unwrap();
1041
1042 let mut response = [0u8; 10];
1043 client.read_exact(&mut response).await.unwrap();
1044 assert_eq!(response[0], 0x05);
1045 assert_eq!(response[1], 0x07); }
1047
1048 #[tokio::test]
1049 async fn test_send_udp_associate_reply() {
1050 let (mut client, mut server) = duplex(1024);
1051
1052 let bind_addr = SocksAddr::IPv4([127, 0, 0, 1], 1080);
1053 send_udp_associate_reply(&mut server, &bind_addr)
1054 .await
1055 .unwrap();
1056
1057 let mut response = [0u8; 10];
1058 client.read_exact(&mut response).await.unwrap();
1059 assert_eq!(response[0], 0x05);
1060 assert_eq!(response[1], 0x00); assert_eq!(response[3], 0x01); assert_eq!(&response[4..8], &[127, 0, 0, 1]);
1063 assert_eq!(&response[8..10], &1080u16.to_be_bytes());
1064 }
1065
1066 #[test]
1067 fn parse_socks5_request_rsv_zero_accepted() {
1068 let buf = [0x05, 0x01, 0x00, 0x01, 127, 0, 0, 1, 0x00, 0x50];
1069 let result = parse_socks5_request(&buf);
1070 assert!(result.is_ok());
1071 }
1072
1073 #[test]
1074 fn parse_socks5_request_rsv_nonzero_rejected() {
1075 let buf = [0x05, 0x01, 0x01, 0x01, 127, 0, 0, 1, 0x00, 0x50];
1076 let result = parse_socks5_request(&buf);
1077 assert!(matches!(
1078 result,
1079 Err(Socks5Error::InvalidReservedByte(0x01))
1080 ));
1081 }
1082
1083 #[test]
1084 fn parse_connect_request_rsv_nonzero_rejected() {
1085 let buf = [0x05, 0x01, 0x42, 0x01, 127, 0, 0, 1, 0x00, 0x50];
1086 let result = parse_connect_request(&buf);
1087 assert!(matches!(
1088 result,
1089 Err(Socks5Error::InvalidReservedByte(0x42))
1090 ));
1091 }
1092
1093 #[tokio::test]
1094 async fn read_socks5_request_rsv_nonzero_rejected() {
1095 let (mut client, mut server) = duplex(1024);
1096
1097 client
1099 .write_all(&[0x05, 0x01, 0x01, 0x01, 127, 0, 0, 1])
1100 .await
1101 .unwrap();
1102 client.write_all(&80u16.to_be_bytes()).await.unwrap();
1103
1104 let result = read_socks5_request(&mut server).await;
1105 assert!(matches!(
1106 result,
1107 Err(Socks5Error::InvalidReservedByte(0x01))
1108 ));
1109 }
1110
1111 #[tokio::test]
1112 async fn read_connect_request_rsv_nonzero_rejected() {
1113 let (mut client, mut server) = duplex(1024);
1114
1115 client
1117 .write_all(&[0x05, 0x01, 0xFF, 0x01, 127, 0, 0, 1])
1118 .await
1119 .unwrap();
1120 client.write_all(&80u16.to_be_bytes()).await.unwrap();
1121
1122 let result = read_connect_request(&mut server).await;
1123 assert!(matches!(
1124 result,
1125 Err(Socks5Error::InvalidReservedByte(0xFF))
1126 ));
1127 }
1128
1129 #[test]
1130 fn encode_reply_domain_255_bytes_ok() {
1131 let domain = "a".repeat(255);
1132 let addr = SocksAddr::Domain(domain, 80);
1133 let encoded = addr.encode_reply().unwrap();
1134 assert_eq!(encoded[0], ATYP_DOMAIN);
1135 assert_eq!(encoded[1], 255);
1136 assert_eq!(&encoded[2..257], "a".repeat(255).as_bytes());
1137 assert_eq!(&encoded[257..259], &80u16.to_be_bytes());
1138 }
1139
1140 #[test]
1141 fn encode_reply_domain_256_bytes_error() {
1142 let domain = "a".repeat(256);
1143 let addr = SocksAddr::Domain(domain, 80);
1144 let result = addr.encode_reply();
1145 assert!(matches!(result, Err(Socks5Error::DomainTooLong(256))));
1146 }
1147
1148 #[test]
1149 fn encode_reply_multibyte_utf8_domain_exceeding_255_bytes() {
1150 let domain = "é".repeat(128);
1152 let addr = SocksAddr::Domain(domain, 80);
1153 let result = addr.encode_reply();
1154 assert!(matches!(result, Err(Socks5Error::DomainTooLong(256))));
1155 }
1156
1157 #[test]
1158 fn encode_reply_ipv4_unchanged() {
1159 let addr = SocksAddr::IPv4([192, 168, 1, 1], 8080);
1160 let encoded = addr.encode_reply().unwrap();
1161 assert_eq!(encoded, vec![ATYP_IPV4, 192, 168, 1, 1, 0x1F, 0x90]);
1162 }
1163
1164 #[test]
1165 fn encode_reply_ipv6_unchanged() {
1166 let addr = SocksAddr::IPv6([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 443);
1167 let encoded = addr.encode_reply().unwrap();
1168 assert_eq!(encoded[0], ATYP_IPV6);
1169 assert_eq!(
1170 &encoded[1..17],
1171 &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
1172 );
1173 assert_eq!(&encoded[17..19], &443u16.to_be_bytes());
1174 }
1175
1176 #[test]
1177 fn encode_reply_domain_unchanged_for_valid() {
1178 let addr = SocksAddr::Domain("example.com".to_string(), 443);
1179 let encoded = addr.encode_reply().unwrap();
1180 assert_eq!(encoded[0], ATYP_DOMAIN);
1181 assert_eq!(encoded[1], 11);
1182 assert_eq!(&encoded[2..13], b"example.com");
1183 assert_eq!(&encoded[13..15], &443u16.to_be_bytes());
1184 }
1185
1186 #[test]
1187 fn udp_rsv_first_byte_nonzero_rejected() {
1188 use super::super::udp_codec::{decode_socks5_udp_datagram, UdpCodecError};
1189 let pkt = vec![0x01, 0x00, 0x00, ATYP_IPV4, 1, 2, 3, 4, 0x00, 0x50];
1190 let result = decode_socks5_udp_datagram(&pkt);
1191 assert!(matches!(result, Err(UdpCodecError::BadReserved)));
1192 }
1193
1194 #[test]
1195 fn udp_rsv_second_byte_nonzero_rejected() {
1196 use super::super::udp_codec::{decode_socks5_udp_datagram, UdpCodecError};
1197 let pkt = vec![0x00, 0x01, 0x00, ATYP_IPV4, 1, 2, 3, 4, 0x00, 0x50];
1198 let result = decode_socks5_udp_datagram(&pkt);
1199 assert!(matches!(result, Err(UdpCodecError::BadReserved)));
1200 }
1201}