tun2proxy/src/http.rs

432 lines
14 KiB
Rust
Raw Normal View History

2023-07-23 02:03:15 +08:00
use crate::{
error::Error,
tun2proxy::{
2023-08-05 15:52:32 +08:00
ConnectionInfo, ConnectionManager, Direction, IncomingDataEvent, IncomingDirection,
2023-07-23 02:03:15 +08:00
OutgoingDataEvent, OutgoingDirection, TcpProxy,
},
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-07-23 02:03:15 +08:00
use socks5_impl::protocol::{Address, UserKey};
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>,
destination: Address,
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,
destination: info.dst.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 ");
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 => {
2023-07-23 02:03:15 +08:00
let uri = self.destination.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)?;
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 => {}
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
}
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 {
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,
};
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;
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
}
}
impl TcpProxy for HttpConnection {
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
}
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(),
IncomingDirection::FromClient => {
2023-04-04 00:19:41 +02:00
!self.client_inbuf.is_empty() || !self.data_buf.is_empty()
}
},
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-06-22 13:09:36 -04:00
fn reset_connection(&self) -> bool {
self.state == HttpState::Reset
}
2021-09-02 11:30:23 +02: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-08-05 15:52:32 +08:00
fn handles_connection(&self, info: &ConnectionInfo) -> bool {
info.protocol == IpProtocol::Tcp
2021-09-02 11:30:23 +02:00
}
2023-08-05 15:52:32 +08:00
fn new_tcp_proxy(&self, info: &ConnectionInfo) -> Result<Box<dyn TcpProxy>, Error> {
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,
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 close_connection(&self, _: &ConnectionInfo) {}
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
}
2023-03-22 01:02:27 +01:00
2023-07-23 02:03:15 +08:00
fn get_credentials(&self) -> &Option<UserKey> {
2023-03-22 01:02:27 +01:00
&self.credentials
}
2021-09-02 11:30:23 +02:00
}
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
}