mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-06-07 23:27:46 +00:00
socks5 stuff
This commit is contained in:
parent
6e81e78dfb
commit
a00f4b1a8b
1 changed files with 36 additions and 72 deletions
102
src/socks.rs
102
src/socks.rs
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use smoltcp::wire::IpProtocol;
|
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};
|
use std::{collections::VecDeque, net::SocketAddr, rc::Rc};
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
|
@ -28,36 +28,6 @@ pub enum SocksVersion {
|
||||||
V5 = 5,
|
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 {
|
pub(crate) struct SocksConnection {
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
state: SocksState,
|
state: SocksState,
|
||||||
|
@ -129,24 +99,15 @@ impl SocksConnection {
|
||||||
SocksVersion::V5 => {
|
SocksVersion::V5 => {
|
||||||
// Providing unassigned methods is supposed to bypass China's GFW.
|
// Providing unassigned methods is supposed to bypass China's GFW.
|
||||||
// For details, refer to https://github.com/blechschmidt/tun2proxy/issues/35.
|
// 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() {
|
if credentials.is_some() {
|
||||||
self.server_outbuf.extend(&[
|
methods.push(AuthMethod::UserPass);
|
||||||
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,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
handshake::Request::new(methods).write_to_stream(&mut self.server_outbuf)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.state = SocksState::ServerHello;
|
self.state = SocksState::ServerHello;
|
||||||
|
@ -171,26 +132,26 @@ impl SocksConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_server_hello_socks5(&mut self) -> Result<(), Error> {
|
fn receive_server_hello_socks5(&mut self) -> Result<(), Error> {
|
||||||
if self.server_inbuf.len() < 2 {
|
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(());
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
return Err(e.to_string().into());
|
||||||
}
|
}
|
||||||
if self.server_inbuf[0] != 5 {
|
|
||||||
return Err("SOCKS5 server replied with an unexpected version.".into());
|
|
||||||
}
|
}
|
||||||
|
let respones = response?;
|
||||||
|
let auth_method = respones.method;
|
||||||
|
|
||||||
let auth_method = self.server_inbuf[1];
|
if auth_method != AuthMethod::NoAuth && self.credentials.is_none()
|
||||||
|
|| (auth_method != AuthMethod::NoAuth && auth_method != AuthMethod::UserPass)
|
||||||
if auth_method != SocksAuthentication::None as u8 && self.credentials.is_none()
|
|
||||||
|| (auth_method != SocksAuthentication::None as u8
|
|
||||||
&& auth_method != SocksAuthentication::Password as u8)
|
|
||||||
&& self.credentials.is_some()
|
&& self.credentials.is_some()
|
||||||
{
|
{
|
||||||
return Err("SOCKS5 server requires an unsupported authentication method.".into());
|
return Err("SOCKS5 server requires an unsupported authentication method.".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.server_inbuf.drain(0..2);
|
if auth_method == AuthMethod::UserPass {
|
||||||
|
|
||||||
if auth_method == SocksAuthentication::Password as u8 {
|
|
||||||
self.state = SocksState::SendAuthData;
|
self.state = SocksState::SendAuthData;
|
||||||
} else {
|
} else {
|
||||||
self.state = SocksState::SendRequest;
|
self.state = SocksState::SendRequest;
|
||||||
|
@ -208,24 +169,27 @@ impl SocksConnection {
|
||||||
fn send_auth_data(&mut self) -> Result<(), Error> {
|
fn send_auth_data(&mut self) -> Result<(), Error> {
|
||||||
let tmp = UserKey::default();
|
let tmp = UserKey::default();
|
||||||
let credentials = self.credentials.as_ref().unwrap_or(&tmp);
|
let credentials = self.credentials.as_ref().unwrap_or(&tmp);
|
||||||
self.server_outbuf
|
let request = password_method::Request::new(&credentials.username, &credentials.password);
|
||||||
.extend(&[1u8, credentials.username.len() as u8]);
|
request.write_to_stream(&mut self.server_outbuf)?;
|
||||||
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());
|
|
||||||
self.state = SocksState::ReceiveAuthResponse;
|
self.state = SocksState::ReceiveAuthResponse;
|
||||||
self.state_change()
|
self.state_change()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_auth_data(&mut self) -> Result<(), Error> {
|
fn receive_auth_data(&mut self) -> Result<(), Error> {
|
||||||
if self.server_inbuf.len() < 2 {
|
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(());
|
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());
|
|
||||||
}
|
}
|
||||||
self.server_inbuf.drain(0..2);
|
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.state = SocksState::SendRequest;
|
self.state = SocksState::SendRequest;
|
||||||
self.state_change()
|
self.state_change()
|
||||||
}
|
}
|
||||||
|
@ -234,7 +198,7 @@ impl SocksConnection {
|
||||||
let response = protocol::Response::rebuild_from_stream(&mut self.server_inbuf);
|
let response = protocol::Response::rebuild_from_stream(&mut self.server_inbuf);
|
||||||
if let Err(e) = &response {
|
if let Err(e) = &response {
|
||||||
if e.kind() == std::io::ErrorKind::UnexpectedEof {
|
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(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
return Err(e.to_string().into());
|
return Err(e.to_string().into());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue