darkfi/net/transport/
socks5.rs1use std::{
20 fmt::Debug,
21 io,
22 net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
23};
24
25use futures::{AsyncReadExt, AsyncWriteExt};
26use smol::net::TcpStream;
27use tracing::debug;
28use url::Url;
29
30#[derive(Clone, Debug)]
32pub struct Socks5Dialer {
33 client: Socks5Client,
34 endpoint: AddrKind,
35}
36
37impl Socks5Dialer {
38 pub(crate) async fn new(uri: &Url) -> io::Result<Self> {
40 let mut dest = uri.path().strip_prefix("/").unwrap().split(':');
48
49 let Some(dest_host) = dest.next() else { return Err(io::ErrorKind::InvalidInput.into()) };
50 let Some(dest_port) = dest.next() else { return Err(io::ErrorKind::InvalidInput.into()) };
51
52 let dest_port: u16 = match dest_port.parse() {
53 Ok(v) => v,
54 Err(_) => return Err(io::ErrorKind::InvalidData.into()),
55 };
56
57 let client = Socks5Client::new(uri.host_str().unwrap(), uri.port().unwrap());
58 let endpoint: AddrKind = (dest_host, dest_port).into();
59
60 Ok(Self { client, endpoint })
61 }
62
63 pub(crate) async fn do_dial(&self) -> io::Result<TcpStream> {
65 debug!(
66 target: "net::socks5::do_dial",
67 "Dialing {:?} with SOCKS5...", self.endpoint,
68 );
69
70 self.client.connect(self.endpoint.clone()).await
71 }
72}
73
74#[derive(Clone, Debug)]
76pub struct Socks5Client {
77 host: String,
79 port: u16,
81}
82
83impl Socks5Client {
84 pub fn new(host: &str, port: u16) -> Self {
86 Self { host: String::from(host), port }
87 }
88
89 pub async fn connect(&self, addr: impl Into<AddrKind> + Debug) -> io::Result<TcpStream> {
91 let addr: AddrKind = addr.into();
92
93 let mut stream = TcpStream::connect(&format!("{}:{}", self.host, self.port)).await?;
95
96 stream.write_all(&[0x05, 0x01, 0x00]).await?;
99 stream.flush().await?;
100
101 let mut buf = [0u8; 2];
103 stream.read_exact(&mut buf).await?;
104
105 if buf[0] != 0x05 && buf[0] != 0x00 {
107 return Err(io::ErrorKind::ConnectionRefused.into())
108 }
109
110 let mut reqbuf = vec![0x05, 0x01, 0x00];
114
115 match addr {
116 AddrKind::Ip(socketaddr) => {
117 if socketaddr.is_ipv4() {
118 reqbuf.push(0x01);
120 } else {
121 reqbuf.push(0x04);
123 }
124 match socketaddr.ip() {
126 IpAddr::V4(ip) => reqbuf.extend_from_slice(&ip.octets()),
127 IpAddr::V6(ip) => reqbuf.extend_from_slice(&ip.octets()),
128 }
129 reqbuf.extend_from_slice(&socketaddr.port().to_be_bytes());
131 }
132 AddrKind::Domain(ref host, port) => {
133 reqbuf.push(0x03);
135 reqbuf.push(host.len() as u8);
137 reqbuf.extend_from_slice(host.as_bytes());
138 reqbuf.extend_from_slice(&port.to_be_bytes());
140 }
141 };
142
143 stream.write_all(&reqbuf).await?;
145 stream.flush().await?;
146 debug!(
147 target: "net::transport::socks5::connect",
148 "Flushed CONNECT({addr:?}) request"
149 );
150
151 let mut buf = [0u8];
153 stream.read_exact(&mut buf).await?;
154 debug!(
155 target: "net::transport::socks5::connect",
156 "REPLY - Version: {:#02x}", buf[0],
157 );
158
159 if buf[0] != 0x05 {
160 return Err(io::ErrorKind::ConnectionRefused.into())
161 }
162
163 buf[0] = 0x00;
164 stream.read_exact(&mut buf).await?;
165 debug!(
166 target: "net::transport::socks5::connect",
167 "REPLY - Reply: {:#02x}", buf[0],
168 );
169 match buf[0] {
170 0x00 => {}
171 0x01 => return Err(io::ErrorKind::ConnectionAborted.into()),
172 0x02 => return Err(io::ErrorKind::PermissionDenied.into()),
173 0x03 => return Err(io::ErrorKind::NetworkUnreachable.into()),
174 0x04 => return Err(io::ErrorKind::HostUnreachable.into()),
175 0x05 => return Err(io::ErrorKind::ConnectionRefused.into()),
176 0x06 => return Err(io::ErrorKind::TimedOut.into()),
177 0x07 => return Err(io::ErrorKind::Unsupported.into()),
178 0x08 => return Err(io::ErrorKind::Unsupported.into()),
179 _ => return Err(io::ErrorKind::ConnectionAborted.into()),
180 }
181
182 stream.read_exact(&mut buf).await?;
184
185 buf[0] = 0x00;
187 stream.read_exact(&mut buf).await?;
188 debug!(
189 target: "net::transport::socks5::connect",
190 "REPLY - ATYP: {:#02x}", buf[0],
191 );
192
193 match buf[0] {
195 0x01 => {
197 let mut buf = [0u8; 4];
198 stream.read_exact(&mut buf).await?;
199 debug!(
200 target: "net::transport::socks5::connect",
201 "REPLY - BND.ADDR: {}", Ipv4Addr::from(buf),
202 );
203 }
204 0x04 => {
206 let mut buf = [0u8; 16];
207 stream.read_exact(&mut buf).await?;
208 debug!(
209 target: "net::transport::socks5::connect",
210 "REPLY - BND.ADDR: {}", Ipv6Addr::from(buf),
211 );
212 }
213 0x03 => {
215 let mut len = [0u8];
216 stream.read_exact(&mut len).await?;
217 let mut buf = vec![0u8; len[0] as usize];
218 stream.read_exact(&mut buf).await?;
219 debug!(
220 target: "net::transport::socks5::connect",
221 "REPLY - BND.ADDR: {}", String::from_utf8_lossy(&buf),
222 );
223 }
224
225 _ => return Err(io::ErrorKind::ConnectionAborted.into()),
226 };
227
228 let mut buf = [0u8; 2];
230 stream.read_exact(&mut buf).await?;
231 debug!(
232 target: "net::transport::socks5::connect",
233 "REPLY - BND.PORT: {}", u16::from_be_bytes(buf),
234 );
235
236 Ok(stream)
237 }
238}
239
240#[derive(Clone, Debug)]
241pub enum AddrKind {
242 Ip(SocketAddr),
243 Domain(String, u16),
244}
245
246impl From<(IpAddr, u16)> for AddrKind {
247 fn from(value: (IpAddr, u16)) -> Self {
248 Self::Ip(value.into())
249 }
250}
251
252impl From<(Ipv4Addr, u16)> for AddrKind {
253 fn from(value: (Ipv4Addr, u16)) -> Self {
254 Self::Ip(value.into())
255 }
256}
257
258impl From<(Ipv6Addr, u16)> for AddrKind {
259 fn from(value: (Ipv6Addr, u16)) -> Self {
260 Self::Ip(value.into())
261 }
262}
263
264impl From<(String, u16)> for AddrKind {
265 fn from((domain, port): (String, u16)) -> Self {
266 Self::Domain(domain, port)
267 }
268}
269
270impl From<(&'_ str, u16)> for AddrKind {
271 fn from((domain, port): (&'_ str, u16)) -> Self {
272 Self::Domain(domain.to_owned(), port)
273 }
274}
275
276impl From<SocketAddr> for AddrKind {
277 fn from(value: SocketAddr) -> Self {
278 Self::Ip(value)
279 }
280}
281
282impl From<SocketAddrV4> for AddrKind {
283 fn from(value: SocketAddrV4) -> Self {
284 Self::Ip(value.into())
285 }
286}
287
288impl From<SocketAddrV6> for AddrKind {
289 fn from(value: SocketAddrV6) -> Self {
290 Self::Ip(value.into())
291 }
292}