2022-08-01 14:36:58 +00:00
|
|
|
use crate::tun2proxy::{
|
|
|
|
Connection, ConnectionManager, IncomingDataEvent, IncomingDirection, OutgoingDataEvent,
|
|
|
|
OutgoingDirection, ProxyError, TcpProxy,
|
|
|
|
};
|
2021-09-02 11:30:23 +02:00
|
|
|
use std::collections::VecDeque;
|
|
|
|
use std::net::{IpAddr, SocketAddr};
|
|
|
|
|
|
|
|
#[derive(Eq, PartialEq, Debug)]
|
|
|
|
#[allow(dead_code)]
|
|
|
|
enum SocksState {
|
|
|
|
ClientHello,
|
|
|
|
ServerHello,
|
|
|
|
SendRequest,
|
|
|
|
ReceiveResponse,
|
2022-08-01 14:36:58 +00:00
|
|
|
Established,
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
#[repr(u8)]
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
enum SocksAddressType {
|
|
|
|
Ipv4 = 1,
|
|
|
|
DomainName = 3,
|
2022-08-01 14:36:58 +00:00
|
|
|
Ipv6 = 4,
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
#[repr(u8)]
|
|
|
|
enum SocksAuthentication {
|
|
|
|
None = 0,
|
2022-08-01 14:36:58 +00:00
|
|
|
Password = 2,
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
2021-09-02 21:02:17 +02:00
|
|
|
#[allow(dead_code)]
|
|
|
|
#[repr(u8)]
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
|
|
enum SocksReplies {
|
|
|
|
Succeeded,
|
|
|
|
GeneralFailure,
|
|
|
|
ConnectionDisallowed,
|
|
|
|
NetworkUnreachable,
|
|
|
|
ConnectionRefused,
|
|
|
|
TtlExpired,
|
|
|
|
CommandUnsupported,
|
2022-08-01 14:36:58 +00:00
|
|
|
AddressUnsupported,
|
2021-09-02 21:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Display for SocksReplies {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
write!(f, "{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-02 11:30:23 +02:00
|
|
|
pub struct SocksConnection {
|
|
|
|
connection: Connection,
|
|
|
|
state: SocksState,
|
|
|
|
client_inbuf: VecDeque<u8>,
|
|
|
|
server_inbuf: VecDeque<u8>,
|
|
|
|
client_outbuf: VecDeque<u8>,
|
|
|
|
server_outbuf: VecDeque<u8>,
|
|
|
|
data_buf: VecDeque<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SocksConnection {
|
|
|
|
pub fn new(connection: &Connection) -> Self {
|
|
|
|
let mut result = Self {
|
|
|
|
connection: *connection,
|
|
|
|
state: SocksState::ServerHello,
|
|
|
|
client_inbuf: Default::default(),
|
|
|
|
server_inbuf: Default::default(),
|
|
|
|
client_outbuf: Default::default(),
|
|
|
|
server_outbuf: Default::default(),
|
|
|
|
data_buf: Default::default(),
|
|
|
|
};
|
|
|
|
result.server_outbuf.extend(&[5u8, 1, 0]);
|
|
|
|
result.state = SocksState::ServerHello;
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
2021-09-02 21:02:17 +02:00
|
|
|
pub fn state_change(&mut self) -> Result<(), ProxyError> {
|
2021-09-02 11:30:23 +02:00
|
|
|
let dst_ip = self.connection.dst.ip();
|
|
|
|
|
|
|
|
match self.state {
|
2021-09-02 21:02:17 +02:00
|
|
|
SocksState::ServerHello if self.server_inbuf.len() >= 2 => {
|
|
|
|
if self.server_inbuf[0] != 5 {
|
|
|
|
return Err(ProxyError::new(
|
2022-08-01 14:36:58 +00:00
|
|
|
"SOCKS server replied with an unexpected version.".into(),
|
|
|
|
));
|
2021-09-02 21:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if self.server_inbuf[1] != 0 {
|
|
|
|
return Err(ProxyError::new(
|
2022-08-01 14:36:58 +00:00
|
|
|
"SOCKS server requires an unsupported authentication method.".into(),
|
|
|
|
));
|
2021-09-02 21:02:17 +02:00
|
|
|
}
|
|
|
|
|
2021-09-02 11:30:23 +02:00
|
|
|
self.server_inbuf.drain(0..2);
|
|
|
|
|
|
|
|
let cmd = if dst_ip.is_ipv4() { 1 } else { 4 };
|
|
|
|
self.server_outbuf.extend(&[5u8, 1, 0, cmd]);
|
|
|
|
match dst_ip {
|
|
|
|
IpAddr::V4(ip) => self.server_outbuf.extend(ip.octets().as_ref()),
|
|
|
|
IpAddr::V6(ip) => self.server_outbuf.extend(ip.octets().as_ref()),
|
|
|
|
};
|
|
|
|
self.server_outbuf.extend(&[
|
|
|
|
(self.connection.dst.port() >> 8) as u8,
|
2022-08-01 14:36:58 +00:00
|
|
|
(self.connection.dst.port() & 0xff) as u8,
|
2021-09-02 11:30:23 +02:00
|
|
|
]);
|
|
|
|
|
|
|
|
self.state = SocksState::ReceiveResponse;
|
2021-09-02 21:02:17 +02:00
|
|
|
return self.state_change();
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SocksState::ReceiveResponse if self.server_inbuf.len() >= 4 => {
|
2021-09-02 21:02:17 +02:00
|
|
|
let ver = self.server_inbuf[0];
|
|
|
|
let rep = self.server_inbuf[1];
|
2021-09-02 11:30:23 +02:00
|
|
|
let _rsv = self.server_inbuf[2];
|
|
|
|
let atyp = self.server_inbuf[3];
|
|
|
|
|
2021-09-02 21:02:17 +02:00
|
|
|
if ver != 5 {
|
2022-08-01 14:36:58 +00:00
|
|
|
return Err(ProxyError::new(
|
|
|
|
"SOCKS server replied with an unexpected version.".into(),
|
|
|
|
));
|
2021-09-02 21:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if rep != 0 {
|
|
|
|
return Err(ProxyError::new("SOCKS connection unsuccessful.".into()));
|
|
|
|
}
|
|
|
|
|
2021-09-02 11:30:23 +02:00
|
|
|
if atyp != SocksAddressType::Ipv4 as u8
|
|
|
|
&& atyp != SocksAddressType::Ipv6 as u8
|
2022-08-01 14:36:58 +00:00
|
|
|
&& atyp != SocksAddressType::DomainName as u8
|
|
|
|
{
|
|
|
|
return Err(ProxyError::new(
|
|
|
|
"SOCKS server replied with unrecognized address type.".into(),
|
|
|
|
));
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if atyp == SocksAddressType::DomainName as u8 && self.server_inbuf.len() < 5 {
|
2021-09-02 21:02:17 +02:00
|
|
|
return Ok(());
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if atyp == SocksAddressType::DomainName as u8
|
2022-08-01 14:36:58 +00:00
|
|
|
&& self.server_inbuf.len() < 7 + (self.server_inbuf[4] as usize)
|
|
|
|
{
|
2021-09-02 21:02:17 +02:00
|
|
|
return Ok(());
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
let message_length = if atyp == SocksAddressType::Ipv4 as u8 {
|
|
|
|
10
|
|
|
|
} else if atyp == SocksAddressType::Ipv6 as u8 {
|
|
|
|
22
|
|
|
|
} else {
|
|
|
|
7 + (self.server_inbuf[4] as usize)
|
|
|
|
};
|
|
|
|
|
|
|
|
self.server_inbuf.drain(0..message_length);
|
|
|
|
self.server_outbuf.append(&mut self.data_buf);
|
|
|
|
self.data_buf.clear();
|
|
|
|
|
|
|
|
self.state = SocksState::Established;
|
2021-09-02 21:02:17 +02:00
|
|
|
return self.state_change();
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SocksState::Established => {
|
2021-09-02 21:02:17 +02:00
|
|
|
self.client_outbuf.extend(self.server_inbuf.iter());
|
|
|
|
self.server_outbuf.extend(self.client_inbuf.iter());
|
|
|
|
self.server_inbuf.clear();
|
|
|
|
self.client_inbuf.clear();
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_ => {}
|
|
|
|
}
|
2021-09-02 21:02:17 +02:00
|
|
|
Ok(())
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TcpProxy for SocksConnection {
|
2021-09-02 21:02:17 +02:00
|
|
|
fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), ProxyError> {
|
2021-09-02 11:30:23 +02:00
|
|
|
let direction = event.direction;
|
|
|
|
let buffer = event.buffer;
|
|
|
|
match direction {
|
|
|
|
IncomingDirection::FromServer => {
|
|
|
|
self.server_inbuf.extend(buffer.iter());
|
2022-08-01 14:36:58 +00:00
|
|
|
}
|
2021-09-02 11:30:23 +02:00
|
|
|
IncomingDirection::FromClient => {
|
|
|
|
if self.state == SocksState::Established {
|
|
|
|
self.client_inbuf.extend(buffer.iter());
|
|
|
|
} else {
|
|
|
|
self.data_buf.extend(buffer.iter());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-02 21:02:17 +02:00
|
|
|
self.state_change()
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn consume_data(&mut self, dir: OutgoingDirection, size: usize) {
|
2022-08-01 14:36:58 +00:00
|
|
|
let buffer = if dir == OutgoingDirection::ToServer {
|
2021-09-02 11:30:23 +02:00
|
|
|
&mut self.server_outbuf
|
|
|
|
} else {
|
|
|
|
&mut self.client_outbuf
|
|
|
|
};
|
|
|
|
buffer.drain(0..size);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn peek_data(&mut self, dir: OutgoingDirection) -> OutgoingDataEvent {
|
|
|
|
let buffer = if dir == OutgoingDirection::ToServer {
|
|
|
|
&mut self.server_outbuf
|
|
|
|
} else {
|
|
|
|
&mut self.client_outbuf
|
|
|
|
};
|
2022-08-01 14:36:58 +00:00
|
|
|
OutgoingDataEvent {
|
2021-09-02 11:30:23 +02:00
|
|
|
direction: dir,
|
2022-08-01 14:36:58 +00:00
|
|
|
buffer: buffer.make_contiguous(),
|
|
|
|
}
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
2021-09-02 21:02:17 +02:00
|
|
|
|
|
|
|
fn connection_established(&self) -> bool {
|
2022-08-01 14:36:58 +00:00
|
|
|
self.state == SocksState::Established
|
2021-09-02 21:02:17 +02:00
|
|
|
}
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Socks5Manager {
|
|
|
|
server: std::net::SocketAddr,
|
|
|
|
authentication: SocksAuthentication,
|
|
|
|
username: Vec<u8>,
|
|
|
|
password: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ConnectionManager for Socks5Manager {
|
|
|
|
fn handles_connection(&self, connection: &Connection) -> bool {
|
|
|
|
connection.proto == smoltcp::wire::IpProtocol::Tcp.into()
|
|
|
|
}
|
|
|
|
|
2023-03-21 01:08:44 +01:00
|
|
|
fn new_connection(&self, connection: &Connection) -> Option<std::boxed::Box<dyn TcpProxy>> {
|
2021-09-02 11:30:23 +02:00
|
|
|
if connection.proto != smoltcp::wire::IpProtocol::Tcp.into() {
|
|
|
|
return None;
|
|
|
|
}
|
2022-08-01 14:36:58 +00:00
|
|
|
Some(std::boxed::Box::new(SocksConnection::new(connection)))
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
2023-03-21 01:08:44 +01:00
|
|
|
fn close_connection(&self, _: &Connection) {}
|
2021-09-02 11:30:23 +02:00
|
|
|
|
|
|
|
fn get_server(&self) -> SocketAddr {
|
|
|
|
self.server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Socks5Manager {
|
|
|
|
pub fn new(server: SocketAddr) -> Self {
|
|
|
|
Self {
|
|
|
|
server,
|
|
|
|
authentication: SocksAuthentication::None,
|
|
|
|
username: Default::default(),
|
2022-08-01 14:36:58 +00:00
|
|
|
password: Default::default(),
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn set_credentials(&mut self, username: &[u8], password: &[u8]) {
|
|
|
|
assert!(username.len() <= 255 && password.len() <= 255);
|
|
|
|
self.authentication = SocksAuthentication::Password;
|
|
|
|
self.username = Vec::from(username);
|
|
|
|
self.password = Vec::from(password);
|
|
|
|
}
|
2022-08-01 14:36:58 +00:00
|
|
|
}
|