mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-04-22 14:59:09 +00:00
Initial support digest auth scheme
This commit is contained in:
parent
6767076a6b
commit
86429ee8eb
6 changed files with 321 additions and 67 deletions
|
@ -23,6 +23,9 @@ prctl = "1.0"
|
||||||
smoltcp = { version = "0.9.1", git = "https://github.com/smoltcp-rs/smoltcp", features = ["std", "phy-tuntap_interface"] }
|
smoltcp = { version = "0.9.1", git = "https://github.com/smoltcp-rs/smoltcp", features = ["std", "phy-tuntap_interface"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
url = "2.3"
|
url = "2.3"
|
||||||
|
digest_auth = "0.3.1"
|
||||||
|
httparse = "1.8.0"
|
||||||
|
unicase = "2.6.0"
|
||||||
|
|
||||||
[target.'cfg(target_os="android")'.dependencies]
|
[target.'cfg(target_os="android")'.dependencies]
|
||||||
android_logger = "0.13"
|
android_logger = "0.13"
|
||||||
|
|
|
@ -48,6 +48,12 @@ pub enum Error {
|
||||||
|
|
||||||
#[error("std::num::ParseIntError {0:?}")]
|
#[error("std::num::ParseIntError {0:?}")]
|
||||||
IntParseError(#[from] std::num::ParseIntError),
|
IntParseError(#[from] std::num::ParseIntError),
|
||||||
|
|
||||||
|
#[error("httparse::Error {0}")]
|
||||||
|
HttpError(#[from] httparse::Error),
|
||||||
|
|
||||||
|
#[error("digest_auth::Error {0}")]
|
||||||
|
DigestAuthError(#[from] digest_auth::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for Error {
|
impl From<&str> for Error {
|
||||||
|
|
328
src/http.rs
328
src/http.rs
|
@ -1,24 +1,41 @@
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::tun2proxy::{
|
use crate::tun2proxy::{
|
||||||
Connection, ConnectionManager, Direction, IncomingDataEvent, IncomingDirection,
|
Connection, ConnectionManager, Destination, Direction, IncomingDataEvent, IncomingDirection,
|
||||||
OutgoingDataEvent, OutgoingDirection, TcpProxy,
|
OutgoingDataEvent, OutgoingDirection, TcpProxy,
|
||||||
};
|
};
|
||||||
use crate::Credentials;
|
use crate::Credentials;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
|
use httparse::Response;
|
||||||
use smoltcp::wire::IpProtocol;
|
use smoltcp::wire::IpProtocol;
|
||||||
use std::collections::VecDeque;
|
use std::cell::RefCell;
|
||||||
|
use std::collections::hash_map::RandomState;
|
||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
use std::iter::FromIterator;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::str;
|
||||||
|
use unicase::UniCase;
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum AuthenticationScheme {
|
||||||
|
None,
|
||||||
|
Basic,
|
||||||
|
Digest,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
enum HttpState {
|
enum HttpState {
|
||||||
SendRequest,
|
SendRequest,
|
||||||
ExpectStatusCode,
|
ExpectResponseHeaders,
|
||||||
ExpectResponse,
|
ExpectResponse,
|
||||||
|
Reset,
|
||||||
Established,
|
Established,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) type DigestState = digest_auth::WwwAuthenticateHeader;
|
||||||
|
|
||||||
pub struct HttpConnection {
|
pub struct HttpConnection {
|
||||||
state: HttpState,
|
state: HttpState,
|
||||||
client_inbuf: VecDeque<u8>,
|
client_inbuf: VecDeque<u8>,
|
||||||
|
@ -27,82 +44,264 @@ pub struct HttpConnection {
|
||||||
server_outbuf: VecDeque<u8>,
|
server_outbuf: VecDeque<u8>,
|
||||||
data_buf: VecDeque<u8>,
|
data_buf: VecDeque<u8>,
|
||||||
crlf_state: u8,
|
crlf_state: u8,
|
||||||
|
counter: usize,
|
||||||
|
skip: usize,
|
||||||
|
digest_state: Rc<RefCell<Option<DigestState>>>,
|
||||||
|
before: bool,
|
||||||
|
credentials: Option<Credentials>,
|
||||||
|
destination: Destination,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpConnection {
|
static PROXY_AUTHENTICATE: &str = "Proxy-Authenticate";
|
||||||
fn new(connection: &Connection, manager: Rc<dyn ConnectionManager>) -> Self {
|
static PROXY_AUTHORIZATION: &str = "Proxy-Authorization";
|
||||||
let mut server_outbuf: VecDeque<u8> = VecDeque::new();
|
static CONNECTION: &str = "Connection";
|
||||||
{
|
static TRANSFER_ENCODING: &str = "Transfer-Encoding";
|
||||||
let credentials = manager.get_credentials();
|
static CONTENT_LENGTH: &str = "Content-Length";
|
||||||
server_outbuf.extend(b"CONNECT ".iter());
|
|
||||||
server_outbuf.extend(connection.dst.to_string().as_bytes());
|
|
||||||
server_outbuf.extend(b" HTTP/1.1\r\nHost: ".iter());
|
|
||||||
server_outbuf.extend(connection.dst.to_string().as_bytes());
|
|
||||||
server_outbuf.extend(b"\r\n".iter());
|
|
||||||
if let Some(credentials) = credentials {
|
|
||||||
server_outbuf.extend(b"Proxy-Authorization: Basic ");
|
|
||||||
let mut auth_plain = credentials.username.clone();
|
|
||||||
auth_plain.extend(b":".iter());
|
|
||||||
auth_plain.extend(&credentials.password);
|
|
||||||
let auth_b64 = base64::engine::general_purpose::STANDARD.encode(auth_plain);
|
|
||||||
server_outbuf.extend(auth_b64.as_bytes().iter());
|
|
||||||
server_outbuf.extend(b"\r\n".iter());
|
|
||||||
}
|
|
||||||
server_outbuf.extend(b"\r\n".iter());
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
impl HttpConnection {
|
||||||
state: HttpState::ExpectStatusCode,
|
fn new(
|
||||||
|
connection: &Connection,
|
||||||
|
manager: Rc<dyn ConnectionManager>,
|
||||||
|
digest_state: Rc<RefCell<Option<DigestState>>>,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let mut res = Self {
|
||||||
|
state: HttpState::ExpectResponseHeaders,
|
||||||
client_inbuf: Default::default(),
|
client_inbuf: Default::default(),
|
||||||
server_inbuf: Default::default(),
|
server_inbuf: Default::default(),
|
||||||
client_outbuf: Default::default(),
|
client_outbuf: Default::default(),
|
||||||
server_outbuf,
|
server_outbuf: Default::default(),
|
||||||
data_buf: Default::default(),
|
data_buf: Default::default(),
|
||||||
crlf_state: Default::default(),
|
skip: 0,
|
||||||
|
counter: 0,
|
||||||
|
crlf_state: 0,
|
||||||
|
digest_state,
|
||||||
|
before: false,
|
||||||
|
credentials: manager.get_credentials().clone(),
|
||||||
|
destination: connection.dst.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
res.send_tunnel_request()?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_tunnel_request(&mut self) -> Result<(), Error> {
|
||||||
|
self.server_outbuf.extend(b"CONNECT ");
|
||||||
|
self.server_outbuf
|
||||||
|
.extend(self.destination.to_string().as_bytes());
|
||||||
|
self.server_outbuf.extend(b" HTTP/1.1\r\nHost: ");
|
||||||
|
self.server_outbuf
|
||||||
|
.extend(self.destination.to_string().as_bytes());
|
||||||
|
self.server_outbuf.extend(b"\r\n");
|
||||||
|
|
||||||
|
self.send_auth_data(if self.digest_state.borrow().is_none() {
|
||||||
|
AuthenticationScheme::Basic
|
||||||
|
} else {
|
||||||
|
AuthenticationScheme::Digest
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.server_outbuf.extend(b"\r\n");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_auth_data(&mut self, scheme: AuthenticationScheme) -> Result<(), Error> {
|
||||||
|
let Some(credentials) = &self.credentials else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
match scheme {
|
||||||
|
AuthenticationScheme::Digest => {
|
||||||
|
let uri = format!("{}:{}", self.destination.host, self.destination.port);
|
||||||
|
|
||||||
|
let context = digest_auth::AuthContext::new_with_method(
|
||||||
|
&credentials.username,
|
||||||
|
&credentials.password,
|
||||||
|
&uri,
|
||||||
|
Option::<&'_ [u8]>::None,
|
||||||
|
digest_auth::HttpMethod::CONNECT,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut state = self.digest_state.borrow_mut();
|
||||||
|
let response = state.as_mut().unwrap().respond(&context)?;
|
||||||
|
|
||||||
|
self.server_outbuf.extend(
|
||||||
|
format!(
|
||||||
|
"{}: {}\r\n",
|
||||||
|
PROXY_AUTHORIZATION,
|
||||||
|
response.to_header_string()
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
AuthenticationScheme::Basic => {
|
||||||
|
let cred = format!("{}:{}", credentials.username, credentials.password);
|
||||||
|
let auth_b64 = base64::engine::general_purpose::STANDARD.encode(cred);
|
||||||
|
self.server_outbuf
|
||||||
|
.extend(format!("{}: Basic {}\r\n", PROXY_AUTHORIZATION, auth_b64).as_bytes());
|
||||||
|
}
|
||||||
|
AuthenticationScheme::None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_change(&mut self) -> Result<(), Error> {
|
fn state_change(&mut self) -> Result<(), Error> {
|
||||||
let http_len = "HTTP/1.1 200".len();
|
|
||||||
match self.state {
|
match self.state {
|
||||||
HttpState::ExpectStatusCode if self.server_inbuf.len() > http_len => {
|
HttpState::ExpectResponseHeaders => {
|
||||||
let status_line: Vec<u8> =
|
while self.counter < self.server_inbuf.len() {
|
||||||
self.server_inbuf.range(0..http_len + 1).copied().collect();
|
let b = self.server_inbuf[self.counter];
|
||||||
let slice = &status_line.as_slice()[0.."HTTP/1.1 2".len()];
|
|
||||||
if slice != b"HTTP/1.1 2" && slice != b"HTTP/1.0 2"
|
|
||||||
|| self.server_inbuf[http_len] != b' '
|
|
||||||
{
|
|
||||||
let status_str = String::from_utf8_lossy(&status_line.as_slice()[0..http_len]);
|
|
||||||
let e =
|
|
||||||
format!("Expected success status code. Server replied with {status_str}.");
|
|
||||||
return Err(e.into());
|
|
||||||
}
|
|
||||||
self.state = HttpState::ExpectResponse;
|
|
||||||
return self.state_change();
|
|
||||||
}
|
|
||||||
HttpState::ExpectResponse => {
|
|
||||||
let mut counter = 0usize;
|
|
||||||
for b_ref in self.server_inbuf.iter() {
|
|
||||||
let b = *b_ref;
|
|
||||||
if b == b'\n' {
|
if b == b'\n' {
|
||||||
self.crlf_state += 1;
|
self.crlf_state += 1;
|
||||||
} else if b != b'\r' {
|
} else if b != b'\r' {
|
||||||
self.crlf_state = 0;
|
self.crlf_state = 0;
|
||||||
}
|
}
|
||||||
counter += 1;
|
|
||||||
|
|
||||||
|
self.counter += 1;
|
||||||
if self.crlf_state == 2 {
|
if self.crlf_state == 2 {
|
||||||
self.server_inbuf.drain(0..counter);
|
break;
|
||||||
|
|
||||||
self.server_outbuf.append(&mut self.data_buf);
|
|
||||||
self.data_buf.clear();
|
|
||||||
|
|
||||||
self.state = HttpState::Established;
|
|
||||||
return self.state_change();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.server_inbuf.drain(0..counter);
|
if self.crlf_state != 2 {
|
||||||
|
// Waiting for the end of the headers yet
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.counter = 0;
|
||||||
|
self.crlf_state = 0;
|
||||||
|
|
||||||
|
let mut headers = [httparse::EMPTY_HEADER; 16];
|
||||||
|
let mut res = Response::new(&mut headers);
|
||||||
|
|
||||||
|
// First make the buffer contiguous
|
||||||
|
let slice = self.server_inbuf.make_contiguous();
|
||||||
|
let status = res.parse(slice)?;
|
||||||
|
if status.is_partial() {
|
||||||
|
// TODO: Optimize in order to detect 200
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let len = status.unwrap();
|
||||||
|
let status_code = res.code.unwrap();
|
||||||
|
let version = res.version.unwrap();
|
||||||
|
|
||||||
|
if status_code == 200 {
|
||||||
|
// Connection successful
|
||||||
|
self.state = HttpState::Established;
|
||||||
|
self.server_inbuf.clear();
|
||||||
|
|
||||||
|
self.server_outbuf.append(&mut self.data_buf);
|
||||||
|
self.data_buf.clear();
|
||||||
|
|
||||||
|
return self.state_change();
|
||||||
|
}
|
||||||
|
|
||||||
|
if status_code != 407 {
|
||||||
|
let e =
|
||||||
|
format!("Expected success status code. Server replied with {status_code} [Reason: {}].", res.reason.unwrap());
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let headers_map: HashMap<UniCase<&str>, &[u8], RandomState> =
|
||||||
|
HashMap::from_iter(headers.map(|x| (UniCase::new(x.name), x.value)));
|
||||||
|
|
||||||
|
let Some(auth_data) = headers_map.get(&UniCase::new(PROXY_AUTHENTICATE)) else {
|
||||||
|
return Err("Proxy requires auth but doesn't send it datails".into());
|
||||||
|
};
|
||||||
|
|
||||||
|
if !auth_data[..6].eq_ignore_ascii_case(b"digest") {
|
||||||
|
// Fail to auth and the scheme isn't in the
|
||||||
|
// supported auth method schemes
|
||||||
|
return Err("Bad credentials".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analize challenge params
|
||||||
|
let data = str::from_utf8(auth_data)?;
|
||||||
|
let state = digest_auth::parse(data)?;
|
||||||
|
if self.before && !state.stale {
|
||||||
|
return Err("Bad credentials".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the digest state
|
||||||
|
self.digest_state.replace(Some(state));
|
||||||
|
self.before = true;
|
||||||
|
|
||||||
|
let closed = match headers_map.get(&UniCase::new(CONNECTION)) {
|
||||||
|
Some(conn_header) => conn_header.eq_ignore_ascii_case(b"close"),
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if closed || version == 0 {
|
||||||
|
// Close mio stream connection and reset it
|
||||||
|
// Reset all the buffers
|
||||||
|
self.server_inbuf.clear();
|
||||||
|
self.server_outbuf.clear();
|
||||||
|
self.send_tunnel_request()?;
|
||||||
|
|
||||||
|
self.state = HttpState::Reset;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// The HTTP/1.1 expected to be keep alive waiting for the next frame so, we must
|
||||||
|
// compute the lenght of the response in order to detect the next frame (response)
|
||||||
|
// [RFC-9112](https://datatracker.ietf.org/doc/html/rfc9112#body.content-length)
|
||||||
|
|
||||||
|
// Transfer-Encoding isn't supported yet
|
||||||
|
if let Some(_) = headers_map.get(&UniCase::new(TRANSFER_ENCODING)) {
|
||||||
|
unimplemented!("Header Transfer-Encoding not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
let content_length = match headers_map.get(&UniCase::new(CONTENT_LENGTH)) {
|
||||||
|
Some(v) => {
|
||||||
|
let value = str::from_utf8(v)?;
|
||||||
|
|
||||||
|
// https://www.rfc-editor.org/rfc/rfc9110#section-5.6.1
|
||||||
|
match value.parse::<usize>() {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(_) => {
|
||||||
|
let mut it = value.split(',').map(|x| x.parse::<usize>());
|
||||||
|
let f = it.next().unwrap()?;
|
||||||
|
for k in it {
|
||||||
|
if k? != f {
|
||||||
|
return Err("Malformed response".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// Close the connection by information miss
|
||||||
|
self.server_inbuf.clear();
|
||||||
|
self.server_outbuf.clear();
|
||||||
|
self.send_tunnel_request()?;
|
||||||
|
|
||||||
|
self.state = HttpState::Reset;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handshake state
|
||||||
|
self.state = HttpState::ExpectResponse;
|
||||||
|
self.skip = content_length + len;
|
||||||
|
|
||||||
|
return self.state_change();
|
||||||
|
}
|
||||||
|
HttpState::ExpectResponse => {
|
||||||
|
if self.skip > 0 {
|
||||||
|
let cnt = self.skip.min(self.server_inbuf.len());
|
||||||
|
self.server_inbuf.drain(..cnt);
|
||||||
|
self.skip -= cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.skip == 0 {
|
||||||
|
// Expected to the server_inbuff to be empty
|
||||||
|
|
||||||
|
// self.server_outbuf.append(&mut self.data_buf);
|
||||||
|
// self.data_buf.clear();
|
||||||
|
self.send_tunnel_request()?;
|
||||||
|
self.state = HttpState::ExpectResponseHeaders;
|
||||||
|
|
||||||
|
return self.state_change();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
HttpState::Established => {
|
HttpState::Established => {
|
||||||
self.client_outbuf.extend(self.server_inbuf.iter());
|
self.client_outbuf.extend(self.server_inbuf.iter());
|
||||||
|
@ -110,6 +309,9 @@ impl HttpConnection {
|
||||||
self.server_inbuf.clear();
|
self.server_inbuf.clear();
|
||||||
self.client_inbuf.clear();
|
self.client_inbuf.clear();
|
||||||
}
|
}
|
||||||
|
HttpState::Reset => {
|
||||||
|
self.state = HttpState::ExpectResponseHeaders;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -175,11 +377,16 @@ impl TcpProxy for HttpConnection {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reset_connection(&self) -> bool {
|
||||||
|
self.state == HttpState::Reset
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct HttpManager {
|
pub(crate) struct HttpManager {
|
||||||
server: SocketAddr,
|
server: SocketAddr,
|
||||||
credentials: Option<Credentials>,
|
credentials: Option<Credentials>,
|
||||||
|
digest_state: Rc<RefCell<Option<DigestState>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectionManager for HttpManager {
|
impl ConnectionManager for HttpManager {
|
||||||
|
@ -195,7 +402,11 @@ impl ConnectionManager for HttpManager {
|
||||||
if connection.proto != IpProtocol::Tcp {
|
if connection.proto != IpProtocol::Tcp {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
Ok(Some(Box::new(HttpConnection::new(connection, manager))))
|
Ok(Some(Box::new(HttpConnection::new(
|
||||||
|
connection,
|
||||||
|
manager,
|
||||||
|
self.digest_state.clone(),
|
||||||
|
)?)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_connection(&self, _: &Connection) {}
|
fn close_connection(&self, _: &Connection) {}
|
||||||
|
@ -214,6 +425,7 @@ impl HttpManager {
|
||||||
Rc::new(Self {
|
Rc::new(Self {
|
||||||
server,
|
server,
|
||||||
credentials,
|
credentials,
|
||||||
|
digest_state: Rc::new(RefCell::new(None)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,15 +110,15 @@ impl Options {
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug)]
|
#[derive(Default, Clone, Debug)]
|
||||||
pub struct Credentials {
|
pub struct Credentials {
|
||||||
pub(crate) username: Vec<u8>,
|
pub(crate) username: String,
|
||||||
pub(crate) password: Vec<u8>,
|
pub(crate) password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Credentials {
|
impl Credentials {
|
||||||
pub fn new(username: &str, password: &str) -> Self {
|
pub fn new(username: &str, password: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
username: username.as_bytes().to_vec(),
|
username: String::from(username),
|
||||||
password: password.as_bytes().to_vec(),
|
password: String::from(password),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/socks.rs
12
src/socks.rs
|
@ -156,10 +156,10 @@ impl SocksConnection {
|
||||||
}
|
}
|
||||||
self.server_outbuf.extend(ip_vec);
|
self.server_outbuf.extend(ip_vec);
|
||||||
if let Some(credentials) = credentials {
|
if let Some(credentials) = credentials {
|
||||||
self.server_outbuf.extend(&credentials.username);
|
self.server_outbuf.extend(credentials.username.as_bytes());
|
||||||
if !credentials.password.is_empty() {
|
if !credentials.password.is_empty() {
|
||||||
self.server_outbuf.push_back(b':');
|
self.server_outbuf.push_back(b':');
|
||||||
self.server_outbuf.extend(&credentials.password);
|
self.server_outbuf.extend(credentials.password.as_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.server_outbuf.push_back(0);
|
self.server_outbuf.push_back(0);
|
||||||
|
@ -250,10 +250,10 @@ impl SocksConnection {
|
||||||
let credentials = self.credentials.as_ref().unwrap_or(&tmp);
|
let credentials = self.credentials.as_ref().unwrap_or(&tmp);
|
||||||
self.server_outbuf
|
self.server_outbuf
|
||||||
.extend(&[1u8, credentials.username.len() as u8]);
|
.extend(&[1u8, credentials.username.len() as u8]);
|
||||||
self.server_outbuf.extend(&credentials.username);
|
self.server_outbuf.extend(credentials.username.as_bytes());
|
||||||
self.server_outbuf
|
self.server_outbuf
|
||||||
.extend(&[credentials.password.len() as u8]);
|
.extend(&[credentials.password.len() as u8]);
|
||||||
self.server_outbuf.extend(&credentials.password);
|
self.server_outbuf.extend(credentials.password.as_bytes());
|
||||||
self.state = SocksState::ReceiveAuthResponse;
|
self.state = SocksState::ReceiveAuthResponse;
|
||||||
self.state_change()
|
self.state_change()
|
||||||
}
|
}
|
||||||
|
@ -424,6 +424,10 @@ impl TcpProxy for SocksConnection {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reset_connection(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SocksManager {
|
pub struct SocksManager {
|
||||||
|
|
|
@ -228,6 +228,7 @@ pub(crate) trait TcpProxy {
|
||||||
fn peek_data(&mut self, dir: OutgoingDirection) -> OutgoingDataEvent;
|
fn peek_data(&mut self, dir: OutgoingDirection) -> OutgoingDataEvent;
|
||||||
fn connection_established(&self) -> bool;
|
fn connection_established(&self) -> bool;
|
||||||
fn have_data(&mut self, dir: Direction) -> bool;
|
fn have_data(&mut self, dir: Direction) -> bool;
|
||||||
|
fn reset_connection(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait ConnectionManager {
|
pub(crate) trait ConnectionManager {
|
||||||
|
@ -291,7 +292,7 @@ impl<'a> TunToProxy<'a> {
|
||||||
let mut virt = VirtualTunDevice::new(tun.capabilities());
|
let mut virt = VirtualTunDevice::new(tun.capabilities());
|
||||||
let gateway4: Ipv4Addr = Ipv4Addr::from_str("0.0.0.1")?;
|
let gateway4: Ipv4Addr = Ipv4Addr::from_str("0.0.0.1")?;
|
||||||
let gateway6: Ipv6Addr = Ipv6Addr::from_str("::1")?;
|
let gateway6: Ipv6Addr = Ipv6Addr::from_str("::1")?;
|
||||||
let mut iface = Interface::new(config, &mut virt);
|
let mut iface = Interface::new(config, &mut virt, smoltcp::time::Instant::now());
|
||||||
iface.update_ip_addrs(|ip_addrs| {
|
iface.update_ip_addrs(|ip_addrs| {
|
||||||
ip_addrs.push(IpCidr::new(gateway4.into(), 0)).unwrap();
|
ip_addrs.push(IpCidr::new(gateway4.into(), 0)).unwrap();
|
||||||
ip_addrs.push(IpCidr::new(gateway6.into(), 0)).unwrap()
|
ip_addrs.push(IpCidr::new(gateway6.into(), 0)).unwrap()
|
||||||
|
@ -699,6 +700,10 @@ impl<'a> TunToProxy<'a> {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let connection = conn_ref.unwrap().clone();
|
let connection = conn_ref.unwrap().clone();
|
||||||
|
let server = self
|
||||||
|
.get_connection_manager(&connection)
|
||||||
|
.unwrap()
|
||||||
|
.get_server();
|
||||||
|
|
||||||
(|| -> Result<(), Error> {
|
(|| -> Result<(), Error> {
|
||||||
if event.is_readable() || event.is_read_closed() {
|
if event.is_readable() || event.is_read_closed() {
|
||||||
|
@ -737,6 +742,30 @@ impl<'a> TunToProxy<'a> {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The handler request for reset the server connection
|
||||||
|
if state.handler.reset_connection() {
|
||||||
|
// Closes the connection with the proxy
|
||||||
|
state.mio_stream.shutdown(Both)?;
|
||||||
|
|
||||||
|
info!("RESETED {}", connection);
|
||||||
|
|
||||||
|
// TODO: Improve the call upstairs
|
||||||
|
state.mio_stream = TcpStream::connect(server)?;
|
||||||
|
|
||||||
|
_ = self.poll.registry().deregister(&mut state.mio_stream);
|
||||||
|
self.poll.registry().register(
|
||||||
|
&mut state.mio_stream,
|
||||||
|
state.token,
|
||||||
|
Interest::WRITABLE,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
state.wait_read = true;
|
||||||
|
state.wait_write = true;
|
||||||
|
state.close_state = 0;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if read == 0 || event.is_read_closed() {
|
if read == 0 || event.is_read_closed() {
|
||||||
state.wait_read = false;
|
state.wait_read = false;
|
||||||
state.close_state |= SERVER_WRITE_CLOSED;
|
state.close_state |= SERVER_WRITE_CLOSED;
|
||||||
|
|
Loading…
Add table
Reference in a new issue