2023-10-23 17:11:12 +00:00
|
|
|
pub mod client;
|
|
|
|
mod io;
|
|
|
|
pub mod server;
|
|
|
|
|
2023-10-28 13:55:14 +00:00
|
|
|
use crate::{tcp, tls, LocalProtocol, LocalToRemote, WsClientConfig};
|
2023-10-23 17:11:12 +00:00
|
|
|
use async_trait::async_trait;
|
|
|
|
use bb8::ManageConnection;
|
|
|
|
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation};
|
|
|
|
use once_cell::sync::Lazy;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use std::collections::HashSet;
|
2023-10-28 13:55:14 +00:00
|
|
|
use std::io::{Error, IoSlice};
|
|
|
|
use std::pin::Pin;
|
|
|
|
use std::task::{Context, Poll};
|
|
|
|
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
2023-10-23 17:11:12 +00:00
|
|
|
use tokio::net::TcpStream;
|
|
|
|
use tokio_rustls::client::TlsStream;
|
2023-10-28 13:55:14 +00:00
|
|
|
use uuid::Uuid;
|
2023-10-23 17:11:12 +00:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
struct JwtTunnelConfig {
|
|
|
|
pub id: String,
|
|
|
|
pub p: LocalProtocol,
|
|
|
|
pub r: String,
|
|
|
|
pub rp: u16,
|
|
|
|
}
|
|
|
|
|
2023-10-28 13:55:14 +00:00
|
|
|
impl JwtTunnelConfig {
|
|
|
|
fn new(request_id: Uuid, tunnel: &LocalToRemote) -> Self {
|
|
|
|
Self {
|
|
|
|
id: request_id.to_string(),
|
|
|
|
p: match tunnel.local_protocol {
|
|
|
|
LocalProtocol::Tcp => LocalProtocol::Tcp,
|
|
|
|
LocalProtocol::Udp { .. } => tunnel.local_protocol,
|
|
|
|
LocalProtocol::Stdio => LocalProtocol::Tcp,
|
|
|
|
LocalProtocol::Socks5 => LocalProtocol::Tcp,
|
|
|
|
},
|
|
|
|
r: tunnel.remote.0.to_string(),
|
|
|
|
rp: tunnel.remote.1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-23 17:11:12 +00:00
|
|
|
static JWT_SECRET: &[u8; 15] = b"champignonfrais";
|
|
|
|
static JWT_KEY: Lazy<(Header, EncodingKey)> = Lazy::new(|| {
|
|
|
|
(
|
|
|
|
Header::new(Algorithm::HS256),
|
|
|
|
EncodingKey::from_secret(JWT_SECRET),
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
static JWT_DECODE: Lazy<(Validation, DecodingKey)> = Lazy::new(|| {
|
|
|
|
let mut validation = Validation::new(Algorithm::HS256);
|
|
|
|
validation.required_spec_claims = HashSet::with_capacity(0);
|
|
|
|
(validation, DecodingKey::from_secret(JWT_SECRET))
|
|
|
|
});
|
|
|
|
|
2023-10-28 13:55:14 +00:00
|
|
|
pub enum TransportStream {
|
|
|
|
Plain(TcpStream),
|
|
|
|
Tls(TlsStream<TcpStream>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsyncRead for TransportStream {
|
|
|
|
fn poll_read(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
buf: &mut ReadBuf<'_>,
|
|
|
|
) -> Poll<std::io::Result<()>> {
|
|
|
|
match self.get_mut() {
|
|
|
|
TransportStream::Plain(cnx) => Pin::new(cnx).poll_read(cx, buf),
|
|
|
|
TransportStream::Tls(cnx) => Pin::new(cnx).poll_read(cx, buf),
|
|
|
|
}
|
|
|
|
}
|
2023-10-23 17:11:12 +00:00
|
|
|
}
|
|
|
|
|
2023-10-28 13:55:14 +00:00
|
|
|
impl AsyncWrite for TransportStream {
|
|
|
|
fn poll_write(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
buf: &[u8],
|
|
|
|
) -> Poll<Result<usize, Error>> {
|
|
|
|
match self.get_mut() {
|
|
|
|
TransportStream::Plain(cnx) => Pin::new(cnx).poll_write(cx, buf),
|
|
|
|
TransportStream::Tls(cnx) => Pin::new(cnx).poll_write(cx, buf),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
|
|
|
match self.get_mut() {
|
|
|
|
TransportStream::Plain(cnx) => Pin::new(cnx).poll_flush(cx),
|
|
|
|
TransportStream::Tls(cnx) => Pin::new(cnx).poll_flush(cx),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
|
|
|
match self.get_mut() {
|
|
|
|
TransportStream::Plain(cnx) => Pin::new(cnx).poll_shutdown(cx),
|
|
|
|
TransportStream::Tls(cnx) => Pin::new(cnx).poll_shutdown(cx),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll_write_vectored(
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
cx: &mut Context<'_>,
|
|
|
|
bufs: &[IoSlice<'_>],
|
|
|
|
) -> Poll<Result<usize, Error>> {
|
|
|
|
match self.get_mut() {
|
|
|
|
TransportStream::Plain(cnx) => Pin::new(cnx).poll_write_vectored(cx, bufs),
|
|
|
|
TransportStream::Tls(cnx) => Pin::new(cnx).poll_write_vectored(cx, bufs),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_write_vectored(&self) -> bool {
|
|
|
|
match &self {
|
|
|
|
TransportStream::Plain(cnx) => cnx.is_write_vectored(),
|
|
|
|
TransportStream::Tls(cnx) => cnx.is_write_vectored(),
|
2023-10-23 17:11:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
impl ManageConnection for WsClientConfig {
|
2023-10-28 13:55:14 +00:00
|
|
|
type Connection = Option<TransportStream>;
|
2023-10-23 17:11:12 +00:00
|
|
|
type Error = anyhow::Error;
|
|
|
|
|
|
|
|
async fn connect(&self) -> Result<Self::Connection, Self::Error> {
|
|
|
|
let (host, port) = &self.remote_addr;
|
|
|
|
let so_mark = &self.socket_so_mark;
|
|
|
|
let timeout = self.timeout_connect;
|
|
|
|
|
|
|
|
let tcp_stream = if let Some(http_proxy) = &self.http_proxy {
|
|
|
|
tcp::connect_with_http_proxy(http_proxy, host, *port, so_mark, timeout).await?
|
|
|
|
} else {
|
|
|
|
tcp::connect(host, *port, so_mark, timeout).await?
|
|
|
|
};
|
|
|
|
|
|
|
|
match &self.tls {
|
2023-10-28 13:55:14 +00:00
|
|
|
None => Ok(Some(TransportStream::Plain(tcp_stream))),
|
2023-10-23 17:11:12 +00:00
|
|
|
Some(tls_cfg) => {
|
|
|
|
let tls_stream = tls::connect(self, tls_cfg, tcp_stream).await?;
|
2023-10-28 13:55:14 +00:00
|
|
|
Ok(Some(TransportStream::Tls(tls_stream)))
|
2023-10-23 17:11:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn is_valid(&self, _conn: &mut Self::Connection) -> Result<(), Self::Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn has_broken(&self, conn: &mut Self::Connection) -> bool {
|
2023-10-28 13:55:14 +00:00
|
|
|
conn.is_none()
|
2023-10-23 17:11:12 +00:00
|
|
|
}
|
|
|
|
}
|