shadowsocks_service/local/socks/
socks4.rs1#![allow(dead_code)]
6
7use std::{
8 fmt,
9 io::{self, ErrorKind},
10 net::{Ipv4Addr, SocketAddr, SocketAddrV4},
11};
12
13use byteorder::{BigEndian, ByteOrder};
14use bytes::{BufMut, BytesMut};
15use thiserror::Error;
16use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
17
18use shadowsocks::relay::socks5;
19
20#[rustfmt::skip]
21mod consts {
22 pub const SOCKS4_VERSION: u8 = 4;
23
24 pub const SOCKS4_COMMAND_CONNECT: u8 = 1;
25 pub const SOCKS4_COMMAND_BIND: u8 = 2;
26
27 pub const SOCKS4_RESULT_REQUEST_GRANTED: u8 = 90;
28 pub const SOCKS4_RESULT_REQUEST_REJECTED_OR_FAILED: u8 = 91;
29 pub const SOCKS4_RESULT_REQUEST_REJECTED_CANNOT_CONNECT: u8 = 92;
30 pub const SOCKS4_RESULT_REQUEST_REJECTED_DIFFERENT_USER_ID: u8 = 93;
31}
32
33#[derive(Clone, Debug, Copy)]
35pub enum Command {
36 Connect,
38 Bind,
40}
41
42impl Command {
43 #[inline]
44 fn as_u8(self) -> u8 {
45 match self {
46 Self::Connect => consts::SOCKS4_COMMAND_CONNECT,
47 Self::Bind => consts::SOCKS4_COMMAND_BIND,
48 }
49 }
50
51 #[inline]
52 fn from_u8(code: u8) -> Option<Self> {
53 match code {
54 consts::SOCKS4_COMMAND_CONNECT => Some(Self::Connect),
55 consts::SOCKS4_COMMAND_BIND => Some(Self::Bind),
56 _ => None,
57 }
58 }
59}
60
61#[derive(Clone, Debug, Copy, Eq, PartialEq)]
63pub enum ResultCode {
64 RequestGranted,
66 RequestRejectedOrFailed,
68 RequestRejectedCannotConnect,
70 RequestRejectedDifferentUserId,
72 Other(u8),
74}
75
76impl ResultCode {
77 #[inline]
78 fn as_u8(self) -> u8 {
79 match self {
80 Self::RequestGranted => consts::SOCKS4_RESULT_REQUEST_GRANTED,
81 Self::RequestRejectedOrFailed => consts::SOCKS4_RESULT_REQUEST_REJECTED_OR_FAILED,
82 Self::RequestRejectedCannotConnect => consts::SOCKS4_RESULT_REQUEST_REJECTED_CANNOT_CONNECT,
83 Self::RequestRejectedDifferentUserId => consts::SOCKS4_RESULT_REQUEST_REJECTED_DIFFERENT_USER_ID,
84 Self::Other(c) => c,
85 }
86 }
87
88 #[inline]
89 fn from_u8(code: u8) -> Self {
90 match code {
91 consts::SOCKS4_RESULT_REQUEST_GRANTED => Self::RequestGranted,
92 consts::SOCKS4_RESULT_REQUEST_REJECTED_OR_FAILED => Self::RequestRejectedOrFailed,
93 consts::SOCKS4_RESULT_REQUEST_REJECTED_CANNOT_CONNECT => Self::RequestRejectedCannotConnect,
94 consts::SOCKS4_RESULT_REQUEST_REJECTED_DIFFERENT_USER_ID => Self::RequestRejectedDifferentUserId,
95 code => Self::Other(code),
96 }
97 }
98}
99
100impl fmt::Display for ResultCode {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 match *self {
103 Self::RequestGranted => f.write_str("request granted"),
104 Self::RequestRejectedOrFailed => f.write_str("request rejected or failed"),
105 Self::RequestRejectedCannotConnect => {
106 f.write_str("request rejected because SOCKS server cannot connect to identd on the client")
107 }
108 Self::RequestRejectedDifferentUserId => {
109 f.write_str("request rejected because the client program and identd report different user-ids")
110 }
111 Self::Other(code) => write!(f, "other result code {code}"),
112 }
113 }
114}
115
116#[derive(Clone, PartialEq, Eq, Hash)]
118pub enum Address {
119 SocketAddress(SocketAddrV4),
121 DomainNameAddress(String, u16),
123}
124
125impl fmt::Debug for Address {
126 #[inline]
127 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
128 match *self {
129 Self::SocketAddress(ref addr) => write!(f, "{addr}"),
130 Self::DomainNameAddress(ref addr, ref port) => write!(f, "{addr}:{port}"),
131 }
132 }
133}
134
135impl fmt::Display for Address {
136 #[inline]
137 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 match *self {
139 Self::SocketAddress(ref addr) => write!(f, "{addr}"),
140 Self::DomainNameAddress(ref addr, ref port) => write!(f, "{addr}:{port}"),
141 }
142 }
143}
144
145impl From<SocketAddrV4> for Address {
146 fn from(s: SocketAddrV4) -> Self {
147 Self::SocketAddress(s)
148 }
149}
150
151impl From<(String, u16)> for Address {
152 fn from((dn, port): (String, u16)) -> Self {
153 Self::DomainNameAddress(dn, port)
154 }
155}
156
157impl From<(&str, u16)> for Address {
158 fn from((dn, port): (&str, u16)) -> Self {
159 Self::DomainNameAddress(dn.to_owned(), port)
160 }
161}
162
163impl From<&Self> for Address {
164 fn from(addr: &Self) -> Self {
165 addr.clone()
166 }
167}
168
169impl From<Address> for socks5::Address {
170 fn from(addr: Address) -> Self {
171 match addr {
172 Address::SocketAddress(a) => Self::SocketAddress(SocketAddr::V4(a)),
173 Address::DomainNameAddress(d, p) => Self::DomainNameAddress(d, p),
174 }
175 }
176}
177
178#[derive(Debug, Clone)]
196pub struct HandshakeRequest {
197 pub cd: Command,
198 pub dst: Address,
199 pub user_id: Vec<u8>,
200}
201
202impl HandshakeRequest {
203 pub async fn read_from<R>(r: &mut R) -> Result<Self, Error>
205 where
206 R: AsyncBufRead + Unpin,
207 {
208 let mut buf = [0u8; 8];
209 let _ = r.read_exact(&mut buf).await?;
210
211 let vn = buf[0];
212 if vn != consts::SOCKS4_VERSION {
213 return Err(Error::UnsupportedSocksVersion(vn));
214 }
215
216 let cd = buf[1];
217 let command = match Command::from_u8(cd) {
218 Some(c) => c,
219 None => {
220 return Err(Error::UnsupportedSocksVersion(cd));
221 }
222 };
223
224 let port = BigEndian::read_u16(&buf[2..4]);
225
226 let mut user_id = Vec::new();
227 let _ = r.read_until(b'\0', &mut user_id).await?;
228 if user_id.is_empty() || user_id.last() != Some(&b'\0') {
229 return Err(io::Error::from(ErrorKind::UnexpectedEof).into());
230 }
231 user_id.pop(); let dst = if buf[4] == 0x00 && buf[5] == 0x00 && buf[6] == 0x00 && buf[7] != 0x00 {
234 let mut host = Vec::new();
236 let _ = r.read_until(b'\0', &mut host).await?;
237 if host.is_empty() || host.last() != Some(&b'\0') {
238 return Err(io::Error::from(ErrorKind::UnexpectedEof).into());
239 }
240 host.pop(); match String::from_utf8(host) {
243 Ok(host) => Address::DomainNameAddress(host, port),
244 Err(..) => {
245 return Err(Error::AddressHostInvalidEncoding);
246 }
247 }
248 } else {
249 let ip = Ipv4Addr::new(buf[4], buf[5], buf[6], buf[7]);
250 Address::SocketAddress(SocketAddrV4::new(ip, port))
251 };
252
253 Ok(Self {
254 cd: command,
255 dst,
256 user_id,
257 })
258 }
259
260 pub async fn write_to<W>(&self, w: &mut W) -> io::Result<()>
262 where
263 W: AsyncWrite + Unpin,
264 {
265 let mut buf = BytesMut::with_capacity(self.serialized_len());
266 self.write_to_buf(&mut buf);
267 w.write_all(&buf).await
268 }
269
270 pub fn write_to_buf<B: BufMut>(&self, buf: &mut B) {
272 debug_assert!(
273 !self.user_id.contains(&b'\0'),
274 "USERID shouldn't contain any NULL characters"
275 );
276
277 buf.put_u8(consts::SOCKS4_VERSION);
278 buf.put_u8(self.cd.as_u8());
279 match self.dst {
280 Address::SocketAddress(ref saddr) => {
281 let port = saddr.port();
282 buf.put_u16(port);
283 buf.put_slice(&saddr.ip().octets());
284
285 buf.put_slice(&self.user_id);
286 buf.put_u8(b'\0');
287 }
288 Address::DomainNameAddress(ref dname, port) => {
289 buf.put_u16(port);
290
291 const PLACEHOLDER: [u8; 4] = [0x00, 0x00, 0x00, 0xff];
293 buf.put_slice(&PLACEHOLDER);
294
295 buf.put_slice(&self.user_id);
296 buf.put_u8(b'\0');
297
298 buf.put_slice(dname.as_bytes());
299 buf.put_u8(b'\0');
300 }
301 }
302 }
303
304 #[inline]
306 pub fn serialized_len(&self) -> usize {
307 let mut s = 1 + 1 + 2 + 4 + self.user_id.len() + 1; if let Address::DomainNameAddress(ref dname, _) = self.dst {
309 s += dname.len() + 1;
310 }
311 s
312 }
313}
314
315#[derive(Debug, Clone)]
324pub struct HandshakeResponse {
325 pub cd: ResultCode,
326}
327
328impl HandshakeResponse {
329 pub fn new(code: ResultCode) -> Self {
331 Self { cd: code }
332 }
333
334 pub async fn read_from<R>(r: &mut R) -> Result<Self, Error>
336 where
337 R: AsyncRead + Unpin,
338 {
339 let mut buf = [0u8; 8];
340 let _ = r.read_exact(&mut buf).await?;
341
342 let vn = buf[0];
343 if vn != 0 {
344 return Err(Error::UnsupportedSocksVersion(vn));
345 }
346
347 let cd = buf[1];
348 let result_code = ResultCode::from_u8(cd);
349
350 Ok(Self { cd: result_code })
353 }
354
355 pub async fn write_to<W>(&self, w: &mut W) -> io::Result<()>
357 where
358 W: AsyncWrite + Unpin,
359 {
360 let mut buf = BytesMut::with_capacity(self.serialized_len());
361 self.write_to_buf(&mut buf);
362 w.write_all(&buf).await
363 }
364
365 pub fn write_to_buf<B: BufMut>(&self, buf: &mut B) {
367 let Self { ref cd } = *self;
368
369 buf.put_slice(&[
370 0x00,
372 cd.as_u8(),
374 0x00,
376 0x00,
377 0x00,
379 0x00,
380 0x00,
381 0x00,
382 ]);
383 }
384
385 #[inline]
387 pub fn serialized_len(&self) -> usize {
388 1 + 1 + 2 + 4
389 }
390}
391
392#[derive(Error, Debug)]
394pub enum Error {
395 #[error("{0}")]
397 IoError(#[from] io::Error),
398 #[error("host must be UTF-8 encoding")]
399 AddressHostInvalidEncoding,
400 #[error("unsupported socks version {0:#x}")]
401 UnsupportedSocksVersion(u8),
402 #[error("unsupported command {0:#x}")]
403 UnsupportedCommand(u8),
404 #[error("{0}")]
405 Result(ResultCode),
406}
407
408impl From<Error> for io::Error {
409 fn from(err: Error) -> Self {
410 match err {
411 Error::IoError(err) => err,
412 e => Self::other(e),
413 }
414 }
415}