Skip to content

Commit 5e9d20e

Browse files
committed
SOCKS 4/5 connectors
1 parent e74ab78 commit 5e9d20e

File tree

9 files changed

+1430
-3
lines changed

9 files changed

+1430
-3
lines changed
+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Proxy helpers
2-
2+
mod socks;
33
mod tunnel;
44

5+
pub use self::socks::{SocksV4, SocksV5};
56
pub use self::tunnel::Tunnel;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
mod v5;
2+
pub use v5::{SocksV5, SocksV5Error};
3+
4+
mod v4;
5+
pub use v4::{SocksV4, SocksV4Error};
6+
7+
use hyper::rt::Read;
8+
9+
#[derive(Debug)]
10+
pub enum SocksError<C> {
11+
Inner(C),
12+
Io(std::io::Error),
13+
14+
DnsFailure,
15+
MissingHost,
16+
MissingPort,
17+
18+
V4(SocksV4Error),
19+
V5(SocksV5Error),
20+
21+
Parsing(ParsingError),
22+
Serialize(SerializeError),
23+
}
24+
25+
#[derive(Debug)]
26+
pub enum ParsingError {
27+
Incomplete,
28+
Other,
29+
}
30+
31+
#[derive(Debug)]
32+
pub enum SerializeError {
33+
WouldOverflow,
34+
}
35+
36+
async fn read_message<T, M, C>(mut conn: &mut T, buf: &mut [u8]) -> Result<M, SocksError<C>>
37+
where
38+
T: Read + Unpin,
39+
M: for<'a> TryFrom<&'a [u8], Error = ParsingError>,
40+
{
41+
let mut n = 0;
42+
loop {
43+
let read = crate::rt::read(&mut conn, buf).await?;
44+
45+
if read == 0 {
46+
return Err(
47+
std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "unexpected eof").into(),
48+
);
49+
}
50+
51+
n += read;
52+
match M::try_from(&buf[..n]) {
53+
Err(ParsingError::Incomplete) => continue,
54+
Err(err) => return Err(err.into()),
55+
Ok(res) => return Ok(res),
56+
}
57+
}
58+
}
59+
60+
impl<C> From<std::io::Error> for SocksError<C> {
61+
fn from(err: std::io::Error) -> Self {
62+
Self::Io(err)
63+
}
64+
}
65+
66+
impl<C> From<ParsingError> for SocksError<C> {
67+
fn from(err: ParsingError) -> Self {
68+
Self::Parsing(err)
69+
}
70+
}
71+
72+
impl<C> From<SerializeError> for SocksError<C> {
73+
fn from(err: SerializeError) -> Self {
74+
Self::Serialize(err)
75+
}
76+
}
77+
78+
impl<C> From<SocksV4Error> for SocksError<C> {
79+
fn from(err: SocksV4Error) -> Self {
80+
Self::V4(err)
81+
}
82+
}
83+
84+
impl<C> From<SocksV5Error> for SocksError<C> {
85+
fn from(err: SocksV5Error) -> Self {
86+
Self::V5(err)
87+
}
88+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use super::Status;
2+
3+
#[derive(Debug)]
4+
pub enum SocksV4Error {
5+
IpV6,
6+
Command(Status),
7+
}
8+
9+
impl From<Status> for SocksV4Error {
10+
fn from(err: Status) -> Self {
11+
Self::Command(err)
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use super::super::{ParsingError, SerializeError};
2+
3+
use bytes::{Buf, BufMut};
4+
use std::net::SocketAddrV4;
5+
6+
/// +-----+-----+----+----+----+----+----+----+-------------+------+------------+------+
7+
/// | VN | CD | DSTPORT | DSTIP | USERID | NULL | DOMAIN | NULL |
8+
/// +-----+-----+----+----+----+----+----+----+-------------+------+------------+------+
9+
/// | 1 | 1 | 2 | 4 | Variable | 1 | Variable | 1 |
10+
/// +-----+-----+----+----+----+----+----+----+-------------+------+------------+------+
11+
/// ^^^^^^^^^^^^^^^^^^^^^
12+
/// optional: only do IP is 0.0.0.X
13+
#[derive(Debug)]
14+
pub struct Request<'a>(pub &'a Address);
15+
16+
/// +-----+-----+----+----+----+----+----+----+
17+
/// | VN | CD | DSTPORT | DSTIP |
18+
/// +-----+-----+----+----+----+----+----+----+
19+
/// | 1 | 1 | 2 | 4 |
20+
/// +-----+-----+----+----+----+----+----+----+
21+
/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22+
/// ignore: only for SOCKSv4 BIND
23+
#[derive(Debug)]
24+
pub struct Response(pub Status);
25+
26+
#[derive(Debug)]
27+
pub enum Address {
28+
Socket(SocketAddrV4),
29+
Domain(String, u16),
30+
}
31+
32+
#[derive(Debug, PartialEq)]
33+
pub enum Status {
34+
Success = 90,
35+
Failed = 91,
36+
IdentFailure = 92,
37+
IdentMismatch = 93,
38+
}
39+
40+
impl Request<'_> {
41+
pub fn write_to_buf<B: BufMut>(&self, mut buf: B) -> Result<usize, SerializeError> {
42+
match self.0 {
43+
Address::Socket(socket) => {
44+
if buf.remaining_mut() < 10 {
45+
return Err(SerializeError::WouldOverflow);
46+
}
47+
48+
buf.put_u8(0x04); // Version
49+
buf.put_u8(0x01); // CONNECT
50+
51+
buf.put_u16(socket.port()); // Port
52+
buf.put_slice(&socket.ip().octets()); // IP
53+
54+
buf.put_u8(0x00); // USERID
55+
buf.put_u8(0x00); // NULL
56+
57+
Ok(10)
58+
}
59+
60+
Address::Domain(domain, port) => {
61+
if buf.remaining_mut() < 10 + domain.len() + 1 {
62+
return Err(SerializeError::WouldOverflow);
63+
}
64+
65+
buf.put_u8(0x04); // Version
66+
buf.put_u8(0x01); // CONNECT
67+
68+
buf.put_u16(*port); // IP
69+
buf.put_slice(&[0x00, 0x00, 0x00, 0xFF]); // Invalid IP
70+
71+
buf.put_u8(0x00); // USERID
72+
buf.put_u8(0x00); // NULL
73+
74+
buf.put_slice(domain.as_bytes()); // Domain
75+
buf.put_u8(0x00); // NULL
76+
77+
Ok(10 + domain.len() + 1)
78+
}
79+
}
80+
}
81+
}
82+
83+
impl TryFrom<&[u8]> for Response {
84+
type Error = ParsingError;
85+
86+
fn try_from(mut buf: &[u8]) -> Result<Self, Self::Error> {
87+
println!("===");
88+
println!("{buf:?}");
89+
println!("===");
90+
91+
if buf.remaining() < 8 {
92+
return Err(ParsingError::Incomplete);
93+
}
94+
95+
if buf.get_u8() != 0x04 {
96+
return Err(ParsingError::Other);
97+
}
98+
99+
let status = buf.get_u8().try_into()?;
100+
101+
let _addr = {
102+
let port = buf.get_u16();
103+
let mut ip = [0; 4];
104+
buf.copy_to_slice(&mut ip);
105+
106+
SocketAddrV4::new(ip.into(), port)
107+
};
108+
109+
return Ok(Self(status));
110+
}
111+
}
112+
113+
impl TryFrom<u8> for Status {
114+
type Error = ParsingError;
115+
116+
fn try_from(byte: u8) -> Result<Self, Self::Error> {
117+
Ok(match byte {
118+
90 => Self::Success,
119+
91 => Self::Failed,
120+
92 => Self::IdentFailure,
121+
93 => Self::IdentMismatch,
122+
_ => return Err(ParsingError::Other),
123+
})
124+
}
125+
}

0 commit comments

Comments
 (0)