remove comments & rewrite client connection
This commit is contained in:
@@ -109,10 +109,8 @@ impl TcpConnection {
|
|||||||
while socket.can_recv() {
|
while socket.can_recv() {
|
||||||
let mut full = false;
|
let mut full = false;
|
||||||
|
|
||||||
// Используем recv_slice для контроля размера чанка
|
|
||||||
let mut temp = [0u8; TCP_CHUNK_SIZE];
|
let mut temp = [0u8; TCP_CHUNK_SIZE];
|
||||||
|
|
||||||
// Peek, чтобы проверить, сможем ли мы отправить данные, прежде чем извлечь их
|
|
||||||
if let Ok(n) = socket.peek_slice(&mut temp) {
|
if let Ok(n) = socket.peek_slice(&mut temp) {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
break;
|
break;
|
||||||
@@ -121,11 +119,10 @@ impl TcpConnection {
|
|||||||
let chunk = Bytes::copy_from_slice(&temp[..n]);
|
let chunk = Bytes::copy_from_slice(&temp[..n]);
|
||||||
match self.tx.try_send(chunk) {
|
match self.tx.try_send(chunk) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Только если успешно отправили в канал, удаляем данные из сокета
|
|
||||||
socket.recv_slice(&mut temp[..n]).unwrap();
|
socket.recv_slice(&mut temp[..n]).unwrap();
|
||||||
}
|
}
|
||||||
Err(mpsc::error::TrySendError::Full(_)) => {
|
Err(mpsc::error::TrySendError::Full(_)) => {
|
||||||
full = true; // Канал забит, сработает Backpressure в smoltcp
|
full = true;
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.state = ConnectionState::Closed;
|
self.state = ConnectionState::Closed;
|
||||||
@@ -143,25 +140,21 @@ impl TcpConnection {
|
|||||||
|
|
||||||
let current_pending = self.pending_data.len();
|
let current_pending = self.pending_data.len();
|
||||||
|
|
||||||
// Считаем % заполненности для логирования
|
|
||||||
let fill_ratio = (current_pending as f32 / MAX_PENDING as f32) * 100.0;
|
let fill_ratio = (current_pending as f32 / MAX_PENDING as f32) * 100.0;
|
||||||
|
|
||||||
if current_pending >= MAX_PENDING {
|
if current_pending >= MAX_PENDING {
|
||||||
// Состояние активного Backpressure
|
|
||||||
netrunner_logger::warn!(
|
netrunner_logger::warn!(
|
||||||
%self.handle,
|
%self.handle,
|
||||||
"Backpressure ACTIVE: Buffer is FULL ({} bytes). Stalling RX channel.",
|
"Backpressure ACTIVE: Buffer is FULL ({} bytes). Stalling RX channel.",
|
||||||
current_pending
|
current_pending
|
||||||
);
|
);
|
||||||
} else if fill_ratio > 80.0 {
|
} else if fill_ratio > 80.0 {
|
||||||
// Состояние Bufferbloat (буфер почти полон, пакеты задерживаются)
|
|
||||||
netrunner_logger::info!(
|
netrunner_logger::info!(
|
||||||
%self.handle,
|
%self.handle,
|
||||||
"Bufferbloat Warning: Buffer {:.1}% full ({} bytes). Latency increasing.",
|
"Bufferbloat Warning: Buffer {:.1}% full ({} bytes). Latency increasing.",
|
||||||
fill_ratio, current_pending
|
fill_ratio, current_pending
|
||||||
);
|
);
|
||||||
|
|
||||||
// Продолжаем читать, пока есть хоть какое-то место
|
|
||||||
while let Ok(data) = self.rx.try_recv() {
|
while let Ok(data) = self.rx.try_recv() {
|
||||||
self.pending_data.extend_from_slice(&data);
|
self.pending_data.extend_from_slice(&data);
|
||||||
if self.pending_data.len() >= MAX_PENDING {
|
if self.pending_data.len() >= MAX_PENDING {
|
||||||
@@ -169,7 +162,6 @@ impl TcpConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Обычный режим
|
|
||||||
while let Ok(data) = self.rx.try_recv() {
|
while let Ok(data) = self.rx.try_recv() {
|
||||||
self.pending_data.extend_from_slice(&data);
|
self.pending_data.extend_from_slice(&data);
|
||||||
if self.pending_data.len() >= MAX_PENDING {
|
if self.pending_data.len() >= MAX_PENDING {
|
||||||
@@ -178,13 +170,11 @@ impl TcpConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. DOWNLOAD: Отправка накопленного буфера в smoltcp
|
|
||||||
if !self.pending_data.is_empty() && socket.can_send() {
|
if !self.pending_data.is_empty() && socket.can_send() {
|
||||||
match socket.send_slice(&self.pending_data) {
|
match socket.send_slice(&self.pending_data) {
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
self.pending_data.advance(n);
|
self.pending_data.advance(n);
|
||||||
|
|
||||||
// Лог освобождения (опционально, чтобы видеть, что пробка рассасывается)
|
|
||||||
if n > 0 && self.pending_data.len() < (MAX_PENDING / 2) && fill_ratio > 90.0 {
|
if n > 0 && self.pending_data.len() < (MAX_PENDING / 2) && fill_ratio > 90.0 {
|
||||||
netrunner_logger::info!(%self.handle, "Backpressure RELIEVED: Buffer drained to {} bytes", self.pending_data.len());
|
netrunner_logger::info!(%self.handle, "Backpressure RELIEVED: Buffer drained to {} bytes", self.pending_data.len());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ use bytes::Bytes;
|
|||||||
|
|
||||||
pub struct UdpConnection {
|
pub struct UdpConnection {
|
||||||
pub handle: SocketHandle,
|
pub handle: SocketHandle,
|
||||||
// UPLOAD: Ограниченный канал для передачи данных наружу
|
|
||||||
tx: mpsc::Sender<Bytes>,
|
tx: mpsc::Sender<Bytes>,
|
||||||
// DOWNLOAD: Канал для приема данных из сети
|
|
||||||
rx: mpsc::Receiver<Bytes>,
|
rx: mpsc::Receiver<Bytes>,
|
||||||
client_endpoint: Option<IpEndpoint>,
|
client_endpoint: Option<IpEndpoint>,
|
||||||
last_activity: Instant,
|
last_activity: Instant,
|
||||||
@@ -20,10 +20,6 @@ pub struct UdpConnection {
|
|||||||
const UDP_TIMEOUT: Duration = Duration::from_secs(60);
|
const UDP_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
|
|
||||||
impl UdpConnection {
|
impl UdpConnection {
|
||||||
/// Возвращает:
|
|
||||||
/// 1. Экземпляр UdpConnection
|
|
||||||
/// 2. Receiver (для чтения данных, отправляемых ИЗ smoltcp В сеть)
|
|
||||||
/// 3. Sender (для записи данных ИЗ сети В smoltcp)
|
|
||||||
pub fn new(handle: SocketHandle) -> (Self, mpsc::Receiver<Bytes>, mpsc::Sender<Bytes>) {
|
pub fn new(handle: SocketHandle) -> (Self, mpsc::Receiver<Bytes>, mpsc::Sender<Bytes>) {
|
||||||
let (tx_to_net, rx_from_smol) = mpsc::channel::<Bytes>(CHANNEL_CAPACITY);
|
let (tx_to_net, rx_from_smol) = mpsc::channel::<Bytes>(CHANNEL_CAPACITY);
|
||||||
let (tx_to_smol, rx_from_net) = mpsc::channel::<Bytes>(CHANNEL_CAPACITY);
|
let (tx_to_smol, rx_from_net) = mpsc::channel::<Bytes>(CHANNEL_CAPACITY);
|
||||||
@@ -40,31 +36,25 @@ impl UdpConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, socket: &mut udp::Socket) -> bool {
|
pub fn tick(&mut self, socket: &mut udp::Socket) -> bool {
|
||||||
// Проверка таймаута бездействия
|
|
||||||
if self.last_activity.elapsed() > UDP_TIMEOUT {
|
if self.last_activity.elapsed() > UDP_TIMEOUT {
|
||||||
netrunner_logger::debug!(%self.handle, "UDP Session closed due to timeout");
|
netrunner_logger::debug!(%self.handle, "UDP Session closed due to timeout");
|
||||||
socket.close();
|
socket.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. UPLOAD: Читаем из smoltcp и отправляем в виртуальный канал
|
|
||||||
if socket.can_recv() {
|
if socket.can_recv() {
|
||||||
while let Ok((data, metadata)) = socket.recv() {
|
while let Ok((data, metadata)) = socket.recv() {
|
||||||
self.client_endpoint = Some(metadata.endpoint);
|
self.client_endpoint = Some(metadata.endpoint);
|
||||||
|
|
||||||
// Копируем данные в Bytes и пытаемся протолкнуть.
|
|
||||||
// Если канал забит (Full), пакет дропается — это штатное поведение UDP.
|
|
||||||
if self.tx.try_send(Bytes::copy_from_slice(data)).is_ok() {
|
if self.tx.try_send(Bytes::copy_from_slice(data)).is_ok() {
|
||||||
self.last_activity = Instant::now();
|
self.last_activity = Instant::now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. DOWNLOAD: Читаем из виртуального канала и пишем в smoltcp
|
|
||||||
if socket.can_send() {
|
if socket.can_send() {
|
||||||
if let Some(endpoint) = self.client_endpoint {
|
if let Some(endpoint) = self.client_endpoint {
|
||||||
while let Ok(data) = self.rx.try_recv() {
|
while let Ok(data) = self.rx.try_recv() {
|
||||||
// Сигнал закрытия стрима
|
|
||||||
if data.is_empty() {
|
if data.is_empty() {
|
||||||
socket.close();
|
socket.close();
|
||||||
return false;
|
return false;
|
||||||
@@ -75,8 +65,6 @@ impl UdpConnection {
|
|||||||
self.last_activity = Instant::now();
|
self.last_activity = Instant::now();
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// Если сокет smoltcp переполнен, прерываем цикл.
|
|
||||||
// Пакет теряется, что опять же является нормой для UDP.
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-29
@@ -1,35 +1,10 @@
|
|||||||
uniffi::setup_scaffolding!();
|
uniffi::setup_scaffolding!();
|
||||||
|
|
||||||
pub mod connections;
|
pub mod connections;
|
||||||
|
pub mod session;
|
||||||
pub mod tun;
|
pub mod tun;
|
||||||
use netrunner_logger::info;
|
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
use tokio_util::sync::CancellationToken;
|
|
||||||
|
|
||||||
use crate::tun::routing::reset_platform_routing;
|
pub static RUNTIME: OnceLock<Runtime> = OnceLock::new();
|
||||||
pub mod session;
|
|
||||||
|
|
||||||
static RUNTIME: OnceLock<Runtime> = OnceLock::new();
|
|
||||||
|
|
||||||
#[derive(uniffi::Object)]
|
|
||||||
pub struct Session {
|
|
||||||
pub(crate) cancel_token: CancellationToken,
|
|
||||||
pub(crate) proxy_ip: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uniffi::export]
|
|
||||||
impl Session {
|
|
||||||
pub fn stop(&self) {
|
|
||||||
info!("Stopping session...");
|
|
||||||
self.cancel_token.cancel();
|
|
||||||
let _ = reset_platform_routing(Some(&self.proxy_ip));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Session {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
info!("Session dropped, stopping all tasks...");
|
|
||||||
self.cancel_token.cancel();
|
|
||||||
let _ = reset_platform_routing(Some(&self.proxy_ip));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+6
-17
@@ -6,7 +6,7 @@ use netrunner_client::{
|
|||||||
tun::Tun,
|
tun::Tun,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use netrunner_core::proxy::{connection::connection::ConnectionRole, network::Network};
|
use netrunner_core::proxy::connection::connection::ClientHandler;
|
||||||
use netrunner_logger::{error, info};
|
use netrunner_logger::{error, info};
|
||||||
use smoltcp::{iface::Config, phy::DeviceCapabilities};
|
use smoltcp::{iface::Config, phy::DeviceCapabilities};
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
@@ -42,26 +42,15 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
caps.max_transmission_unit = 1350;
|
caps.max_transmission_unit = 1350;
|
||||||
caps.medium = smoltcp::phy::Medium::Ip;
|
caps.medium = smoltcp::phy::Medium::Ip;
|
||||||
|
|
||||||
let network = Network::new(
|
|
||||||
"127.0.0.1".into(),
|
|
||||||
8080,
|
|
||||||
ConnectionRole::Client,
|
|
||||||
Some(remote_address.clone()),
|
|
||||||
);
|
|
||||||
|
|
||||||
let network_token = CancellationToken::new();
|
let network_token = CancellationToken::new();
|
||||||
let net_token_for_spawn = network_token.clone();
|
|
||||||
|
|
||||||
info!("Establishing secure tunnel to proxy server...");
|
info!("Establishing secure tunnel to proxy server...");
|
||||||
let muxer = match network.initialize_client_tunnel(net_token_for_spawn).await {
|
|
||||||
|
let muxer = match ClientHandler::connect(&remote_address).await {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to establish secure tunnel: {}", e);
|
error!("Failed to establish secure tunnel to server: {}", e);
|
||||||
|
return Err(anyhow::anyhow!("Failed to establish secure tunnel: {}", e));
|
||||||
let _ = reset_platform_routing(Some(
|
|
||||||
&remote_address.split(':').next().unwrap().to_string(),
|
|
||||||
));
|
|
||||||
return Err(anyhow::anyhow!("Tunnel initialization failed: {}", e));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
info!("Secure tunnel established, Muxer is ready.");
|
info!("Secure tunnel established, Muxer is ready.");
|
||||||
@@ -96,7 +85,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
error!("Failed to restore routing: {}", e);
|
error!("Failed to restore routing: {}", e);
|
||||||
} else {
|
} else {
|
||||||
info!("System routing restored successfully.");
|
info!("System routing restored successfully.");
|
||||||
}
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-58
@@ -1,22 +1,18 @@
|
|||||||
|
use crate::{
|
||||||
|
RUNTIME,
|
||||||
|
tun::{engine::EngineBuilder, routing::reset_platform_routing, tun::Tun},
|
||||||
|
};
|
||||||
|
use netrunner_logger::{error, info};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
pub mod desktop;
|
pub mod desktop;
|
||||||
|
|
||||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
pub mod mobile;
|
pub mod mobile;
|
||||||
|
|
||||||
use crate::{
|
|
||||||
RUNTIME, Session,
|
|
||||||
connections::dns::DnsHandler,
|
|
||||||
tun::{engine::Engine, routing::setup_platform_routing, tun::Tun},
|
|
||||||
};
|
|
||||||
use netrunner_core::proxy::{connection::connection::ConnectionRole, network::Network};
|
|
||||||
use netrunner_logger::{error, info};
|
|
||||||
use smoltcp::{iface::Config, phy::DeviceCapabilities};
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::runtime::Runtime;
|
|
||||||
use tokio_util::sync::CancellationToken;
|
|
||||||
|
|
||||||
fn get_runtime() -> &'static Runtime {
|
fn get_runtime() -> &'static Runtime {
|
||||||
RUNTIME.get_or_init(|| {
|
RUNTIME.get_or_init(|| {
|
||||||
tokio::runtime::Builder::new_multi_thread()
|
tokio::runtime::Builder::new_multi_thread()
|
||||||
@@ -26,6 +22,29 @@ fn get_runtime() -> &'static Runtime {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(uniffi::Object)]
|
||||||
|
pub struct Session {
|
||||||
|
pub(crate) cancel_token: CancellationToken,
|
||||||
|
pub(crate) proxy_ip: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[uniffi::export]
|
||||||
|
impl Session {
|
||||||
|
pub fn stop(&self) {
|
||||||
|
info!("Stopping session...");
|
||||||
|
self.cancel_token.cancel();
|
||||||
|
let _ = reset_platform_routing(Some(&self.proxy_ip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Session {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
info!("Session dropped, stopping all tasks...");
|
||||||
|
self.cancel_token.cancel();
|
||||||
|
let _ = reset_platform_routing(Some(&self.proxy_ip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(uniffi::Object)]
|
#[derive(uniffi::Object)]
|
||||||
pub struct SessionManager;
|
pub struct SessionManager;
|
||||||
|
|
||||||
@@ -48,8 +67,7 @@ impl SessionManager {
|
|||||||
) -> Arc<Session> {
|
) -> Arc<Session> {
|
||||||
let runtime = get_runtime();
|
let runtime = get_runtime();
|
||||||
let cancel_token = CancellationToken::new();
|
let cancel_token = CancellationToken::new();
|
||||||
let sesison_token = cancel_token.clone();
|
let session_token = cancel_token.clone();
|
||||||
let net_token = cancel_token.clone();
|
|
||||||
|
|
||||||
let addr: std::net::SocketAddr = remote_address.parse().expect("Invalid address format");
|
let addr: std::net::SocketAddr = remote_address.parse().expect("Invalid address format");
|
||||||
let remote_proxy_ip = addr.ip().to_string();
|
let remote_proxy_ip = addr.ip().to_string();
|
||||||
@@ -68,11 +86,6 @@ impl SessionManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut dns_handler = DnsHandler::new(&cache_path);
|
|
||||||
if let Err(e) = dns_handler.init().await {
|
|
||||||
error!("Failed to initialize DNS blocklist: {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tun_device = {
|
let tun_device = {
|
||||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
{
|
{
|
||||||
@@ -100,55 +113,32 @@ impl SessionManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = setup_platform_routing(&remote_address);
|
let builder_result = EngineBuilder::new(&remote_address)
|
||||||
|
.with_cache_path(&cache_path)
|
||||||
|
.with_tun(tun_device)
|
||||||
|
.build()
|
||||||
|
.await;
|
||||||
|
|
||||||
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
match builder_result {
|
||||||
let mut caps = DeviceCapabilities::default();
|
Ok((mut engine, tun)) => {
|
||||||
caps.max_transmission_unit = 1350;
|
|
||||||
caps.medium = smoltcp::phy::Medium::Ip;
|
|
||||||
|
|
||||||
let network = Network::new(
|
|
||||||
"0.0.0.0".into(),
|
|
||||||
8080,
|
|
||||||
ConnectionRole::Client,
|
|
||||||
Some(remote_address.clone()),
|
|
||||||
);
|
|
||||||
|
|
||||||
let muxer = match network.initialize_client_tunnel(net_token).await {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(e) => {
|
|
||||||
error!("Failed to establish secure tunnel to server: {}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
info!("Secure tunnel established, Muxer is ready.");
|
|
||||||
|
|
||||||
let mut engine = Engine::new(config, caps, dns_handler, muxer);
|
|
||||||
engine.set_any_ip(true);
|
|
||||||
engine.set_transparent_mode();
|
|
||||||
engine.set_default_gateway(Ipv4Addr::new(10, 0, 0, 2));
|
|
||||||
engine.activate();
|
|
||||||
let cancel_token_for_engine = cancel_token.clone();
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
|
||||||
info!("Engine async task started");
|
info!("Engine async task started");
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
res = engine.run(tun) => {
|
||||||
res = engine.run(tun_device) => {
|
|
||||||
|
|
||||||
info!("Engine loop finished: {:?}", res);
|
info!("Engine loop finished: {:?}", res);
|
||||||
},
|
},
|
||||||
_ = cancel_token_for_engine.cancelled() => {
|
_ = cancel_token.cancelled() => {
|
||||||
info!("Engine task shutting down via token");
|
info!("Engine task shutting down via token");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to build VPN Engine: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Arc::new(Session {
|
Arc::new(Session {
|
||||||
cancel_token: sesison_token,
|
cancel_token: session_token,
|
||||||
proxy_ip: remote_proxy_ip,
|
proxy_ip: remote_proxy_ip,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,10 +101,7 @@ impl ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_sockets(&mut self, socket_set: &mut SocketSet) {
|
pub fn process_sockets(&mut self, socket_set: &mut SocketSet) {
|
||||||
// Добавим лог в начало цикла, если сессий много, чтобы видеть нагрузку
|
if !self.active_tcp_sessions.is_empty() || !self.active_udp_sessions.is_empty() {}
|
||||||
if !self.active_tcp_sessions.is_empty() || !self.active_udp_sessions.is_empty() {
|
|
||||||
// trace!("Processing sockets: TCP={}, UDP={}", self.active_tcp_sessions.len(), self.active_udp_sessions.len());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (handle, socket) in socket_set.iter_mut() {
|
for (handle, socket) in socket_set.iter_mut() {
|
||||||
if let Some(tcp) = tcp::Socket::downcast_mut(socket) {
|
if let Some(tcp) = tcp::Socket::downcast_mut(socket) {
|
||||||
@@ -170,7 +167,6 @@ impl ConnectionManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ждем подтверждения от прокси (handshake)
|
|
||||||
match tokio::time::timeout(Duration::from_secs(10), v_rx.recv()).await {
|
match tokio::time::timeout(Duration::from_secs(10), v_rx.recv()).await {
|
||||||
Ok(Some(data)) => {
|
Ok(Some(data)) => {
|
||||||
if data.len() >= 2 && data[1] == 0x00 {
|
if data.len() >= 2 && data[1] == 0x00 {
|
||||||
@@ -281,11 +277,9 @@ impl ConnectionManager {
|
|||||||
|
|
||||||
netrunner_logger::info!(%handle, target = %target, "New UDP proxied session established");
|
netrunner_logger::info!(%handle, target = %target, "New UDP proxied session established");
|
||||||
|
|
||||||
// 1. Создаем UDP соединение и получаем каналы
|
|
||||||
let (conn, mut rx_from_smol, tx_to_smol) = UdpConnection::new(handle);
|
let (conn, mut rx_from_smol, tx_to_smol) = UdpConnection::new(handle);
|
||||||
self.active_udp_sessions.insert(handle, conn);
|
self.active_udp_sessions.insert(handle, conn);
|
||||||
|
|
||||||
// 2. Фоновая задача для Muxer'а
|
|
||||||
let muxer = self.muxer.clone();
|
let muxer = self.muxer.clone();
|
||||||
let stream_id = muxer.next_id();
|
let stream_id = muxer.next_id();
|
||||||
let connect_payload = target.to_string();
|
let connect_payload = target.to_string();
|
||||||
@@ -441,8 +435,8 @@ impl ConnectionManager {
|
|||||||
|
|
||||||
fn create_dynamic_udp_socket<'a>(port: u16) -> udp::Socket<'a> {
|
fn create_dynamic_udp_socket<'a>(port: u16) -> udp::Socket<'a> {
|
||||||
let (buf_size, packet_count) = match port {
|
let (buf_size, packet_count) = match port {
|
||||||
443 => (512 * 1024, 390), // Большой буфер для QUIC (YouTube)
|
443 => (512 * 1024, 390),
|
||||||
53 => (64 * 1024, 32), // DNS
|
53 => (64 * 1024, 32),
|
||||||
_ => (128 * 1024, 100),
|
_ => (128 * 1024, 100),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ use std::{
|
|||||||
Arc, LazyLock, Mutex,
|
Arc, LazyLock, Mutex,
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
},
|
},
|
||||||
time::Instant as StdInstant, // Добавлено для расчёта скорости
|
time::Instant as StdInstant,
|
||||||
};
|
};
|
||||||
|
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use netrunner_logger::info; // Предполагается, что у тебя есть этот логгер
|
use netrunner_logger::info;
|
||||||
use smoltcp::{
|
use smoltcp::{
|
||||||
phy::{self, Device, DeviceCapabilities},
|
phy::{self, Device, DeviceCapabilities},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
@@ -20,7 +20,6 @@ use tokio::sync::mpsc;
|
|||||||
const TOKEN_BUFFER_LIST_MAX_SIZE: usize = 64;
|
const TOKEN_BUFFER_LIST_MAX_SIZE: usize = 64;
|
||||||
static TOKEN_BUFFER_LIST: LazyLock<Mutex<Vec<BytesMut>>> = LazyLock::new(|| Mutex::new(Vec::new()));
|
static TOKEN_BUFFER_LIST: LazyLock<Mutex<Vec<BytesMut>>> = LazyLock::new(|| Mutex::new(Vec::new()));
|
||||||
|
|
||||||
// Структура, которую мы будем возвращать пользователю
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct TrafficStats {
|
pub struct TrafficStats {
|
||||||
pub rx_bytes: u64,
|
pub rx_bytes: u64,
|
||||||
@@ -79,20 +78,17 @@ pub struct VirtTunDevice {
|
|||||||
tx_queue: mpsc::UnboundedSender<TokenBuffer>,
|
tx_queue: mpsc::UnboundedSender<TokenBuffer>,
|
||||||
rx_avail: Arc<AtomicBool>,
|
rx_avail: Arc<AtomicBool>,
|
||||||
|
|
||||||
// === Статистика трафика ===
|
|
||||||
rx_bytes: u64,
|
rx_bytes: u64,
|
||||||
tx_bytes: u64,
|
tx_bytes: u64,
|
||||||
rx_packets: u64,
|
rx_packets: u64,
|
||||||
tx_packets: u64,
|
tx_packets: u64,
|
||||||
|
|
||||||
// Внутренние переменные для расчёта скорости
|
|
||||||
last_speed_calc: StdInstant,
|
last_speed_calc: StdInstant,
|
||||||
last_rx_bytes: u64,
|
last_rx_bytes: u64,
|
||||||
last_tx_bytes: u64,
|
last_tx_bytes: u64,
|
||||||
cached_rx_speed: f64,
|
cached_rx_speed: f64,
|
||||||
cached_tx_speed: f64,
|
cached_tx_speed: f64,
|
||||||
|
|
||||||
// Для периодического логирования
|
|
||||||
last_log_time: StdInstant,
|
last_log_time: StdInstant,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +143,6 @@ impl VirtTunDevice {
|
|||||||
let rx_diff = self.rx_bytes.saturating_sub(self.last_rx_bytes);
|
let rx_diff = self.rx_bytes.saturating_sub(self.last_rx_bytes);
|
||||||
let tx_diff = self.tx_bytes.saturating_sub(self.last_tx_bytes);
|
let tx_diff = self.tx_bytes.saturating_sub(self.last_tx_bytes);
|
||||||
|
|
||||||
// Переводим в МегаБайты в секунду (MB/s)
|
|
||||||
self.cached_rx_speed = (rx_diff as f64 / 1_048_576.0) / elapsed_speed;
|
self.cached_rx_speed = (rx_diff as f64 / 1_048_576.0) / elapsed_speed;
|
||||||
self.cached_tx_speed = (tx_diff as f64 / 1_048_576.0) / elapsed_speed;
|
self.cached_tx_speed = (tx_diff as f64 / 1_048_576.0) / elapsed_speed;
|
||||||
|
|
||||||
@@ -166,12 +161,11 @@ impl VirtTunDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Внутренний метод проверки таймера для вывода логов
|
|
||||||
fn check_and_log_stats(&mut self) {
|
fn check_and_log_stats(&mut self) {
|
||||||
let now = StdInstant::now();
|
let now = StdInstant::now();
|
||||||
// Логируем каждые 5 секунд
|
|
||||||
if now.duration_since(self.last_log_time).as_secs() >= 5 {
|
if now.duration_since(self.last_log_time).as_secs() >= 5 {
|
||||||
let stats = self.get_stats(); // Заодно обновляем скорости
|
let stats = self.get_stats();
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"TunDevice Traffic: RX: {:.2} MB ({} pkts) | TX: {:.2} MB ({} pkts) | Speed: ↓{:.2} MB/s, ↑{:.2} MB/s",
|
"TunDevice Traffic: RX: {:.2} MB ({} pkts) | TX: {:.2} MB ({} pkts) | Speed: ↓{:.2} MB/s, ↑{:.2} MB/s",
|
||||||
@@ -193,12 +187,9 @@ impl Device for VirtTunDevice {
|
|||||||
type TxToken<'a> = VirtTxToken<'a>;
|
type TxToken<'a> = VirtTxToken<'a>;
|
||||||
|
|
||||||
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||||
// Проверяем, не пора ли записать стату в лог. receive() вызывается очень часто,
|
|
||||||
// поэтому это отличное место для heartbeat таймера.
|
|
||||||
self.check_and_log_stats();
|
self.check_and_log_stats();
|
||||||
|
|
||||||
if let Ok(buffer) = self.rx_queue.try_recv() {
|
if let Ok(buffer) = self.rx_queue.try_recv() {
|
||||||
// Учет входящего трафика (DOWNLOAD)
|
|
||||||
self.rx_bytes += buffer.len() as u64;
|
self.rx_bytes += buffer.len() as u64;
|
||||||
self.rx_packets += 1;
|
self.rx_packets += 1;
|
||||||
|
|
||||||
@@ -250,7 +241,6 @@ impl phy::TxToken for VirtTxToken<'_> {
|
|||||||
|
|
||||||
let result = f(&mut buffer);
|
let result = f(&mut buffer);
|
||||||
|
|
||||||
// Учет исходящего трафика (UPLOAD)
|
|
||||||
self.0.tx_bytes += len as u64;
|
self.0.tx_bytes += len as u64;
|
||||||
self.0.tx_packets += 1;
|
self.0.tx_packets += 1;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use netrunner_core::proxy::connection::connection::ClientHandler;
|
||||||
use netrunner_core::proxy::connection::muxer::Muxer;
|
use netrunner_core::proxy::connection::muxer::Muxer;
|
||||||
use smoltcp::iface::PollResult;
|
use smoltcp::iface::PollResult;
|
||||||
use smoltcp::time::Instant;
|
use smoltcp::time::Instant;
|
||||||
@@ -6,6 +7,7 @@ use smoltcp::{
|
|||||||
iface::{Config, Interface, SocketSet},
|
iface::{Config, Interface, SocketSet},
|
||||||
phy::DeviceCapabilities,
|
phy::DeviceCapabilities,
|
||||||
};
|
};
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::{
|
use std::{
|
||||||
sync::{Arc, LazyLock, atomic::AtomicBool},
|
sync::{Arc, LazyLock, atomic::AtomicBool},
|
||||||
@@ -16,11 +18,12 @@ use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
|||||||
use tokio::time::{Duration, sleep};
|
use tokio::time::{Duration, sleep};
|
||||||
use tun::{DeviceReader, DeviceWriter};
|
use tun::{DeviceReader, DeviceWriter};
|
||||||
|
|
||||||
use netrunner_logger::{debug, info, warn};
|
use netrunner_logger::{debug, error, info, warn};
|
||||||
|
|
||||||
use crate::connections::dns::DnsHandler;
|
use crate::connections::dns::DnsHandler;
|
||||||
use crate::tun::connection_manager::ConnectionManager;
|
use crate::tun::connection_manager::ConnectionManager;
|
||||||
use crate::tun::device::{TokenBuffer, VirtTunDevice};
|
use crate::tun::device::{TokenBuffer, VirtTunDevice};
|
||||||
|
use crate::tun::routing::setup_platform_routing;
|
||||||
use crate::tun::tun::Tun;
|
use crate::tun::tun::Tun;
|
||||||
|
|
||||||
pub static START_TIME: LazyLock<StdInstant> = LazyLock::new(StdInstant::now);
|
pub static START_TIME: LazyLock<StdInstant> = LazyLock::new(StdInstant::now);
|
||||||
@@ -212,3 +215,65 @@ impl Engine {
|
|||||||
self.manager.start_listening(&mut self.socket_set);
|
self.manager.start_listening(&mut self.socket_set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct EngineBuilder {
|
||||||
|
remote_address: String,
|
||||||
|
cache_path: String,
|
||||||
|
tun_device: Option<Tun>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EngineBuilder {
|
||||||
|
pub fn new(remote_address: impl Into<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
remote_address: remote_address.into(),
|
||||||
|
cache_path: ".".to_string(),
|
||||||
|
tun_device: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_cache_path(mut self, path: impl Into<String>) -> Self {
|
||||||
|
self.cache_path = path.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_tun(mut self, tun: Tun) -> Self {
|
||||||
|
self.tun_device = Some(tun);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn build(self) -> Result<(Engine, Tun), String> {
|
||||||
|
let tun = self.tun_device.ok_or("TUN device is required")?;
|
||||||
|
|
||||||
|
info!("Initializing Engine components...");
|
||||||
|
|
||||||
|
let mut dns_handler = DnsHandler::new(&self.cache_path);
|
||||||
|
if let Err(e) = dns_handler.init().await {
|
||||||
|
error!("Failed to initialize DNS blocklist: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = setup_platform_routing(&self.remote_address) {
|
||||||
|
return Err(format!("Routing setup failed: {}", e));
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
||||||
|
let mut caps = DeviceCapabilities::default();
|
||||||
|
caps.max_transmission_unit = 1350;
|
||||||
|
caps.medium = smoltcp::phy::Medium::Ip;
|
||||||
|
|
||||||
|
info!("Establishing secure tunnel to proxy server...");
|
||||||
|
let muxer = ClientHandler::connect(&self.remote_address)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to establish secure tunnel: {}", e))?;
|
||||||
|
info!("Secure tunnel established, Muxer is ready.");
|
||||||
|
|
||||||
|
let mut engine = Engine::new(config, caps, dns_handler, muxer);
|
||||||
|
engine.set_any_ip(true);
|
||||||
|
engine.set_transparent_mode();
|
||||||
|
engine.set_default_gateway(Ipv4Addr::new(10, 0, 0, 2));
|
||||||
|
engine.activate();
|
||||||
|
|
||||||
|
info!("Stack IP initialized: 10.0.0.2");
|
||||||
|
|
||||||
|
Ok((engine, tun))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ pub async fn run_proxy_bridge<R, W>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Отправляем Close фрейм перед выходом
|
|
||||||
let _ = muxer
|
let _ = muxer
|
||||||
.send_to_netwrok(MuxMessage {
|
.send_to_netwrok(MuxMessage {
|
||||||
stream_id,
|
stream_id,
|
||||||
@@ -68,10 +67,8 @@ pub async fn run_proxy_bridge<R, W>(
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Небольшая пауза, чтобы Close фрейм успел уйти в сеть
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
||||||
|
|
||||||
// ИЗМЕНЕНИЕ: remove_stream теперь синхронный
|
|
||||||
muxer.remove_stream(stream_id);
|
muxer.remove_stream(stream_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +128,5 @@ pub async fn run_udp_bridge(
|
|||||||
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
||||||
|
|
||||||
// ИЗМЕНЕНИЕ: remove_stream теперь синхронный
|
|
||||||
muxer.remove_stream(stream_id);
|
muxer.remove_stream(stream_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,12 @@ use crate::{
|
|||||||
parser::parser::Parser,
|
parser::parser::Parser,
|
||||||
},
|
},
|
||||||
proxy::connection::{
|
proxy::connection::{
|
||||||
bridge::run_proxy_bridge,
|
bridge::run_proxy_bridge, engine::TunnelEngine, handler::StreamHandler, muxer::Muxer,
|
||||||
engine::TunnelEngine,
|
|
||||||
handler::StreamHandler,
|
|
||||||
muxer::{MuxMessage, Muxer},
|
|
||||||
MESSAGE_CHANNEL_SIZE, TCP_BUF_SIZE,
|
MESSAGE_CHANNEL_SIZE, TCP_BUF_SIZE,
|
||||||
},
|
},
|
||||||
tlseng::profile::BrowserProfile,
|
tlseng::profile::BrowserProfile,
|
||||||
};
|
};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::BytesMut;
|
||||||
use netrunner_logger::{info, warn};
|
use netrunner_logger::{info, warn};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
io::{AsyncReadExt, AsyncWriteExt},
|
||||||
@@ -101,10 +98,7 @@ pub struct ClientHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClientHandler {
|
impl ClientHandler {
|
||||||
pub async fn connect(
|
pub async fn connect(remote_proxy_addr: &str) -> Result<Muxer, String> {
|
||||||
remote_proxy_addr: &str,
|
|
||||||
token: CancellationToken,
|
|
||||||
) -> Result<Muxer, String> {
|
|
||||||
let stream = TcpStream::connect(remote_proxy_addr)
|
let stream = TcpStream::connect(remote_proxy_addr)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
@@ -138,9 +132,8 @@ impl ClientHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- ИЗМЕНЕНИЕ ДЛЯ НОВОГО MUXER ---
|
let (control_tx, control_rx) = mpsc::channel(MESSAGE_CHANNEL_SIZE * 4);
|
||||||
let (control_tx, control_rx) = mpsc::channel(MESSAGE_CHANNEL_SIZE);
|
let (data_tx, data_rx) = mpsc::channel(MESSAGE_CHANNEL_SIZE * 4);
|
||||||
let (data_tx, data_rx) = mpsc::channel(MESSAGE_CHANNEL_SIZE);
|
|
||||||
|
|
||||||
let muxer = Muxer::new(control_tx, data_tx, true);
|
let muxer = Muxer::new(control_tx, data_tx, true);
|
||||||
|
|
||||||
@@ -152,10 +145,9 @@ impl ClientHandler {
|
|||||||
outbound: conn.outbound,
|
outbound: conn.outbound,
|
||||||
codec: conn.codec,
|
codec: conn.codec,
|
||||||
read_buf: conn.read_buf,
|
read_buf: conn.read_buf,
|
||||||
control_rx, // Передаем оба ресивера в Engine
|
control_rx,
|
||||||
data_rx, // Передаем оба ресивера в Engine
|
data_rx,
|
||||||
handler,
|
handler,
|
||||||
token: token.clone(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tokio::spawn(async move { engine.run().await });
|
tokio::spawn(async move { engine.run().await });
|
||||||
@@ -210,7 +202,6 @@ impl TunnelHandler for ClientHandler {
|
|||||||
let (v_tx, mut v_rx) = mpsc::channel::<bytes::Bytes>(TCP_BUF_SIZE);
|
let (v_tx, mut v_rx) = mpsc::channel::<bytes::Bytes>(TCP_BUF_SIZE);
|
||||||
self.muxer.register_stream(stream_id, v_tx);
|
self.muxer.register_stream(stream_id, v_tx);
|
||||||
|
|
||||||
// Используем send_control для отправки FrameType::Connect
|
|
||||||
self.muxer
|
self.muxer
|
||||||
.send_control(
|
.send_control(
|
||||||
stream_id,
|
stream_id,
|
||||||
@@ -269,7 +260,6 @@ impl ServerHandler {
|
|||||||
let target_host = "ubuntu.com:443";
|
let target_host = "ubuntu.com:443";
|
||||||
info!(target = %target_host, "Stealth fallback: bridging to Target");
|
info!(target = %target_host, "Stealth fallback: bridging to Target");
|
||||||
|
|
||||||
// 1. Пытаемся подключиться с коротким таймаутом
|
|
||||||
let target_stream = tokio::time::timeout(
|
let target_stream = tokio::time::timeout(
|
||||||
std::time::Duration::from_secs(3),
|
std::time::Duration::from_secs(3),
|
||||||
TcpStream::connect(target_host),
|
TcpStream::connect(target_host),
|
||||||
@@ -277,10 +267,9 @@ impl ServerHandler {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
match target_stream {
|
match target_stream {
|
||||||
Ok(Ok(mut target_server)) => {
|
Ok(Ok(target_server)) => {
|
||||||
let (mut server_read, mut server_write) = target_server.into_split();
|
let (mut server_read, mut server_write) = target_server.into_split();
|
||||||
|
|
||||||
// 2. Скармливаем те байты, которые уже вычитали (Client Hello)
|
|
||||||
if !initial_data.is_empty() {
|
if !initial_data.is_empty() {
|
||||||
if let Err(e) = server_write.write_all(&initial_data).await {
|
if let Err(e) = server_write.write_all(&initial_data).await {
|
||||||
warn!("Failed to push initial data to fallback: {}", e);
|
warn!("Failed to push initial data to fallback: {}", e);
|
||||||
@@ -288,8 +277,6 @@ impl ServerHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Запускаем bidirectional copy
|
|
||||||
// Это создаст две задачи, которые будут перекачивать байты, пока одна сторона не закроется
|
|
||||||
let res = tokio::io::copy_bidirectional(
|
let res = tokio::io::copy_bidirectional(
|
||||||
&mut tokio::io::join(&mut client_inbound, &mut client_outbound),
|
&mut tokio::io::join(&mut client_inbound, &mut client_outbound),
|
||||||
&mut tokio::io::join(&mut server_read, &mut server_write),
|
&mut tokio::io::join(&mut server_read, &mut server_write),
|
||||||
@@ -345,7 +332,7 @@ impl TunnelHandler for ServerHandler {
|
|||||||
Ok(Err(e)) => return Err(e.to_string()),
|
Ok(Err(e)) => return Err(e.to_string()),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!("Handshake timeout. Going stealth.");
|
warn!("Handshake timeout. Going stealth.");
|
||||||
// Используем наш снимок, так как основной буфер мог быть частично съеден
|
|
||||||
ServerHandler::handle_stealth_fallback(
|
ServerHandler::handle_stealth_fallback(
|
||||||
self.conn.inbound,
|
self.conn.inbound,
|
||||||
self.conn.outbound,
|
self.conn.outbound,
|
||||||
@@ -358,7 +345,7 @@ impl TunnelHandler for ServerHandler {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Auth/Format failed: {:?}. Going stealth.", e);
|
warn!("Auth/Format failed: {:?}. Going stealth.", e);
|
||||||
// ВАЖНО: используем сохраненный buf_snapshot
|
|
||||||
info!(
|
info!(
|
||||||
"DEBUG: Restoring {} bytes from snapshot for fallback",
|
"DEBUG: Restoring {} bytes from snapshot for fallback",
|
||||||
buf_snapshot.len()
|
buf_snapshot.len()
|
||||||
@@ -375,7 +362,6 @@ impl TunnelHandler for ServerHandler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Если дошли сюда — значит это наш клиент, шлем Server Hello
|
|
||||||
self.conn
|
self.conn
|
||||||
.outbound
|
.outbound
|
||||||
.write_all(&hello)
|
.write_all(&hello)
|
||||||
@@ -392,7 +378,6 @@ impl TunnelHandler for ServerHandler {
|
|||||||
control_rx,
|
control_rx,
|
||||||
data_rx,
|
data_rx,
|
||||||
handler,
|
handler,
|
||||||
token: self.token,
|
|
||||||
}
|
}
|
||||||
.run()
|
.run()
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ pub struct TunnelEngine {
|
|||||||
pub control_rx: Receiver<MuxMessage>,
|
pub control_rx: Receiver<MuxMessage>,
|
||||||
pub data_rx: Receiver<MuxMessage>,
|
pub data_rx: Receiver<MuxMessage>,
|
||||||
pub handler: Arc<StreamHandler>,
|
pub handler: Arc<StreamHandler>,
|
||||||
pub token: CancellationToken,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TunnelEngine {
|
impl TunnelEngine {
|
||||||
@@ -33,25 +32,20 @@ impl TunnelEngine {
|
|||||||
let inbound = self.inbound;
|
let inbound = self.inbound;
|
||||||
let outbound = self.outbound;
|
let outbound = self.outbound;
|
||||||
|
|
||||||
// Оборачиваем кодек в потокобезопасный мьютекс
|
|
||||||
let codec = Arc::new(Mutex::new(self.codec));
|
let codec = Arc::new(Mutex::new(self.codec));
|
||||||
let read_buf = self.read_buf;
|
let read_buf = self.read_buf;
|
||||||
|
|
||||||
let control_rx = self.control_rx;
|
let control_rx = self.control_rx;
|
||||||
let data_rx = self.data_rx;
|
let data_rx = self.data_rx;
|
||||||
let handler = self.handler;
|
let handler = self.handler;
|
||||||
let token = self.token;
|
let token = CancellationToken::new();
|
||||||
|
|
||||||
// Клонируем Arc для независимых тасок
|
|
||||||
let codec_reader = codec.clone();
|
let codec_reader = codec.clone();
|
||||||
let codec_writer = codec.clone();
|
let codec_writer = codec.clone();
|
||||||
|
|
||||||
let token_reader = token.clone();
|
let token_reader = token.clone();
|
||||||
let token_writer = token.clone();
|
let token_writer = token.clone();
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// 1. READER TASK (Только чтение и расшифровка)
|
|
||||||
// ==========================================
|
|
||||||
let reader_handle = tokio::spawn(async move {
|
let reader_handle = tokio::spawn(async move {
|
||||||
let mut read_buf = read_buf;
|
let mut read_buf = read_buf;
|
||||||
let mut inbound = inbound;
|
let mut inbound = inbound;
|
||||||
@@ -65,23 +59,23 @@ impl TunnelEngine {
|
|||||||
res = inbound.read_buf(&mut read_buf) => {
|
res = inbound.read_buf(&mut read_buf) => {
|
||||||
let n = res.map_err(|e| e.to_string())?;
|
let n = res.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
// --- ИСПРАВЛЕННАЯ ЛОГИКА EOF ---
|
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
if read_buf.is_empty() {
|
if read_buf.is_empty() {
|
||||||
info!("Connection closed by peer (Clean EOF)");
|
info!("Connection closed by peer (Clean EOF)");
|
||||||
} else {
|
} else {
|
||||||
error!("Connection abruptly closed by peer (Incomplete frame: {} bytes left)", read_buf.len());
|
error!("Connection abruptly closed by peer (Incomplete frame: {} bytes left)", read_buf.len());
|
||||||
}
|
}
|
||||||
// ВЫХОДИМ В ЛЮБОМ СЛУЧАЕ, СОКЕТ МЕРТВ!
|
|
||||||
return Err::<(), String>("EOF".into());
|
return Err::<(), String>("EOF".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Вектор для фреймов. Мы расшифруем всё быстро,
|
|
||||||
// сложим сюда и отпустим лок Кодека.
|
|
||||||
let mut frames = Vec::new();
|
let mut frames = Vec::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
// Блокируем кодек только на время математики (расшифровки)
|
|
||||||
let mut c = codec_reader.lock().await;
|
let mut c = codec_reader.lock().await;
|
||||||
loop {
|
loop {
|
||||||
match c.inbound(&mut read_buf) {
|
match c.inbound(&mut read_buf) {
|
||||||
@@ -100,9 +94,9 @@ impl TunnelEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // Лок кодека отпущен!
|
}
|
||||||
|
|
||||||
|
|
||||||
// Обрабатываем фреймы (I/O) без лока, не мешая Writer Task
|
|
||||||
for frame in frames {
|
for frame in frames {
|
||||||
handler.handle(frame).await;
|
handler.handle(frame).await;
|
||||||
}
|
}
|
||||||
@@ -112,9 +106,6 @@ impl TunnelEngine {
|
|||||||
Ok::<(), String>(())
|
Ok::<(), String>(())
|
||||||
});
|
});
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// 2. WRITER TASK (Только шифрование и отправка)
|
|
||||||
// ==========================================
|
|
||||||
let writer_handle = tokio::spawn(async move {
|
let writer_handle = tokio::spawn(async move {
|
||||||
let mut outbound = outbound;
|
let mut outbound = outbound;
|
||||||
let mut control_rx = control_rx;
|
let mut control_rx = control_rx;
|
||||||
@@ -123,14 +114,14 @@ impl TunnelEngine {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
biased; // Приоритет сверху вниз
|
biased;
|
||||||
|
|
||||||
_ = token_writer.cancelled() => {
|
_ = token_writer.cancelled() => {
|
||||||
info!("Writer Task: Shutdown signal received.");
|
info!("Writer Task: Shutdown signal received.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FAST TRACK: Управляющие команды
|
|
||||||
msg_opt = control_rx.recv() => {
|
msg_opt = control_rx.recv() => {
|
||||||
if let Some(msg) = msg_opt {
|
if let Some(msg) = msg_opt {
|
||||||
Self::handle_outbound(&mut outbound, &codec_writer, msg).await?;
|
Self::handle_outbound(&mut outbound, &codec_writer, msg).await?;
|
||||||
@@ -139,13 +130,13 @@ impl TunnelEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Пинг
|
|
||||||
_ = heartbeat.tick() => {
|
_ = heartbeat.tick() => {
|
||||||
let msg = MuxMessage { stream_id: 0, frame_type: FrameType::Heartbeat, data: Bytes::new() };
|
let msg = MuxMessage { stream_id: 0, frame_type: FrameType::Heartbeat, data: Bytes::new() };
|
||||||
Self::handle_outbound(&mut outbound, &codec_writer, msg).await?;
|
Self::handle_outbound(&mut outbound, &codec_writer, msg).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SLOW TRACK: Данные
|
|
||||||
msg_opt = data_rx.recv() => {
|
msg_opt = data_rx.recv() => {
|
||||||
if let Some(msg) = msg_opt {
|
if let Some(msg) = msg_opt {
|
||||||
Self::handle_outbound(&mut outbound, &codec_writer, msg).await?;
|
Self::handle_outbound(&mut outbound, &codec_writer, msg).await?;
|
||||||
@@ -158,10 +149,6 @@ impl TunnelEngine {
|
|||||||
Ok::<(), String>(())
|
Ok::<(), String>(())
|
||||||
});
|
});
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// Ожидаем завершения обеих тасок.
|
|
||||||
// Если одна падает с ошибкой, убиваем туннель.
|
|
||||||
// ==========================================
|
|
||||||
let res = tokio::select! {
|
let res = tokio::select! {
|
||||||
res = reader_handle => res.unwrap_or_else(|e| Err(format!("Reader panic: {}", e))),
|
res = reader_handle => res.unwrap_or_else(|e| Err(format!("Reader panic: {}", e))),
|
||||||
res = writer_handle => res.unwrap_or_else(|e| Err(format!("Writer panic: {}", e))),
|
res = writer_handle => res.unwrap_or_else(|e| Err(format!("Writer panic: {}", e))),
|
||||||
@@ -185,11 +172,9 @@ impl TunnelEngine {
|
|||||||
let stream_id = msg.stream_id;
|
let stream_id = msg.stream_id;
|
||||||
let frame_type = msg.frame_type;
|
let frame_type = msg.frame_type;
|
||||||
|
|
||||||
// Вектор зашифрованных пакетов. Собираем их быстро под локом.
|
|
||||||
let mut packets = Vec::new();
|
let mut packets = Vec::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
// Берем лок кодека только для шифрования
|
|
||||||
let mut c = codec.lock().await;
|
let mut c = codec.lock().await;
|
||||||
|
|
||||||
if data.is_empty() {
|
if data.is_empty() {
|
||||||
@@ -214,10 +199,8 @@ impl TunnelEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // Лок кодека отпущен!
|
}
|
||||||
|
|
||||||
// Выполняем I/O операцию (которая может зависнуть при плохой сети) БЕЗ лока кодека.
|
|
||||||
// Это позволяет Reader Task продолжать читать сеть!
|
|
||||||
for pkt in packets {
|
for pkt in packets {
|
||||||
outbound.write_all(&pkt).await.map_err(|e| {
|
outbound.write_all(&pkt).await.map_err(|e| {
|
||||||
error!(stream_id, error = %e, "Failed to write encrypted data to network");
|
error!(stream_id, error = %e, "Failed to write encrypted data to network");
|
||||||
|
|||||||
@@ -54,12 +54,10 @@ impl Muxer {
|
|||||||
self.id_gen.next()
|
self.id_gen.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обычные данные летят в канал с низким приоритетом
|
|
||||||
pub async fn send_to_netwrok(&self, message: MuxMessage) -> Result<(), SendError<MuxMessage>> {
|
pub async fn send_to_netwrok(&self, message: MuxMessage) -> Result<(), SendError<MuxMessage>> {
|
||||||
self.data_tx.send(message).await
|
self.data_tx.send(message).await
|
||||||
}
|
}
|
||||||
|
|
||||||
// Управляющие фреймы летят в VIP-канал
|
|
||||||
pub async fn send_control(
|
pub async fn send_control(
|
||||||
&self,
|
&self,
|
||||||
stream_id: u32,
|
stream_id: u32,
|
||||||
@@ -96,7 +94,6 @@ impl Muxer {
|
|||||||
self.remove_stream(stream_id);
|
self.remove_stream(stream_id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Уменьшил уровень лога до TRACE, потому что это штатная ситуация при больших буферах!
|
|
||||||
netrunner_logger::trace!(
|
netrunner_logger::trace!(
|
||||||
stream_id,
|
stream_id,
|
||||||
len = data.len(),
|
len = data.len(),
|
||||||
|
|||||||
@@ -1,19 +1,8 @@
|
|||||||
use crate::{
|
use crate::proxy::connection::connection::{
|
||||||
protocol::errors::ErrorAction,
|
ClientHandler, Connection, ConnectionRole, ServerHandler, TunnelHandler,
|
||||||
proxy::connection::{
|
|
||||||
connection::{ClientHandler, Connection, ConnectionRole, ServerHandler, TunnelHandler},
|
|
||||||
engine::TunnelEngine,
|
|
||||||
muxer::Muxer,
|
|
||||||
MESSAGE_CHANNEL_SIZE,
|
|
||||||
},
|
|
||||||
tlseng::profile::BrowserProfile,
|
|
||||||
};
|
};
|
||||||
use bytes::BytesMut;
|
|
||||||
use netrunner_logger::{error, info};
|
use netrunner_logger::{error, info};
|
||||||
use tokio::{
|
use tokio::net::TcpListener;
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
|
||||||
net::{TcpListener, TcpStream},
|
|
||||||
};
|
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
pub struct Network {
|
pub struct Network {
|
||||||
@@ -49,7 +38,7 @@ impl Network {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or("No proxy addr")
|
.ok_or("No proxy addr")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let muxer = match ClientHandler::connect(server_addr, token.clone()).await {
|
let muxer = match ClientHandler::connect(server_addr).await {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!(error = %e, "Global tunnel failed.");
|
error!(error = %e, "Global tunnel failed.");
|
||||||
@@ -96,78 +85,4 @@ impl Network {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn initialize_client_tunnel(
|
|
||||||
&self,
|
|
||||||
token: CancellationToken,
|
|
||||||
) -> Result<Muxer, String> {
|
|
||||||
let server_addr = self.remote_proxy_addr.as_ref().ok_or("No proxy addr")?;
|
|
||||||
|
|
||||||
let stream = TcpStream::connect(server_addr)
|
|
||||||
.await
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
let (mut inbound, mut outbound) = stream.into_split();
|
|
||||||
|
|
||||||
let mut codec = crate::protocol::codec::codec::Codec::new(false);
|
|
||||||
|
|
||||||
let ch = codec
|
|
||||||
.make_client_handshake(&BrowserProfile::CHROME_131, "ubuntu.com")
|
|
||||||
.map_err(|e| format!("{:?}", e))?;
|
|
||||||
outbound.write_all(&ch).await.map_err(|e| e.to_string())?;
|
|
||||||
|
|
||||||
let mut sh_buf = BytesMut::with_capacity(2048);
|
|
||||||
loop {
|
|
||||||
match codec.process_handshake(&mut sh_buf) {
|
|
||||||
Ok(_) => break,
|
|
||||||
Err(e) if e.action == ErrorAction::Wait => {
|
|
||||||
let n = inbound
|
|
||||||
.read_buf(&mut sh_buf)
|
|
||||||
.await
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
if n == 0 {
|
|
||||||
return Err("EOF during handshake".into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => return Err(format!("TLS error: {:?}", e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- ИЗМЕНЕНИЯ ЗДЕСЬ: Создаем два канала ---
|
|
||||||
let (control_tx, control_rx) = tokio::sync::mpsc::channel(MESSAGE_CHANNEL_SIZE * 4);
|
|
||||||
let (data_tx, data_rx) = tokio::sync::mpsc::channel(MESSAGE_CHANNEL_SIZE * 4);
|
|
||||||
|
|
||||||
// Передаем оба трансмиттера в Muxer
|
|
||||||
let muxer = Muxer::new(control_tx, data_tx, true);
|
|
||||||
|
|
||||||
let handler = std::sync::Arc::new(crate::proxy::connection::handler::StreamHandler::new(
|
|
||||||
muxer.clone(),
|
|
||||||
ConnectionRole::Client,
|
|
||||||
));
|
|
||||||
|
|
||||||
let engine = TunnelEngine {
|
|
||||||
inbound,
|
|
||||||
outbound,
|
|
||||||
codec,
|
|
||||||
read_buf: sh_buf,
|
|
||||||
control_rx,
|
|
||||||
data_rx,
|
|
||||||
handler,
|
|
||||||
token,
|
|
||||||
};
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
|
||||||
if let Err(e) = engine.run().await {
|
|
||||||
netrunner_logger::error!(
|
|
||||||
"CRITICAL: Tunnel Engine died: {}. Restarting process...",
|
|
||||||
e
|
|
||||||
);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Ok(muxer)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_self_local_address(&self) -> String {
|
|
||||||
format!("127.0.0.1:{}", self.port)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user