stable connection
This commit is contained in:
+1
-1
@@ -77,7 +77,7 @@ impl SessionManager {
|
|||||||
cache_dir: String,
|
cache_dir: String,
|
||||||
) -> Arc<Session> {
|
) -> Arc<Session> {
|
||||||
netrunner_logger::Logger::init(None);
|
netrunner_logger::Logger::init(None);
|
||||||
netrunner_logger::Logger::global().set_level("info"); // Поменял на info для дебага
|
netrunner_logger::Logger::global().set_level("info");
|
||||||
|
|
||||||
let runtime = get_runtime();
|
let runtime = get_runtime();
|
||||||
let cancel_token = CancellationToken::new();
|
let cancel_token = CancellationToken::new();
|
||||||
|
|||||||
@@ -209,7 +209,6 @@ impl TcpConnection {
|
|||||||
tx_tunnel: mpsc::Sender<RawCastFrame>,
|
tx_tunnel: mpsc::Sender<RawCastFrame>,
|
||||||
) {
|
) {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
// 1. Формируем и отправляем кадр на установку соединения
|
|
||||||
let mut frame = RawCastFrame::connect(LocalProtocol::Tcp, socket_id, dst_ip, dst_port);
|
let mut frame = RawCastFrame::connect(LocalProtocol::Tcp, socket_id, dst_ip, dst_port);
|
||||||
frame.payload = Bytes::from(target);
|
frame.payload = Bytes::from(target);
|
||||||
|
|
||||||
@@ -218,10 +217,8 @@ impl TcpConnection {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Сигнализируем ConnectionManager, что запрос в туннель ушел успешно
|
|
||||||
let _ = handshake_tx.send(());
|
let _ = handshake_tx.send(());
|
||||||
|
|
||||||
// 3. Цикл пересылки данных из smoltcp -> туннель
|
|
||||||
while let Some(data) = rx_smol.recv().await {
|
while let Some(data) = rx_smol.recv().await {
|
||||||
let data_frame = RawCastFrame::data(
|
let data_frame = RawCastFrame::data(
|
||||||
LocalProtocol::Tcp,
|
LocalProtocol::Tcp,
|
||||||
@@ -232,7 +229,7 @@ impl TcpConnection {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if tx_tunnel.send(data_frame).await.is_err() {
|
if tx_tunnel.send(data_frame).await.is_err() {
|
||||||
break; // Туннель закрыт
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +325,6 @@ impl UdpConnection {
|
|||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
debug!("📡 [UDP {}] Task started for {}", socket_id, target);
|
debug!("📡 [UDP {}] Task started for {}", socket_id, target);
|
||||||
|
|
||||||
// 1. Регистрация UDP сессии в туннеле
|
|
||||||
let mut frame = RawCastFrame::connect(LocalProtocol::Udp, socket_id, dst_ip, dst_port);
|
let mut frame = RawCastFrame::connect(LocalProtocol::Udp, socket_id, dst_ip, dst_port);
|
||||||
frame.payload = Bytes::from(target);
|
frame.payload = Bytes::from(target);
|
||||||
|
|
||||||
@@ -337,8 +333,6 @@ impl UdpConnection {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Цикл пересылки пакетов
|
|
||||||
// rx_smol отдает кортеж (данные, ip, порт)
|
|
||||||
while let Some((data, ip, port)) = rx_smol.recv().await {
|
while let Some((data, ip, port)) = rx_smol.recv().await {
|
||||||
let data_frame =
|
let data_frame =
|
||||||
RawCastFrame::data(LocalProtocol::Udp, socket_id, ip, port, data.to_vec());
|
RawCastFrame::data(LocalProtocol::Udp, socket_id, ip, port, data.to_vec());
|
||||||
@@ -366,12 +360,9 @@ impl IcmpResponder {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Сначала достаем данные и адрес
|
|
||||||
let result = socket.recv();
|
let result = socket.recv();
|
||||||
|
|
||||||
if let Ok((data, src_addr)) = result {
|
if let Ok((data, src_addr)) = result {
|
||||||
// 2. Копируем данные в Vec, чтобы разорвать связь с буфером сокета.
|
|
||||||
// Теперь заимствование `socket` от метода .recv() закончилось.
|
|
||||||
let payload = data.to_vec();
|
let payload = data.to_vec();
|
||||||
|
|
||||||
match src_addr {
|
match src_addr {
|
||||||
@@ -381,7 +372,6 @@ impl IcmpResponder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Принимаем Vec<u8>, чтобы не делать to_vec() второй раз внутри
|
|
||||||
fn reply_v4(socket: &mut icmp::Socket, mut payload: Vec<u8>, src: IpAddress) {
|
fn reply_v4(socket: &mut icmp::Socket, mut payload: Vec<u8>, src: IpAddress) {
|
||||||
if let Ok(pkt) = Icmpv4Packet::new_checked(&payload) {
|
if let Ok(pkt) = Icmpv4Packet::new_checked(&payload) {
|
||||||
if pkt.msg_type() == Icmpv4Message::EchoRequest {
|
if pkt.msg_type() == Icmpv4Message::EchoRequest {
|
||||||
|
|||||||
@@ -162,7 +162,6 @@ impl DnsHandler {
|
|||||||
.set_recursion_available(true)
|
.set_recursion_available(true)
|
||||||
.add_query(query.clone());
|
.add_query(query.clone());
|
||||||
|
|
||||||
// 1. Проверка блокировок
|
|
||||||
if self.forbidden_suffixes.iter().any(|s| name.ends_with(s))
|
if self.forbidden_suffixes.iter().any(|s| name.ends_with(s))
|
||||||
|| self.block_list.contains(&name)
|
|| self.block_list.contains(&name)
|
||||||
{
|
{
|
||||||
@@ -171,7 +170,6 @@ impl DnsHandler {
|
|||||||
return res.to_vec().ok();
|
return res.to_vec().ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Генерация Fake IP для A-записей
|
|
||||||
if query.query_type() == RecordType::A {
|
if query.query_type() == RecordType::A {
|
||||||
let fake_ip = store.get_or_assign(&name);
|
let fake_ip = store.get_or_assign(&name);
|
||||||
res.add_answer(Record::from_rdata(
|
res.add_answer(Record::from_rdata(
|
||||||
@@ -181,7 +179,6 @@ impl DnsHandler {
|
|||||||
));
|
));
|
||||||
res.set_response_code(ResponseCode::NoError);
|
res.set_response_code(ResponseCode::NoError);
|
||||||
} else {
|
} else {
|
||||||
// Для остальных типов записей (AAAA и т.д.) просто возвращаем пустой NoError или NXDomain
|
|
||||||
res.set_response_code(ResponseCode::NoError);
|
res.set_response_code(ResponseCode::NoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ impl EngineConfig {
|
|||||||
pub struct EngineBuilder {
|
pub struct EngineBuilder {
|
||||||
config: EngineConfig,
|
config: EngineConfig,
|
||||||
tun_device: Option<Tun>,
|
tun_device: Option<Tun>,
|
||||||
// Добавляем возможность прокинуть кастомную фабрику сокетов
|
|
||||||
socket_factory: Option<Arc<dyn SocketProvider>>,
|
socket_factory: Option<Arc<dyn SocketProvider>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,13 +344,10 @@ impl EngineBuilder {
|
|||||||
.map_err(|e| format!("Failed to establish secure tunnel: {}", e))?;
|
.map_err(|e| format!("Failed to establish secure tunnel: {}", e))?;
|
||||||
|
|
||||||
let factory = self.socket_factory.unwrap_or_else(|| {
|
let factory = self.socket_factory.unwrap_or_else(|| {
|
||||||
// 1. Разыменовываем ссылку и клонируем данные в новый объект
|
|
||||||
let config_owned = (*NetworkConfig::global()).clone();
|
let config_owned = (*NetworkConfig::global()).clone();
|
||||||
|
|
||||||
// 2. Оборачиваем во владеющий Arc
|
|
||||||
let config = Arc::new(config_owned);
|
let config = Arc::new(config_owned);
|
||||||
|
|
||||||
// Теперь типы совпадают: Arc<NetworkConfig> -> SmolSocketFactory::new
|
|
||||||
Arc::new(SmolSocketFactory::new(config))
|
Arc::new(SmolSocketFactory::new(config))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ pub struct SessionTracker {
|
|||||||
active_udp: HashMap<SocketHandle, UdpConnection>,
|
active_udp: HashMap<SocketHandle, UdpConnection>,
|
||||||
inbound_tx: HashMap<u64, mpsc::Sender<Bytes>>,
|
inbound_tx: HashMap<u64, mpsc::Sender<Bytes>>,
|
||||||
handle_to_id: HashMap<SocketHandle, u64>,
|
handle_to_id: HashMap<SocketHandle, u64>,
|
||||||
// 🔥 ДОБАВЛЕНО: Обратный маппинг, чтобы находить сокет по ID из туннеля
|
|
||||||
id_to_handle: HashMap<u64, SocketHandle>,
|
id_to_handle: HashMap<u64, SocketHandle>,
|
||||||
pending_tcp: HashMap<SocketHandle, StdInstant>,
|
pending_tcp: HashMap<SocketHandle, StdInstant>,
|
||||||
to_remove: Vec<SocketHandle>,
|
to_remove: Vec<SocketHandle>,
|
||||||
@@ -34,7 +34,7 @@ impl SessionTracker {
|
|||||||
active_udp: HashMap::new(),
|
active_udp: HashMap::new(),
|
||||||
inbound_tx: HashMap::new(),
|
inbound_tx: HashMap::new(),
|
||||||
handle_to_id: HashMap::new(),
|
handle_to_id: HashMap::new(),
|
||||||
id_to_handle: HashMap::new(), // Инициализация
|
id_to_handle: HashMap::new(),
|
||||||
pending_tcp: HashMap::new(),
|
pending_tcp: HashMap::new(),
|
||||||
to_remove: Vec::new(),
|
to_remove: Vec::new(),
|
||||||
next_socket_id: 1,
|
next_socket_id: 1,
|
||||||
@@ -60,10 +60,10 @@ impl SessionTracker {
|
|||||||
) {
|
) {
|
||||||
self.pending_tcp.remove(&handle);
|
self.pending_tcp.remove(&handle);
|
||||||
self.handle_to_id.insert(handle, id);
|
self.handle_to_id.insert(handle, id);
|
||||||
self.id_to_handle.insert(id, handle); // 🔥 Регистрация обратного индекса
|
self.id_to_handle.insert(id, handle);
|
||||||
self.active_tcp.insert(handle, conn);
|
self.active_tcp.insert(handle, conn);
|
||||||
self.inbound_tx.insert(id, tx);
|
self.inbound_tx.insert(id, tx);
|
||||||
self.last_activity.insert(handle, StdInstant::now()); // Для TCP тоже полезно
|
self.last_activity.insert(handle, StdInstant::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_udp(
|
pub fn register_udp(
|
||||||
@@ -74,7 +74,7 @@ impl SessionTracker {
|
|||||||
tx: mpsc::Sender<Bytes>,
|
tx: mpsc::Sender<Bytes>,
|
||||||
) {
|
) {
|
||||||
self.handle_to_id.insert(handle, id);
|
self.handle_to_id.insert(handle, id);
|
||||||
self.id_to_handle.insert(id, handle); // 🔥 Регистрация обратного индекса
|
self.id_to_handle.insert(id, handle);
|
||||||
self.active_udp.insert(handle, conn);
|
self.active_udp.insert(handle, conn);
|
||||||
self.inbound_tx.insert(id, tx);
|
self.inbound_tx.insert(id, tx);
|
||||||
self.last_activity.insert(handle, StdInstant::now());
|
self.last_activity.insert(handle, StdInstant::now());
|
||||||
@@ -128,7 +128,7 @@ impl SessionTracker {
|
|||||||
|
|
||||||
pub fn close_tunnel_session(&mut self, id: u64) {
|
pub fn close_tunnel_session(&mut self, id: u64) {
|
||||||
self.inbound_tx.remove(&id);
|
self.inbound_tx.remove(&id);
|
||||||
// 🔥 ИСПРАВЛЕНО: Теперь мы реально находим сокет и ставим его в очередь на удаление
|
|
||||||
if let Some(handle) = self.id_to_handle.remove(&id) {
|
if let Some(handle) = self.id_to_handle.remove(&id) {
|
||||||
self.queue_removal(handle);
|
self.queue_removal(handle);
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,6 @@ impl SessionTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔥 ДОБАВЛЕНО: Сборщик мусора для залипших сокетов
|
|
||||||
pub fn enforce_idle_timeouts(&mut self, timeout: Duration) {
|
pub fn enforce_idle_timeouts(&mut self, timeout: Duration) {
|
||||||
let now = StdInstant::now();
|
let now = StdInstant::now();
|
||||||
let mut ghosts = Vec::new();
|
let mut ghosts = Vec::new();
|
||||||
@@ -159,8 +158,6 @@ impl SessionTracker {
|
|||||||
|
|
||||||
pub fn cleanup(&mut self, socket_set: &mut SocketSet) {
|
pub fn cleanup(&mut self, socket_set: &mut SocketSet) {
|
||||||
for handle in self.to_remove.drain(..) {
|
for handle in self.to_remove.drain(..) {
|
||||||
// Удаление из socket_set автоматически делает abort() внутри smoltcp
|
|
||||||
// и освобождает память пула/буферов
|
|
||||||
socket_set.remove(handle);
|
socket_set.remove(handle);
|
||||||
|
|
||||||
self.active_tcp.remove(&handle);
|
self.active_tcp.remove(&handle);
|
||||||
|
|||||||
@@ -46,17 +46,15 @@ impl SmolSocketFactory {
|
|||||||
pub fn new(config: Arc<NetworkConfig>) -> Self {
|
pub fn new(config: Arc<NetworkConfig>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
config,
|
config,
|
||||||
// Пул на 128 тяжелых буферов. Если нужно больше — queue вернет ошибку,
|
|
||||||
// и мы просто отдадим память ОС (что безопасно).
|
|
||||||
heavy_pool: Arc::new(ArrayQueue::new(128)),
|
heavy_pool: Arc::new(ArrayQueue::new(128)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Берем буфер из пула или создаем новый, если пул пуст
|
|
||||||
fn alloc_buf(&self, size: usize) -> Vec<u8> {
|
fn alloc_buf(&self, size: usize) -> Vec<u8> {
|
||||||
if size == self.config.tcp_buf_heavy {
|
if size == self.config.tcp_buf_heavy {
|
||||||
if let Some(mut buf) = self.heavy_pool.pop() {
|
if let Some(mut buf) = self.heavy_pool.pop() {
|
||||||
buf.fill(0); // Очищаем данные от прошлой сессии
|
buf.fill(0);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,7 +142,7 @@ impl SocketProvider for SmolSocketFactory {
|
|||||||
|
|
||||||
fn create_base_set(&self, n_icmp: usize) -> SocketSet<'static> {
|
fn create_base_set(&self, n_icmp: usize) -> SocketSet<'static> {
|
||||||
let mut sockets = SocketSet::new(Vec::with_capacity(128));
|
let mut sockets = SocketSet::new(Vec::with_capacity(128));
|
||||||
sockets.add(self.create_bound_udp(None, 53)); // DNS
|
sockets.add(self.create_bound_udp(None, 53));
|
||||||
for _ in 0..n_icmp {
|
for _ in 0..n_icmp {
|
||||||
sockets.add(self.create_icmp());
|
sockets.add(self.create_icmp());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ impl NetworkConfig {
|
|||||||
tcp_buffer_size: 8 * 1024,
|
tcp_buffer_size: 8 * 1024,
|
||||||
udp_buffer_size: 64 * 1024,
|
udp_buffer_size: 64 * 1024,
|
||||||
|
|
||||||
muxer_capacity: 256,
|
muxer_capacity: 64,
|
||||||
tcp_stream_capacity: 32,
|
tcp_stream_capacity: 8,
|
||||||
udp_stream_capacity: 128,
|
udp_stream_capacity: 32,
|
||||||
|
|
||||||
smoltcp_socket_buf: heavy_buf,
|
smoltcp_socket_buf: heavy_buf,
|
||||||
tcp_chunk_size: chunk_size,
|
tcp_chunk_size: chunk_size,
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ pub(crate) async fn run_tcp_bridge<R, W>(
|
|||||||
data: buf.split().freeze(),
|
data: buf.split().freeze(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if muxer.send_to_network(msg).is_err() {
|
if muxer.send_to_network(msg).await.is_err() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
@@ -139,7 +139,7 @@ pub(crate) async fn run_udp_bridge(
|
|||||||
match res {
|
match res {
|
||||||
Ok(n) if n > 0 => {
|
Ok(n) if n > 0 => {
|
||||||
let data = Bytes::copy_from_slice(&buf[..n]);
|
let data = Bytes::copy_from_slice(&buf[..n]);
|
||||||
if let Err(e) = muxer.send_data_safe(stream_id, data, true) {
|
if let Err(e) = muxer.send_data_safe(stream_id, data, true).await {
|
||||||
error!(stream_id, "UDP Failed to send to tunnel: {}", e);
|
error!(stream_id, "UDP Failed to send to tunnel: {}", e);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,11 +89,9 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Измененный контекст: теперь храним оригинальный (локальный) socket_id
|
|
||||||
type StreamContext = (u32, Ipv4Addr, u16, LocalProtocol);
|
type StreamContext = (u32, Ipv4Addr, u16, LocalProtocol);
|
||||||
|
|
||||||
pub struct ClientHandler;
|
pub struct ClientHandler;
|
||||||
|
|
||||||
impl ClientHandler {
|
impl ClientHandler {
|
||||||
async fn establish_leg(
|
async fn establish_leg(
|
||||||
remote_proxy_addr: &str,
|
remote_proxy_addr: &str,
|
||||||
@@ -197,9 +195,7 @@ impl ClientHandler {
|
|||||||
|
|
||||||
let muxer = Arc::new(Muxer::new(true, session_id.clone()));
|
let muxer = Arc::new(Muxer::new(true, session_id.clone()));
|
||||||
|
|
||||||
// Реестр для отправки данных обратно в виртуальный сетевой стек
|
|
||||||
let registry: Arc<DashMap<u32, StreamContext>> = Arc::new(DashMap::new());
|
let registry: Arc<DashMap<u32, StreamContext>> = Arc::new(DashMap::new());
|
||||||
// Мапа для трансляции: локальный socket_id -> глобальный stream_id
|
|
||||||
let local_to_global: Arc<DashMap<u32, u32>> = Arc::new(DashMap::new());
|
let local_to_global: Arc<DashMap<u32, u32>> = Arc::new(DashMap::new());
|
||||||
|
|
||||||
info!("🚀 Netrunner Multi-Path Tunnel Initializing (10 Legs max).");
|
info!("🚀 Netrunner Multi-Path Tunnel Initializing (10 Legs max).");
|
||||||
@@ -228,10 +224,7 @@ impl ClientHandler {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔥 ЗАПУСК HEALTH CHECK: Пингуем все леги
|
|
||||||
m_stats.perform_health_check().await;
|
m_stats.perform_health_check().await;
|
||||||
|
|
||||||
// После пинга выводим красивую топологию
|
|
||||||
m_stats.print_topology_tree();
|
m_stats.print_topology_tree();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -239,21 +232,18 @@ impl ClientHandler {
|
|||||||
let muxer_inner = muxer.clone();
|
let muxer_inner = muxer.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while let Some(raw_frame) = rx_from_engine.recv().await {
|
while let Some(raw_frame) = rx_from_engine.recv().await {
|
||||||
// Извлекаем нужные метаданные до передачи во фрейм
|
|
||||||
let dst_ip = raw_frame.dst_ip;
|
let dst_ip = raw_frame.dst_ip;
|
||||||
let dst_port = raw_frame.dst_port;
|
let dst_port = raw_frame.dst_port;
|
||||||
let protocol = raw_frame.protocol;
|
let protocol = raw_frame.protocol;
|
||||||
let is_udp = protocol == LocalProtocol::Udp;
|
let is_udp = protocol == LocalProtocol::Udp;
|
||||||
|
|
||||||
if let Ok(nrxp_frame) = RawCastAdapter::to_nrxp(raw_frame) {
|
if let Ok(nrxp_frame) = RawCastAdapter::to_nrxp(raw_frame) {
|
||||||
// Адаптер кладет socket_id от smoltcp в заголовок stream_id
|
|
||||||
let local_socket_id = nrxp_frame.header.stream_id;
|
let local_socket_id = nrxp_frame.header.stream_id;
|
||||||
let f_type = nrxp_frame.header.frame_type;
|
let f_type = nrxp_frame.header.frame_type;
|
||||||
let payload = nrxp_frame.payload;
|
let payload = nrxp_frame.payload;
|
||||||
|
|
||||||
match f_type {
|
match f_type {
|
||||||
FrameType::Connect | FrameType::UdpConnect => {
|
FrameType::Connect | FrameType::UdpConnect => {
|
||||||
// 🔥 ШАГ 2: Выделяем глобальный ID для нового потока
|
|
||||||
let global_stream_id = muxer_inner.next_stream_id();
|
let global_stream_id = muxer_inner.next_stream_id();
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
@@ -264,7 +254,6 @@ impl ClientHandler {
|
|||||||
global_stream_id
|
global_stream_id
|
||||||
);
|
);
|
||||||
|
|
||||||
// Запоминаем связь
|
|
||||||
local_to_global.insert(local_socket_id, global_stream_id);
|
local_to_global.insert(local_socket_id, global_stream_id);
|
||||||
registry.insert(
|
registry.insert(
|
||||||
global_stream_id,
|
global_stream_id,
|
||||||
@@ -274,7 +263,6 @@ impl ClientHandler {
|
|||||||
let (v_tx, mut v_rx) =
|
let (v_tx, mut v_rx) =
|
||||||
mpsc::channel(NetworkConfig::global().tcp_stream_capacity);
|
mpsc::channel(NetworkConfig::global().tcp_stream_capacity);
|
||||||
|
|
||||||
// Регистрируем локальный поток под глобальным ID
|
|
||||||
muxer_inner.register_stream(global_stream_id, v_tx);
|
muxer_inner.register_stream(global_stream_id, v_tx);
|
||||||
|
|
||||||
let tx_to_tun = tx_to_engine.clone();
|
let tx_to_tun = tx_to_engine.clone();
|
||||||
@@ -282,16 +270,16 @@ impl ClientHandler {
|
|||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while let Some(back_payload) = v_rx.recv().await {
|
while let Some(back_payload) = v_rx.recv().await {
|
||||||
if let Some(ctx) = reg.get(&global_stream_id) {
|
// ✅ ИСПРАВЛЕНИЕ 1: Копируем данные и отпускаем DashMap до .await
|
||||||
let (orig_local_id, ip, port, proto) = *ctx;
|
let ctx = reg.get(&global_stream_id).map(|r| *r);
|
||||||
|
|
||||||
|
if let Some((orig_local_id, ip, port, proto)) = ctx {
|
||||||
let out_f_type = if proto == LocalProtocol::Udp {
|
let out_f_type = if proto == LocalProtocol::Udp {
|
||||||
FrameType::UdpData
|
FrameType::UdpData
|
||||||
} else {
|
} else {
|
||||||
FrameType::Data
|
FrameType::Data
|
||||||
};
|
};
|
||||||
|
|
||||||
// Оборачиваем обратно в оригинальный локальный ID,
|
|
||||||
// чтобы smoltcp и tun-адаптер поняли, кому это принадлежит
|
|
||||||
let mock_nrxp =
|
let mock_nrxp =
|
||||||
Frame::new(orig_local_id, out_f_type, back_payload);
|
Frame::new(orig_local_id, out_f_type, back_payload);
|
||||||
|
|
||||||
@@ -307,14 +295,19 @@ impl ClientHandler {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let _ = muxer_inner.send_control(global_stream_id, f_type, payload);
|
// ✅ Добавлен .await
|
||||||
|
let _ = muxer_inner
|
||||||
|
.send_control(global_stream_id, f_type, payload)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
FrameType::Data | FrameType::UdpData => {
|
FrameType::Data | FrameType::UdpData => {
|
||||||
// Ищем глобальный ID по локальному
|
// ✅ ИСПРАВЛЕНИЕ 2: Сброс блокировки DashMap
|
||||||
if let Some(global_ref) = local_to_global.get(&local_socket_id) {
|
let global_stream_id =
|
||||||
let global_stream_id = *global_ref;
|
local_to_global.get(&local_socket_id).map(|r| *r);
|
||||||
let _ =
|
|
||||||
muxer_inner.send_data_safe(global_stream_id, payload, is_udp);
|
if let Some(id) = global_stream_id {
|
||||||
|
// ✅ Добавлен .await
|
||||||
|
let _ = muxer_inner.send_data_safe(id, payload, is_udp).await;
|
||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
"Data received for unknown local socket_id: {}",
|
"Data received for unknown local socket_id: {}",
|
||||||
@@ -323,14 +316,16 @@ impl ClientHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
FrameType::Close => {
|
FrameType::Close => {
|
||||||
|
// .remove() сам по себе возвращает владение данными и снимает лок мгновенно,
|
||||||
|
// поэтому здесь дедлока не было, но мы добавляем .await для вызова Муксера.
|
||||||
if let Some((_, global_stream_id)) =
|
if let Some((_, global_stream_id)) =
|
||||||
local_to_global.remove(&local_socket_id)
|
local_to_global.remove(&local_socket_id)
|
||||||
{
|
{
|
||||||
let _ = muxer_inner.send_control(
|
// ✅ Добавлен .await
|
||||||
global_stream_id,
|
let _ = muxer_inner
|
||||||
FrameType::Close,
|
.send_control(global_stream_id, FrameType::Close, Bytes::new())
|
||||||
Bytes::new(),
|
.await;
|
||||||
);
|
|
||||||
muxer_inner.remove_stream(global_stream_id);
|
muxer_inner.remove_stream(global_stream_id);
|
||||||
registry.remove(&global_stream_id);
|
registry.remove(&global_stream_id);
|
||||||
}
|
}
|
||||||
@@ -346,7 +341,6 @@ impl ClientHandler {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ServerHandler {
|
pub struct ServerHandler {
|
||||||
pub(crate) conn: Connection,
|
pub(crate) conn: Connection,
|
||||||
pub(crate) session_manager: Arc<SessionManager>,
|
pub(crate) session_manager: Arc<SessionManager>,
|
||||||
@@ -414,7 +408,6 @@ impl TunnelHandler for ServerHandler {
|
|||||||
|
|
||||||
let handshake_timeout = std::time::Duration::from_secs(1);
|
let handshake_timeout = std::time::Duration::from_secs(1);
|
||||||
|
|
||||||
// 1. ФАЗА TLS HANDSHAKE
|
|
||||||
let hello = loop {
|
let hello = loop {
|
||||||
let buf_snapshot = self.conn.read_buf.clone().freeze();
|
let buf_snapshot = self.conn.read_buf.clone().freeze();
|
||||||
match self
|
match self
|
||||||
@@ -423,9 +416,7 @@ impl TunnelHandler for ServerHandler {
|
|||||||
.make_server_handshake(&mut self.conn.read_buf)
|
.make_server_handshake(&mut self.conn.read_buf)
|
||||||
{
|
{
|
||||||
Ok(b) => break b,
|
Ok(b) => break b,
|
||||||
Err(e) => {
|
Err(e) => match e.execute_strategy() {
|
||||||
// 🔥 ВЫЗЫВАЕМ СТРАТЕГИЮ (Она заодно и залогирует ошибку)
|
|
||||||
match e.execute_strategy() {
|
|
||||||
ErrorAction::Wait => {
|
ErrorAction::Wait => {
|
||||||
let res = tokio::time::timeout(
|
let res = tokio::time::timeout(
|
||||||
handshake_timeout,
|
handshake_timeout,
|
||||||
@@ -437,8 +428,6 @@ impl TunnelHandler for ServerHandler {
|
|||||||
Ok(Ok(0)) => return Err("Client closed".into()),
|
Ok(Ok(0)) => return Err("Client closed".into()),
|
||||||
Ok(Ok(_)) => continue,
|
Ok(Ok(_)) => continue,
|
||||||
_ => {
|
_ => {
|
||||||
// По таймауту тоже редиректим, так как сканеры часто
|
|
||||||
// присылают пол-пакета и "висят"
|
|
||||||
Self::handle_stealth_fallback(
|
Self::handle_stealth_fallback(
|
||||||
self.conn.inbound,
|
self.conn.inbound,
|
||||||
self.conn.outbound,
|
self.conn.outbound,
|
||||||
@@ -450,7 +439,6 @@ impl TunnelHandler for ServerHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ErrorAction::Redirect => {
|
ErrorAction::Redirect => {
|
||||||
// Пришел валидный TLS пакет, но от чужака -> притворяемся сайтом
|
|
||||||
Self::handle_stealth_fallback(
|
Self::handle_stealth_fallback(
|
||||||
self.conn.inbound,
|
self.conn.inbound,
|
||||||
self.conn.outbound,
|
self.conn.outbound,
|
||||||
@@ -460,22 +448,18 @@ impl TunnelHandler for ServerHandler {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
ErrorAction::Drop => {
|
ErrorAction::Drop => {
|
||||||
// Полный мусор, отключаем немедленно (экономим сокеты ОС)
|
|
||||||
return Err("Dropped by security strategy (TLS Phase)".into());
|
return Err("Dropped by security strategy (TLS Phase)".into());
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Отвечаем ServerHello
|
|
||||||
self.conn
|
self.conn
|
||||||
.outbound
|
.outbound
|
||||||
.write_all(&hello)
|
.write_all(&hello)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
// 2. ФАЗА NETRUNNER HANDSHAKE (Внутри туннеля)
|
|
||||||
let (session_id, leg_id) = loop {
|
let (session_id, leg_id) = loop {
|
||||||
let n = tokio::time::timeout(
|
let n = tokio::time::timeout(
|
||||||
std::time::Duration::from_secs(3),
|
std::time::Duration::from_secs(3),
|
||||||
@@ -513,17 +497,15 @@ impl TunnelHandler for ServerHandler {
|
|||||||
let buf_snapshot = self.conn.read_buf.clone().freeze();
|
let buf_snapshot = self.conn.read_buf.clone().freeze();
|
||||||
match e.execute_strategy() {
|
match e.execute_strategy() {
|
||||||
ErrorAction::Redirect => {
|
ErrorAction::Redirect => {
|
||||||
// Если мы решаем прятать VPN даже на уровне неудачной криптографии
|
|
||||||
Self::handle_stealth_fallback(
|
Self::handle_stealth_fallback(
|
||||||
self.conn.inbound,
|
self.conn.inbound,
|
||||||
self.conn.outbound,
|
self.conn.outbound,
|
||||||
buf_snapshot, // Отправляем зашифрованный мусор на целевой сервак (он сам его дропнет)
|
buf_snapshot,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Wait или Drop на этапе Handshake лучше просто дропать
|
|
||||||
return Err("Dropped by security strategy (Auth Phase)".into());
|
return Err("Dropped by security strategy (Auth Phase)".into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -531,7 +513,6 @@ impl TunnelHandler for ServerHandler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ... Инициализация Muxer и TunnelEngine (остается без изменений)
|
|
||||||
let muxer = self.session_manager.get_or_create(&session_id);
|
let muxer = self.session_manager.get_or_create(&session_id);
|
||||||
|
|
||||||
let (control_tx, control_rx) = mpsc::channel(NetworkConfig::global().muxer_capacity);
|
let (control_tx, control_rx) = mpsc::channel(NetworkConfig::global().muxer_capacity);
|
||||||
|
|||||||
@@ -185,7 +185,6 @@ impl TunnelEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TCP - потоковый, режем на чанки по 16KB для совместимости с TLS Record
|
|
||||||
while !data.is_empty() {
|
while !data.is_empty() {
|
||||||
let chunk_size =
|
let chunk_size =
|
||||||
std::cmp::min(data.len(), NetworkConfig::global().tcp_chunk_size);
|
std::cmp::min(data.len(), NetworkConfig::global().tcp_chunk_size);
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ use crate::net::{
|
|||||||
};
|
};
|
||||||
use crate::nrxp::{Frame, FrameType};
|
use crate::nrxp::{Frame, FrameType};
|
||||||
|
|
||||||
// --- ОТКРЫВАШКА ДЛЯ СЕРВЕРА (Remote) ---
|
|
||||||
// Этот парень реально идет в интернет через сокеты ОС
|
|
||||||
pub struct RemoteOpener {
|
pub struct RemoteOpener {
|
||||||
pub muxer: Arc<Muxer>,
|
pub muxer: Arc<Muxer>,
|
||||||
}
|
}
|
||||||
@@ -63,11 +61,9 @@ impl RemoteOpener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- ЕДИНЫЙ ХЭНДЛЕР ---
|
|
||||||
|
|
||||||
pub(crate) struct StreamHandler {
|
pub(crate) struct StreamHandler {
|
||||||
muxer: Arc<Muxer>,
|
muxer: Arc<Muxer>,
|
||||||
opener: Option<Arc<RemoteOpener>>, // На сервере Some, на клиенте None
|
opener: Option<Arc<RemoteOpener>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StreamHandler {
|
impl StreamHandler {
|
||||||
@@ -89,8 +85,7 @@ impl StreamHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FrameType::Data | FrameType::UdpData => {
|
FrameType::Data | FrameType::UdpData => {
|
||||||
// Унифицировано: просто кидаем в локальный канал
|
self.muxer.dispatch_to_local(stream_id, frame.payload).await;
|
||||||
self.muxer.dispatch_to_local(stream_id, frame.payload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameType::Close => {
|
FrameType::Close => {
|
||||||
@@ -105,7 +100,6 @@ impl StreamHandler {
|
|||||||
let target = String::from_utf8_lossy(&payload).to_string();
|
let target = String::from_utf8_lossy(&payload).to_string();
|
||||||
|
|
||||||
if let Some(opener) = &self.opener {
|
if let Some(opener) = &self.opener {
|
||||||
// Создаем виртуальную трубу для этого стрима
|
|
||||||
let capacity = if is_udp {
|
let capacity = if is_udp {
|
||||||
NetworkConfig::global().udp_stream_capacity
|
NetworkConfig::global().udp_stream_capacity
|
||||||
} else {
|
} else {
|
||||||
@@ -125,7 +119,7 @@ impl StreamHandler {
|
|||||||
stream_id,
|
stream_id,
|
||||||
"⚠️ [Tunnel] Rejected incoming connection to {} (Client mode)", target
|
"⚠️ [Tunnel] Rejected incoming connection to {} (Client mode)", target
|
||||||
);
|
);
|
||||||
// Если мы клиент, мы не принимаем входящие соединения из туннеля
|
|
||||||
let _ = self
|
let _ = self
|
||||||
.muxer
|
.muxer
|
||||||
.send_control(stream_id, FrameType::Close, Bytes::new());
|
.send_control(stream_id, FrameType::Close, Bytes::new());
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use netrunner_logger::{debug, info, warn};
|
use netrunner_logger::{debug, info, warn};
|
||||||
use tokio::sync::mpsc::error::TrySendError;
|
|
||||||
use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::mpsc::error::TrySendError;
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
|
|
||||||
use crate::nrxp::FrameType;
|
use crate::nrxp::FrameType;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct LegStats {
|
pub struct LegStats {
|
||||||
pub tx_bytes: AtomicU64,
|
pub tx_bytes: AtomicU64,
|
||||||
@@ -59,9 +58,7 @@ pub struct Muxer {
|
|||||||
id_gen: Arc<IdGenerator>,
|
id_gen: Arc<IdGenerator>,
|
||||||
session_id: Arc<String>,
|
session_id: Arc<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Muxer {
|
impl Muxer {
|
||||||
|
|
||||||
pub fn new(is_client: bool, session_id: String) -> Self {
|
pub fn new(is_client: bool, session_id: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
legs: Arc::new(DashMap::new()),
|
legs: Arc::new(DashMap::new()),
|
||||||
@@ -77,7 +74,6 @@ impl Muxer {
|
|||||||
control_tx: Sender<MuxMessage>,
|
control_tx: Sender<MuxMessage>,
|
||||||
data_tx: Sender<MuxMessage>,
|
data_tx: Sender<MuxMessage>,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
if self.legs.len() >= 10 {
|
if self.legs.len() >= 10 {
|
||||||
warn!(
|
warn!(
|
||||||
leg_id,
|
leg_id,
|
||||||
@@ -113,43 +109,40 @@ impl Muxer {
|
|||||||
|
|
||||||
let is_udp = matches!(frame_type, FrameType::UdpData | FrameType::UdpConnect);
|
let is_udp = matches!(frame_type, FrameType::UdpData | FrameType::UdpConnect);
|
||||||
|
|
||||||
|
let mut candidates: Vec<(u32, MuxLeg)> = self
|
||||||
let mut candidates: Vec<(u32, MuxLeg)> = self.legs
|
.legs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|kv| (*kv.key(), kv.value().clone()))
|
.map(|kv| (*kv.key(), kv.value().clone()))
|
||||||
.filter(|(id, _)| {
|
.filter(|(id, _)| if is_udp { id % 2 != 0 } else { id % 2 == 0 })
|
||||||
|
|
||||||
if is_udp { id % 2 != 0 } else { id % 2 == 0 }
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
||||||
if candidates.is_empty() {
|
if candidates.is_empty() {
|
||||||
candidates = self.legs.iter().map(|kv| (*kv.key(), kv.value().clone())).collect();
|
candidates = self
|
||||||
|
.legs
|
||||||
|
.iter()
|
||||||
|
.map(|kv| (*kv.key(), kv.value().clone()))
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
candidates.sort_by_key(|(_, leg)| {
|
candidates.sort_by_key(|(_, leg)| {
|
||||||
let rtt = leg.stats.rtt_ms.load(Ordering::Relaxed);
|
let rtt = leg.stats.rtt_ms.load(Ordering::Relaxed);
|
||||||
if rtt == 0 { 9999 } else { rtt }
|
if rtt == 0 {
|
||||||
|
9999
|
||||||
|
} else {
|
||||||
|
rtt
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let pool_size = std::cmp::min(candidates.len(), 2);
|
let pool_size = std::cmp::min(candidates.len(), 2);
|
||||||
let target = &candidates[stream_id as usize % pool_size];
|
let target = &candidates[stream_id as usize % pool_size];
|
||||||
|
|
||||||
Some(target.clone())
|
Some(target.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send_to_network(&self, message: MuxMessage) -> Result<(), String> {
|
||||||
pub fn send_to_network(&self, message: MuxMessage) -> Result<(), String> {
|
|
||||||
let stream_id = message.stream_id;
|
let stream_id = message.stream_id;
|
||||||
let size = message.data.len() as u64;
|
let size = message.data.len() as u64;
|
||||||
|
|
||||||
|
|
||||||
let (leg_id, leg) = self
|
let (leg_id, leg) = self
|
||||||
.select_leg(&message.frame_type, stream_id)
|
.select_leg(&message.frame_type, stream_id)
|
||||||
.ok_or_else(|| "MUXER: No active legs available".to_string())?;
|
.ok_or_else(|| "MUXER: No active legs available".to_string())?;
|
||||||
@@ -158,42 +151,30 @@ impl Muxer {
|
|||||||
FrameType::Connect
|
FrameType::Connect
|
||||||
| FrameType::Close
|
| FrameType::Close
|
||||||
| FrameType::UdpConnect
|
| FrameType::UdpConnect
|
||||||
| FrameType::Handshake => &leg.control_tx,
|
| FrameType::Handshake => leg.control_tx.clone(),
|
||||||
_ => &leg.data_tx,
|
_ => leg.data_tx.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match target_tx.try_send(message) {
|
match target_tx.send(message).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
|
|
||||||
leg.stats.tx_bytes.fetch_add(size, Ordering::Relaxed);
|
leg.stats.tx_bytes.fetch_add(size, Ordering::Relaxed);
|
||||||
if let Some(stream_ref) = self.streams.get(&stream_id) {
|
|
||||||
stream_ref
|
|
||||||
.value()
|
|
||||||
.1
|
|
||||||
.tx_bytes
|
|
||||||
.fetch_add(size, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => {
|
|
||||||
|
|
||||||
warn!(
|
if let Some(stream_ref) = self.streams.get(&stream_id) {
|
||||||
leg_id,
|
stream_ref.1.tx_bytes.fetch_add(size, Ordering::Relaxed);
|
||||||
"MUXER: Network queue full! Dropping outbound packet."
|
}
|
||||||
);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => {
|
Err(_) => {
|
||||||
self.remove_leg(leg_id);
|
self.remove_leg(leg_id);
|
||||||
Err(format!("MUXER: Leg {} died during send", leg_id))
|
Err(format!("MUXER: Leg {} died during send", leg_id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_data_safe(
|
pub async fn send_data_safe(
|
||||||
&self,
|
&self,
|
||||||
stream_id: u32,
|
stream_id: u32,
|
||||||
data: Bytes, // Больше не mut
|
data: Bytes,
|
||||||
is_udp: bool,
|
is_udp: bool,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let frame_type = if is_udp {
|
let frame_type = if is_udp {
|
||||||
@@ -202,15 +183,15 @@ impl Muxer {
|
|||||||
FrameType::Data
|
FrameType::Data
|
||||||
};
|
};
|
||||||
|
|
||||||
// Отправляем как есть, целиком!
|
|
||||||
self.send_to_network(MuxMessage {
|
self.send_to_network(MuxMessage {
|
||||||
stream_id,
|
stream_id,
|
||||||
frame_type,
|
frame_type,
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_control(
|
pub async fn send_control(
|
||||||
&self,
|
&self,
|
||||||
stream_id: u32,
|
stream_id: u32,
|
||||||
f_type: FrameType,
|
f_type: FrameType,
|
||||||
@@ -221,6 +202,7 @@ impl Muxer {
|
|||||||
frame_type: f_type,
|
frame_type: f_type,
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_stream(&self, stream_id: u32, tx: Sender<Bytes>) {
|
pub fn register_stream(&self, stream_id: u32, tx: Sender<Bytes>) {
|
||||||
@@ -232,8 +214,7 @@ impl Muxer {
|
|||||||
self.streams.remove(&stream_id);
|
self.streams.remove(&stream_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispatch_to_local(&self, stream_id: u32, data: Bytes) {
|
pub async fn dispatch_to_local(&self, stream_id: u32, data: Bytes) {
|
||||||
|
|
||||||
let stream_opt = self
|
let stream_opt = self
|
||||||
.streams
|
.streams
|
||||||
.get(&stream_id)
|
.get(&stream_id)
|
||||||
@@ -242,18 +223,11 @@ pub fn dispatch_to_local(&self, stream_id: u32, data: Bytes) {
|
|||||||
if let Some((tx, stats)) = stream_opt {
|
if let Some((tx, stats)) = stream_opt {
|
||||||
let size = data.len() as u64;
|
let size = data.len() as u64;
|
||||||
|
|
||||||
|
match tx.send(data).await {
|
||||||
match tx.try_send(data) {
|
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
stats.rx_bytes.fetch_add(size, Ordering::Relaxed);
|
stats.rx_bytes.fetch_add(size, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
Err(TrySendError::Full(_)) => {
|
Err(_) => {
|
||||||
netrunner_logger::warn!(
|
|
||||||
stream_id,
|
|
||||||
"Muxer -> Local: Buffer full, dropping packet. Check your bridge/TUN speed."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(TrySendError::Closed(_)) => {
|
|
||||||
self.remove_stream(stream_id);
|
self.remove_stream(stream_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,8 +245,9 @@ pub fn dispatch_to_local(&self, stream_id: u32, data: Bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn perform_health_check(&self) {
|
pub async fn perform_health_check(&self) {
|
||||||
|
let legs: Vec<(u32, Sender<MuxMessage>)> = self
|
||||||
let legs: Vec<(u32, Sender<MuxMessage>)> = self.legs.iter()
|
.legs
|
||||||
|
.iter()
|
||||||
.map(|k| (*k.key(), k.value().control_tx.clone()))
|
.map(|k| (*k.key(), k.value().control_tx.clone()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -280,7 +255,6 @@ pub fn dispatch_to_local(&self, stream_id: u32, data: Bytes) {
|
|||||||
let probe_stream_id = self.id_gen.next();
|
let probe_stream_id = self.id_gen.next();
|
||||||
let (probe_tx, mut probe_rx) = tokio::sync::mpsc::channel(2);
|
let (probe_tx, mut probe_rx) = tokio::sync::mpsc::channel(2);
|
||||||
|
|
||||||
|
|
||||||
self.register_stream(probe_stream_id, probe_tx);
|
self.register_stream(probe_stream_id, probe_tx);
|
||||||
|
|
||||||
let msg = MuxMessage {
|
let msg = MuxMessage {
|
||||||
@@ -291,10 +265,9 @@ pub fn dispatch_to_local(&self, stream_id: u32, data: Bytes) {
|
|||||||
|
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
|
|
||||||
if tx.try_send(msg).is_ok() {
|
if tx.try_send(msg).is_ok() {
|
||||||
|
match tokio::time::timeout(std::time::Duration::from_secs(2), probe_rx.recv()).await
|
||||||
match tokio::time::timeout(std::time::Duration::from_secs(2), probe_rx.recv()).await {
|
{
|
||||||
Ok(Some(_)) => {
|
Ok(Some(_)) => {
|
||||||
let rtt = start.elapsed().as_millis() as u32;
|
let rtt = start.elapsed().as_millis() as u32;
|
||||||
if let Some(leg) = self.legs.get(&leg_id) {
|
if let Some(leg) = self.legs.get(&leg_id) {
|
||||||
@@ -303,7 +276,6 @@ pub fn dispatch_to_local(&self, stream_id: u32, data: Bytes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
||||||
if let Some(leg) = self.legs.get(&leg_id) {
|
if let Some(leg) = self.legs.get(&leg_id) {
|
||||||
leg.stats.rtt_ms.store(5000, Ordering::Relaxed);
|
leg.stats.rtt_ms.store(5000, Ordering::Relaxed);
|
||||||
warn!(leg_id, "❌ Leg Health Check Timeout (marked as slow)");
|
warn!(leg_id, "❌ Leg Health Check Timeout (marked as slow)");
|
||||||
@@ -312,12 +284,10 @@ pub fn dispatch_to_local(&self, stream_id: u32, data: Bytes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
self.remove_stream(probe_stream_id);
|
self.remove_stream(probe_stream_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn format_size(bytes: u64) -> String {
|
fn format_size(bytes: u64) -> String {
|
||||||
const KB: u64 = 1024;
|
const KB: u64 = 1024;
|
||||||
const MB: u64 = KB * 1024;
|
const MB: u64 = KB * 1024;
|
||||||
@@ -333,7 +303,6 @@ pub fn dispatch_to_local(&self, stream_id: u32, data: Bytes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn print_topology_tree(&self) {
|
pub fn print_topology_tree(&self) {
|
||||||
println!(
|
println!(
|
||||||
"\n🌐 Netrunner Tunnel Topology [Session: {}]",
|
"\n🌐 Netrunner Tunnel Topology [Session: {}]",
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ impl Codec {
|
|||||||
|
|
||||||
let decrypted = self.crypto.decrypt(&mut data_to_decrypt).map_err(|_| {
|
let decrypted = self.crypto.decrypt(&mut data_to_decrypt).map_err(|_| {
|
||||||
self.staging.clear();
|
self.staging.clear();
|
||||||
// Сохраняем первые 32 байта зашифрованного пакета для логов, чтобы понять, что нам прислали
|
|
||||||
let bad_data =
|
let bad_data =
|
||||||
Bytes::copy_from_slice(&data_to_decrypt[..data_to_decrypt.len().min(32)]);
|
Bytes::copy_from_slice(&data_to_decrypt[..data_to_decrypt.len().min(32)]);
|
||||||
TlsError::new(
|
TlsError::new(
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ impl Network {
|
|||||||
pub async fn run(&self, token: CancellationToken) {
|
pub async fn run(&self, token: CancellationToken) {
|
||||||
let addr = format!("{}:{}", self.host, self.port);
|
let addr = format!("{}:{}", self.host, self.port);
|
||||||
|
|
||||||
// Инициализируем конфиг для сервера
|
|
||||||
NetworkConfig::init_global(1500);
|
NetworkConfig::init_global(1500);
|
||||||
|
|
||||||
info!("🌐 Netrunner Server: Listening on {}", addr);
|
info!("🌐 Netrunner Server: Listening on {}", addr);
|
||||||
@@ -32,10 +31,10 @@ impl Network {
|
|||||||
if let Ok((stream, client_addr)) = res {
|
if let Ok((stream, client_addr)) = res {
|
||||||
info!("🔌 Connection from {}", client_addr);
|
info!("🔌 Connection from {}", client_addr);
|
||||||
|
|
||||||
// Создаем объект соединения (включает кодек)
|
|
||||||
let conn = Connection::new(stream, true);
|
let conn = Connection::new(stream, true);
|
||||||
|
|
||||||
// Создаем хэндлер. (Он сам разберется с SessionManager, если нужно)
|
|
||||||
let handler = ServerHandler::new(conn);
|
let handler = ServerHandler::new(conn);
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
|||||||
Reference in New Issue
Block a user