2023-07-23 02:03:15 +08:00
|
|
|
use crate::{
|
|
|
|
error::Error,
|
|
|
|
tun2proxy::{
|
2023-08-08 23:45:16 +08:00
|
|
|
ConnectionInfo, ConnectionManager, Direction, IncomingDataEvent, IncomingDirection, OutgoingDataEvent,
|
2023-09-01 11:28:06 +08:00
|
|
|
OutgoingDirection, ProxyHandler,
|
2023-07-23 02:03:15 +08:00
|
|
|
},
|
2022-08-01 14:36:58 +00:00
|
|
|
};
|
2023-03-22 10:12:32 +01:00
|
|
|
use base64::Engine;
|
2023-06-22 13:09:36 -04:00
|
|
|
use httparse::Response;
|
2023-03-23 18:31:09 +08:00
|
|
|
use smoltcp::wire::IpProtocol;
|
2023-08-10 14:17:07 +08:00
|
|
|
use socks5_impl::protocol::UserKey;
|
2023-07-23 02:03:15 +08:00
|
|
|
use std::{
|
|
|
|
cell::RefCell,
|
|
|
|
collections::{hash_map::RandomState, HashMap, VecDeque},
|
|
|
|
iter::FromIterator,
|
|
|
|
net::SocketAddr,
|
|
|
|
rc::Rc,
|
|
|
|
str,
|
|
|
|
};
|
2023-06-22 13:09:36 -04:00
|
|
|
use unicase::UniCase;
|
|
|
|
|
|
|
|
#[derive(Eq, PartialEq, Debug)]
|
|
|
|
#[allow(dead_code)]
|
|
|
|
enum AuthenticationScheme {
|
|
|
|
None,
|
|
|
|
Basic,
|
|
|
|
Digest,
|
|
|
|
}
|
2021-09-02 11:30:23 +02:00
|
|
|
|
|
|
|
#[derive(Eq, PartialEq, Debug)]
|
|
|
|
#[allow(dead_code)]
|
|
|
|
enum HttpState {
|
|
|
|
SendRequest,
|
2023-06-22 13:09:36 -04:00
|
|
|
ExpectResponseHeaders,
|
2021-09-02 11:30:23 +02:00
|
|
|
ExpectResponse,
|
2023-06-22 13:09:36 -04:00
|
|
|
Reset,
|
2022-08-01 14:36:58 +00:00
|
|
|
Established,
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
2023-06-22 13:09:36 -04:00
|
|
|
pub(crate) type DigestState = digest_auth::WwwAuthenticateHeader;
|
|
|
|
|
2021-09-02 11:30:23 +02:00
|
|
|
pub struct HttpConnection {
|
|
|
|
state: HttpState,
|
|
|
|
client_inbuf: VecDeque<u8>,
|
|
|
|
server_inbuf: VecDeque<u8>,
|
|
|
|
client_outbuf: VecDeque<u8>,
|
|
|
|
server_outbuf: VecDeque<u8>,
|
|
|
|
data_buf: VecDeque<u8>,
|
2022-08-01 14:36:58 +00:00
|
|
|
crlf_state: u8,
|
2023-06-22 13:09:36 -04:00
|
|
|
counter: usize,
|
|
|
|
skip: usize,
|
|
|
|
digest_state: Rc<RefCell<Option<DigestState>>>,
|
|
|
|
before: bool,
|
2023-07-23 02:03:15 +08:00
|
|
|
credentials: Option<UserKey>,
|
2023-08-10 14:17:07 +08:00
|
|
|
info: ConnectionInfo,
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
2023-06-22 13:09:36 -04:00
|
|
|
static PROXY_AUTHENTICATE: &str = "Proxy-Authenticate";
|
|
|
|
static PROXY_AUTHORIZATION: &str = "Proxy-Authorization";
|
|
|
|
static CONNECTION: &str = "Connection";
|
|
|
|
static TRANSFER_ENCODING: &str = "Transfer-Encoding";
|
|
|
|
static CONTENT_LENGTH: &str = "Content-Length";
|
2023-03-22 10:12:32 +01:00
|
|
|
|
2023-06-22 13:09:36 -04:00
|
|
|
impl HttpConnection {
|
|
|
|
fn new(
|
2023-08-05 15:52:32 +08:00
|
|
|
info: &ConnectionInfo,
|
|
|
|
credentials: Option<UserKey>,
|
2023-06-22 13:09:36 -04:00
|
|
|
digest_state: Rc<RefCell<Option<DigestState>>>,
|
|
|
|
) -> Result<Self, Error> {
|
|
|
|
let mut res = Self {
|
|
|
|
state: HttpState::ExpectResponseHeaders,
|
2023-07-23 02:03:15 +08:00
|
|
|
client_inbuf: VecDeque::default(),
|
|
|
|
server_inbuf: VecDeque::default(),
|
|
|
|
client_outbuf: VecDeque::default(),
|
|
|
|
server_outbuf: VecDeque::default(),
|
|
|
|
data_buf: VecDeque::default(),
|
2023-06-22 13:09:36 -04:00
|
|
|
skip: 0,
|
|
|
|
counter: 0,
|
|
|
|
crlf_state: 0,
|
|
|
|
digest_state,
|
|
|
|
before: false,
|
2023-08-05 15:52:32 +08:00
|
|
|
credentials,
|
2023-08-10 14:17:07 +08:00
|
|
|
info: info.clone(),
|
2023-06-22 13:09:36 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
res.send_tunnel_request()?;
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn send_tunnel_request(&mut self) -> Result<(), Error> {
|
|
|
|
self.server_outbuf.extend(b"CONNECT ");
|
2023-08-10 14:17:07 +08:00
|
|
|
self.server_outbuf.extend(self.info.dst.to_string().as_bytes());
|
2023-06-22 13:09:36 -04:00
|
|
|
self.server_outbuf.extend(b" HTTP/1.1\r\nHost: ");
|
2023-08-10 14:17:07 +08:00
|
|
|
self.server_outbuf.extend(self.info.dst.to_string().as_bytes());
|
2023-06-22 13:09:36 -04:00
|
|
|
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 => {
|
2023-08-10 14:17:07 +08:00
|
|
|
let uri = self.info.dst.to_string();
|
2023-06-22 13:09:36 -04:00
|
|
|
|
|
|
|
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)?;
|
|
|
|
|
2023-08-08 23:45:16 +08:00
|
|
|
self.server_outbuf
|
|
|
|
.extend(format!("{}: {}\r\n", PROXY_AUTHORIZATION, response.to_header_string()).as_bytes());
|
2023-06-22 13:09:36 -04:00
|
|
|
}
|
|
|
|
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 => {}
|
2023-03-22 10:12:32 +01:00
|
|
|
}
|
2023-06-22 13:09:36 -04:00
|
|
|
|
|
|
|
Ok(())
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
2023-03-22 22:19:00 +08:00
|
|
|
fn state_change(&mut self) -> Result<(), Error> {
|
2021-09-02 11:30:23 +02:00
|
|
|
match self.state {
|
2023-06-22 13:09:36 -04:00
|
|
|
HttpState::ExpectResponseHeaders => {
|
|
|
|
while self.counter < self.server_inbuf.len() {
|
|
|
|
let b = self.server_inbuf[self.counter];
|
2021-09-02 11:30:23 +02:00
|
|
|
if b == b'\n' {
|
|
|
|
self.crlf_state += 1;
|
|
|
|
} else if b != b'\r' {
|
|
|
|
self.crlf_state = 0;
|
|
|
|
}
|
|
|
|
|
2023-06-22 13:09:36 -04:00
|
|
|
self.counter += 1;
|
2021-09-02 11:30:23 +02:00
|
|
|
if self.crlf_state == 2 {
|
2023-06-22 13:09:36 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2023-08-08 23:45:16 +08:00
|
|
|
let e = format!(
|
|
|
|
"Expected success status code. Server replied with {} [Reason: {}].",
|
|
|
|
status_code,
|
|
|
|
res.reason.unwrap()
|
|
|
|
);
|
2023-06-22 13:09:36 -04:00
|
|
|
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,
|
|
|
|
};
|
2021-09-02 11:30:23 +02:00
|
|
|
|
2023-06-22 13:09:36 -04:00
|
|
|
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()?;
|
2021-09-02 11:30:23 +02:00
|
|
|
|
2023-06-22 13:09:36 -04:00
|
|
|
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
|
2023-06-30 21:21:40 +02:00
|
|
|
if headers_map.get(&UniCase::new(TRANSFER_ENCODING)).is_some() {
|
2023-06-22 13:09:36 -04:00
|
|
|
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(());
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
2023-06-22 13:09:36 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// 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;
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
2023-06-22 13:09:36 -04:00
|
|
|
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();
|
|
|
|
}
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
HttpState::Established => {
|
|
|
|
self.client_outbuf.extend(self.server_inbuf.iter());
|
|
|
|
self.server_outbuf.extend(self.client_inbuf.iter());
|
|
|
|
self.server_inbuf.clear();
|
|
|
|
self.client_inbuf.clear();
|
|
|
|
}
|
2023-06-22 13:09:36 -04:00
|
|
|
HttpState::Reset => {
|
|
|
|
self.state = HttpState::ExpectResponseHeaders;
|
2023-07-02 23:02:08 +02:00
|
|
|
return self.state_change();
|
2023-06-22 13:09:36 -04:00
|
|
|
}
|
2022-08-01 14:36:58 +00:00
|
|
|
_ => {}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-01 11:28:06 +08:00
|
|
|
impl ProxyHandler for HttpConnection {
|
2023-08-10 14:17:07 +08:00
|
|
|
fn get_connection_info(&self) -> &ConnectionInfo {
|
|
|
|
&self.info
|
|
|
|
}
|
|
|
|
|
2023-03-22 22:19:00 +08:00
|
|
|
fn push_data(&mut self, event: IncomingDataEvent<'_>) -> Result<(), Error> {
|
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 == HttpState::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 == HttpState::Established
|
2021-09-02 21:02:17 +02:00
|
|
|
}
|
2023-04-04 00:18:50 +02:00
|
|
|
|
|
|
|
fn have_data(&mut self, dir: Direction) -> bool {
|
|
|
|
match dir {
|
|
|
|
Direction::Incoming(incoming) => match incoming {
|
2023-04-04 00:19:41 +02:00
|
|
|
IncomingDirection::FromServer => !self.server_inbuf.is_empty(),
|
2023-08-08 23:45:16 +08:00
|
|
|
IncomingDirection::FromClient => !self.client_inbuf.is_empty() || !self.data_buf.is_empty(),
|
2023-04-04 00:18:50 +02:00
|
|
|
},
|
|
|
|
Direction::Outgoing(outgoing) => match outgoing {
|
2023-04-04 00:19:41 +02:00
|
|
|
OutgoingDirection::ToServer => !self.server_outbuf.is_empty(),
|
|
|
|
OutgoingDirection::ToClient => !self.client_outbuf.is_empty(),
|
2023-04-04 00:18:50 +02:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2023-06-22 13:09:36 -04:00
|
|
|
|
|
|
|
fn reset_connection(&self) -> bool {
|
|
|
|
self.state == HttpState::Reset
|
|
|
|
}
|
2023-08-11 19:18:18 +08:00
|
|
|
|
|
|
|
fn get_udp_associate(&self) -> Option<SocketAddr> {
|
|
|
|
None
|
|
|
|
}
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
2023-03-25 13:07:39 +01:00
|
|
|
pub(crate) struct HttpManager {
|
2023-03-23 20:00:59 +08:00
|
|
|
server: SocketAddr,
|
2023-07-23 02:03:15 +08:00
|
|
|
credentials: Option<UserKey>,
|
2023-06-22 13:09:36 -04:00
|
|
|
digest_state: Rc<RefCell<Option<DigestState>>>,
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ConnectionManager for HttpManager {
|
2023-09-01 11:28:06 +08:00
|
|
|
fn new_proxy_handler(&self, info: &ConnectionInfo, _: bool) -> Result<Box<dyn ProxyHandler>, Error> {
|
2023-08-05 15:52:32 +08:00
|
|
|
if info.protocol != IpProtocol::Tcp {
|
|
|
|
return Err("Invalid protocol".into());
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
2023-08-05 15:52:32 +08:00
|
|
|
Ok(Box::new(HttpConnection::new(
|
|
|
|
info,
|
2023-09-02 21:26:58 +08:00
|
|
|
self.credentials.clone(),
|
2023-06-22 13:09:36 -04:00
|
|
|
self.digest_state.clone(),
|
2023-08-05 15:52:32 +08:00
|
|
|
)?))
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
|
|
|
|
2023-08-05 15:52:32 +08:00
|
|
|
fn get_server_addr(&self) -> SocketAddr {
|
2021-09-02 11:30:23 +02:00
|
|
|
self.server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl HttpManager {
|
2023-08-05 15:52:32 +08:00
|
|
|
pub fn new(server: SocketAddr, credentials: Option<UserKey>) -> Self {
|
|
|
|
Self {
|
2023-03-22 01:02:27 +01:00
|
|
|
server,
|
|
|
|
credentials,
|
2023-06-22 13:09:36 -04:00
|
|
|
digest_state: Rc::new(RefCell::new(None)),
|
2023-08-05 15:52:32 +08:00
|
|
|
}
|
2021-09-02 11:30:23 +02:00
|
|
|
}
|
2022-08-01 14:36:58 +00:00
|
|
|
}
|