Add udp reverse tunneling

This commit is contained in:
Σrebe - Romain GERARD 2023-11-26 18:22:28 +01:00
parent b352d5717d
commit f48b156542
No known key found for this signature in database
GPG key ID: 7A42B4B97E0332F4
5 changed files with 70 additions and 20 deletions

View file

@ -1,5 +1,5 @@
use super::{JwtTunnelConfig, JWT_KEY};
use crate::{tcp, LocalToRemote, WsClientConfig};
use crate::{LocalToRemote, WsClientConfig};
use anyhow::{anyhow, Context};
use fastwebsockets::WebSocket;
@ -149,10 +149,16 @@ where
Ok(())
}
pub async fn run_reverse_tunnel(
pub async fn run_reverse_tunnel<F, Fut, T>(
client_config: Arc<WsClientConfig>,
mut tunnel_cfg: LocalToRemote,
) -> anyhow::Result<()> {
connect_to_dest: F,
) -> anyhow::Result<()>
where
F: Fn() -> Fut,
Fut: Future<Output = anyhow::Result<T>>,
T: AsyncRead + AsyncWrite + Send + 'static,
{
// Invert local with remote
let remote = tunnel_cfg.remote;
tunnel_cfg.remote = match tunnel_cfg.local.ip() {
@ -178,14 +184,7 @@ pub async fn run_reverse_tunnel(
ws.set_auto_apply_mask(client_config.websocket_mask_frame);
// Connect to endpoint
let stream = tcp::connect(
&remote.0,
remote.1,
&client_config.socket_so_mark,
client_config.timeout_connect,
)
.instrument(span.clone())
.await;
let stream = connect_to_dest().instrument(span.clone()).await;
let stream = match stream {
Ok(s) => s,

View file

@ -35,6 +35,7 @@ impl JwtTunnelConfig {
LocalProtocol::Stdio => LocalProtocol::Tcp,
LocalProtocol::Socks5 => LocalProtocol::Tcp,
LocalProtocol::ReverseTcp => LocalProtocol::ReverseTcp,
LocalProtocol::ReverseUdp { .. } => tunnel.local_protocol,
},
r: tunnel.remote.0.to_string(),
rp: tunnel.remote.1,
@ -114,7 +115,7 @@ impl ManageConnection for WsClientConfig {
async fn connect(&self) -> Result<Self::Connection, Self::Error> {
let (host, port) = &self.remote_addr;
let so_mark = &self.socket_so_mark;
let so_mark = self.socket_so_mark;
let timeout = self.timeout_connect;
let tcp_stream = if let Some(http_proxy) = &self.http_proxy {

View file

@ -1,6 +1,7 @@
use ahash::{HashMap, HashMapExt};
use futures_util::StreamExt;
use futures_util::{Stream, StreamExt};
use std::cmp::min;
use std::io;
use std::ops::{Deref, Not};
use std::pin::Pin;
use std::sync::Arc;
@ -15,6 +16,7 @@ use jsonwebtoken::TokenData;
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use crate::udp::UdpStream;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpListener;
use tokio::sync::oneshot;
@ -71,7 +73,7 @@ async fn from_query(
LocalProtocol::Tcp => {
let host = Host::parse(&jwt.claims.r)?;
let port = jwt.claims.rp;
let (rx, tx) = tcp::connect(&host, port, &server_config.socket_so_mark, Duration::from_secs(10))
let (rx, tx) = tcp::connect(&host, port, server_config.socket_so_mark, Duration::from_secs(10))
.await?
.into_split();
@ -97,6 +99,27 @@ async fn from_query(
Ok((jwt.claims.p, local_srv.0, local_srv.1, Box::pin(local_rx), Box::pin(local_tx)))
}
LocalProtocol::ReverseUdp { timeout } => {
#[allow(clippy::type_complexity)]
static REVERSE: Lazy<
Mutex<HashMap<(Host<String>, u16), Pin<Box<dyn Stream<Item = io::Result<UdpStream>> + Send>>>>,
> = Lazy::new(|| Mutex::new(HashMap::with_capacity(0)));
let local_srv = (Host::parse(&jwt.claims.r)?, jwt.claims.rp);
let listening_server = REVERSE.lock().remove(&local_srv);
let mut listening_server = if let Some(listening_server) = listening_server {
listening_server
} else {
let bind = format!("{}:{}", local_srv.0, local_srv.1);
Box::pin(udp::run_server(bind.parse()?, timeout).await?)
};
let udp = listening_server.next().await.unwrap()?;
let (local_rx, local_tx) = tokio::io::split(udp);
REVERSE.lock().insert(local_srv.clone(), listening_server);
Ok((jwt.claims.p, local_srv.0, local_srv.1, Box::pin(local_rx), Box::pin(local_tx)))
}
_ => Err(anyhow::anyhow!("Invalid upgrade request")),
}
}