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