karyon_net/layers/proxy/
socks5.rs1use std::net::{Ipv4Addr, Ipv6Addr};
2
3use karyon_core::async_runtime::io::{AsyncReadExt, AsyncWriteExt};
4
5use crate::{layer::ClientLayer, ByteStream, Error, Result};
6
7const SOCKS5_VERSION: u8 = 0x05;
8const NO_AUTH: u8 = 0x00;
9const CMD_CONNECT: u8 = 0x01;
10const ATYPE_IPV4: u8 = 0x01;
11const ATYPE_DOMAIN: u8 = 0x03;
12const ATYPE_IPV6: u8 = 0x04;
13const REPLY_SUCCESS: u8 = 0x00;
14
15#[derive(Clone)]
37pub struct Socks5Layer {
38 target_host: String,
39 target_port: u16,
40}
41
42impl Socks5Layer {
43 pub fn new(host: &str, port: u16) -> Self {
45 Self {
46 target_host: host.to_string(),
47 target_port: port,
48 }
49 }
50}
51
52impl ClientLayer<Box<dyn ByteStream>, Box<dyn ByteStream>> for Socks5Layer {
53 async fn handshake(&self, mut stream: Box<dyn ByteStream>) -> Result<Box<dyn ByteStream>> {
54 stream.write_all(&[SOCKS5_VERSION, 1, NO_AUTH]).await?;
56 stream.flush().await?;
57
58 let mut resp = [0u8; 2];
60 stream.read_exact(&mut resp).await?;
61 if resp[0] != SOCKS5_VERSION || resp[1] != NO_AUTH {
62 return Err(Error::Socks5("server rejected auth method".into()));
63 }
64
65 let host = self.target_host.as_bytes();
67 let port = self.target_port.to_be_bytes();
68
69 let mut req = vec![SOCKS5_VERSION, CMD_CONNECT, 0x00];
70 if let Ok(ip) = self.target_host.parse::<Ipv4Addr>() {
71 req.push(ATYPE_IPV4);
72 req.extend_from_slice(&ip.octets());
73 } else if let Ok(ip) = self.target_host.parse::<Ipv6Addr>() {
74 req.push(ATYPE_IPV6);
75 req.extend_from_slice(&ip.octets());
76 } else {
77 req.push(ATYPE_DOMAIN);
78 req.push(host.len() as u8);
79 req.extend_from_slice(host);
80 }
81 req.extend_from_slice(&port);
82
83 stream.write_all(&req).await?;
84 stream.flush().await?;
85
86 let mut reply = [0u8; 4];
88 stream.read_exact(&mut reply).await?;
89 if reply[0] != SOCKS5_VERSION {
90 return Err(Error::Socks5("invalid reply version".into()));
91 }
92 if reply[1] != REPLY_SUCCESS {
93 return Err(Error::Socks5(format!("connect failed (code {})", reply[1])));
94 }
95
96 match reply[3] {
98 ATYPE_IPV4 => {
99 let mut skip = [0u8; 4 + 2]; stream.read_exact(&mut skip).await?;
101 }
102 ATYPE_DOMAIN => {
103 let mut len = [0u8; 1];
104 stream.read_exact(&mut len).await?;
105 let mut skip = vec![0u8; len[0] as usize + 2];
106 stream.read_exact(&mut skip).await?;
107 }
108 ATYPE_IPV6 => {
109 let mut skip = [0u8; 16 + 2];
110 stream.read_exact(&mut skip).await?;
111 }
112 atype => {
113 return Err(Error::Socks5(format!(
114 "unknown address type in reply: {atype:#x}"
115 )));
116 }
117 }
118
119 Ok(stream)
120 }
121}