mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-04-20 22:09:09 +00:00
socks5 stuff
This commit is contained in:
parent
6e81e78dfb
commit
a00f4b1a8b
1 changed files with 36 additions and 72 deletions
108
src/socks.rs
108
src/socks.rs
|
@ -6,7 +6,7 @@ use crate::{
|
|||
},
|
||||
};
|
||||
use smoltcp::wire::IpProtocol;
|
||||
use socks5_impl::protocol::{self, Address, UserKey};
|
||||
use socks5_impl::protocol::{self, handshake, password_method, Address, AuthMethod, UserKey};
|
||||
use std::{collections::VecDeque, net::SocketAddr, rc::Rc};
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
|
@ -28,36 +28,6 @@ pub enum SocksVersion {
|
|||
V5 = 5,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum SocksAuthentication {
|
||||
None = 0,
|
||||
GssApi = 1,
|
||||
Password = 2,
|
||||
ChallengeHandshake = 3,
|
||||
Unassigned = 4,
|
||||
Unassigned100 = 100,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum SocksReplies {
|
||||
Succeeded,
|
||||
GeneralFailure,
|
||||
ConnectionDisallowed,
|
||||
NetworkUnreachable,
|
||||
ConnectionRefused,
|
||||
TtlExpired,
|
||||
CommandUnsupported,
|
||||
AddressUnsupported,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SocksReplies {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SocksConnection {
|
||||
connection: Connection,
|
||||
state: SocksState,
|
||||
|
@ -129,24 +99,15 @@ impl SocksConnection {
|
|||
SocksVersion::V5 => {
|
||||
// Providing unassigned methods is supposed to bypass China's GFW.
|
||||
// For details, refer to https://github.com/blechschmidt/tun2proxy/issues/35.
|
||||
let mut methods = vec![
|
||||
AuthMethod::NoAuth,
|
||||
AuthMethod::from(4_u8),
|
||||
AuthMethod::from(100_u8),
|
||||
];
|
||||
if credentials.is_some() {
|
||||
self.server_outbuf.extend(&[
|
||||
self.version as u8,
|
||||
4u8,
|
||||
SocksAuthentication::None as u8,
|
||||
SocksAuthentication::Password as u8,
|
||||
SocksAuthentication::Unassigned as u8,
|
||||
SocksAuthentication::Unassigned100 as u8,
|
||||
]);
|
||||
} else {
|
||||
self.server_outbuf.extend(&[
|
||||
self.version as u8,
|
||||
3u8,
|
||||
SocksAuthentication::None as u8,
|
||||
SocksAuthentication::Unassigned as u8,
|
||||
SocksAuthentication::Unassigned100 as u8,
|
||||
]);
|
||||
methods.push(AuthMethod::UserPass);
|
||||
}
|
||||
handshake::Request::new(methods).write_to_stream(&mut self.server_outbuf)?;
|
||||
}
|
||||
}
|
||||
self.state = SocksState::ServerHello;
|
||||
|
@ -171,26 +132,26 @@ impl SocksConnection {
|
|||
}
|
||||
|
||||
fn receive_server_hello_socks5(&mut self) -> Result<(), Error> {
|
||||
if self.server_inbuf.len() < 2 {
|
||||
return Ok(());
|
||||
}
|
||||
if self.server_inbuf[0] != 5 {
|
||||
return Err("SOCKS5 server replied with an unexpected version.".into());
|
||||
let response = handshake::Response::rebuild_from_stream(&mut self.server_inbuf);
|
||||
if let Err(e) = &response {
|
||||
if e.kind() == std::io::ErrorKind::UnexpectedEof {
|
||||
log::trace!("receive_server_hello_socks5 need more data \"{}\"...", e);
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(e.to_string().into());
|
||||
}
|
||||
}
|
||||
let respones = response?;
|
||||
let auth_method = respones.method;
|
||||
|
||||
let auth_method = self.server_inbuf[1];
|
||||
|
||||
if auth_method != SocksAuthentication::None as u8 && self.credentials.is_none()
|
||||
|| (auth_method != SocksAuthentication::None as u8
|
||||
&& auth_method != SocksAuthentication::Password as u8)
|
||||
if auth_method != AuthMethod::NoAuth && self.credentials.is_none()
|
||||
|| (auth_method != AuthMethod::NoAuth && auth_method != AuthMethod::UserPass)
|
||||
&& self.credentials.is_some()
|
||||
{
|
||||
return Err("SOCKS5 server requires an unsupported authentication method.".into());
|
||||
}
|
||||
|
||||
self.server_inbuf.drain(0..2);
|
||||
|
||||
if auth_method == SocksAuthentication::Password as u8 {
|
||||
if auth_method == AuthMethod::UserPass {
|
||||
self.state = SocksState::SendAuthData;
|
||||
} else {
|
||||
self.state = SocksState::SendRequest;
|
||||
|
@ -208,24 +169,27 @@ impl SocksConnection {
|
|||
fn send_auth_data(&mut self) -> Result<(), Error> {
|
||||
let tmp = UserKey::default();
|
||||
let credentials = self.credentials.as_ref().unwrap_or(&tmp);
|
||||
self.server_outbuf
|
||||
.extend(&[1u8, credentials.username.len() as u8]);
|
||||
self.server_outbuf.extend(credentials.username.as_bytes());
|
||||
self.server_outbuf
|
||||
.extend(&[credentials.password.len() as u8]);
|
||||
self.server_outbuf.extend(credentials.password.as_bytes());
|
||||
let request = password_method::Request::new(&credentials.username, &credentials.password);
|
||||
request.write_to_stream(&mut self.server_outbuf)?;
|
||||
self.state = SocksState::ReceiveAuthResponse;
|
||||
self.state_change()
|
||||
}
|
||||
|
||||
fn receive_auth_data(&mut self) -> Result<(), Error> {
|
||||
if self.server_inbuf.len() < 2 {
|
||||
return Ok(());
|
||||
let response = password_method::Response::rebuild_from_stream(&mut self.server_inbuf);
|
||||
if let Err(e) = &response {
|
||||
if e.kind() == std::io::ErrorKind::UnexpectedEof {
|
||||
log::trace!("receive_auth_data need more data \"{}\"...", e);
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(e.to_string().into());
|
||||
}
|
||||
}
|
||||
if self.server_inbuf[0] != 1 || self.server_inbuf[1] != 0 {
|
||||
return Err("SOCKS authentication failed.".into());
|
||||
assert!(self.server_inbuf.is_empty());
|
||||
let response = response?;
|
||||
if response.status != password_method::Status::Succeeded {
|
||||
return Err(format!("SOCKS authentication failed: {:?}", response.status).into());
|
||||
}
|
||||
self.server_inbuf.drain(0..2);
|
||||
self.state = SocksState::SendRequest;
|
||||
self.state_change()
|
||||
}
|
||||
|
@ -234,7 +198,7 @@ impl SocksConnection {
|
|||
let response = protocol::Response::rebuild_from_stream(&mut self.server_inbuf);
|
||||
if let Err(e) = &response {
|
||||
if e.kind() == std::io::ErrorKind::UnexpectedEof {
|
||||
log::trace!("Waiting for more data \"{}\"...", e);
|
||||
log::trace!("receive_connection_status need more data \"{}\"...", e);
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(e.to_string().into());
|
||||
|
|
Loading…
Add table
Reference in a new issue