This commit is contained in:
2026-04-06 12:27:08 +07:00
parent 6b5f7b23d8
commit aa25030827
4 changed files with 50 additions and 11 deletions
+9
View File
@@ -44,6 +44,8 @@ impl TunnelEngine {
let leg_id = self.leg_id;
let muxer = self.muxer.clone();
let muxer_pong = muxer.clone();
let token = CancellationToken::new();
let codec_reader = codec.clone();
@@ -102,6 +104,10 @@ impl TunnelEngine {
}
for frame in frames {
if frame.header.frame_type == FrameType::Heartbeat {
muxer.record_pong(leg_id).await;
continue;
}
handler.handle(frame).await;
}
}
@@ -134,6 +140,9 @@ impl TunnelEngine {
}
_ = heartbeat.tick() => {
// 1. Фиксируем время
muxer_pong.record_ping_sent(leg_id);
// 2. Шлем пакет
let msg = MuxMessage { stream_id: 0, frame_type: FrameType::Heartbeat, data: Bytes::new() };
Self::handle_outbound(&mut outbound, &codec_writer, msg).await?;
}
+17 -2
View File
@@ -1,5 +1,5 @@
use bytes::Bytes;
use netrunner_logger::{debug, error, info, warn};
use netrunner_logger::{debug, error, info, trace, warn};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::net::{TcpStream, UdpSocket};
@@ -75,6 +75,21 @@ impl StreamHandler {
let stream_id = frame.header.stream_id;
match frame.header.frame_type {
FrameType::Heartbeat => {
// Проверяем: если мы Opener (т.е. мы Сервер), то отвечаем.
// Если мы Клиент (opener == None), то мы сюда вообще не должны дойти
// (т.к. перехватили в TunnelEngine), но на всякий случай логируем.
if self.opener.is_some() {
trace!(stream_id, "💓 [Server] Ping received, sending Pong");
let _ = self
.muxer
.send_control(stream_id, FrameType::Heartbeat, Bytes::new())
.await;
} else {
trace!(stream_id, "💓 [Client] Pong received (captured by Engine)");
}
}
FrameType::Connect => {
self.handle_conn_request(stream_id, frame.payload, false)
.await
@@ -92,10 +107,10 @@ impl StreamHandler {
debug!(stream_id, "🏁 [Tunnel] Peer closed stream");
self.muxer.remove_stream(stream_id);
}
_ => debug!(stream_id, "Unhandled frame: {:?}", frame.header.frame_type),
}
}
async fn handle_conn_request(&self, stream_id: u32, payload: Bytes, is_udp: bool) {
let target = String::from_utf8_lossy(&payload).to_string();
+20 -1
View File
@@ -3,6 +3,7 @@ use dashmap::DashMap;
use netrunner_logger::{debug, info, trace, warn};
use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::mpsc::Sender;
use crate::net::{HEALTH_CHECK_TIMEOUT, MAX_TUNNEL_LEGS, MUXER_POOL_SIZE};
@@ -55,8 +56,9 @@ pub struct MuxMessage {
pub struct Muxer {
legs: Arc<DashMap<u32, MuxLeg>>,
streams: Arc<DashMap<u32, (Sender<Bytes>, Arc<StreamStats>)>>,
// 🚨 Sticky Sessions: Привязка Stream ID -> Leg ID
stream_bindings: Arc<DashMap<u32, u32>>,
// 🚨 Добавляем сюда:
pending_pings: Arc<DashMap<u32, Instant>>,
id_gen: Arc<IdGenerator>,
session_id: Arc<String>,
}
@@ -68,6 +70,7 @@ impl Muxer {
streams: Arc::new(DashMap::new()),
stream_bindings: Arc::new(DashMap::new()),
id_gen: Arc::new(IdGenerator::new(is_client)),
pending_pings: Arc::new(DashMap::new()),
session_id: Arc::new(session_id),
}
}
@@ -163,6 +166,22 @@ impl Muxer {
Some((selected_id, selected_leg))
}
pub fn record_ping_sent(&self, leg_id: u32) {
self.pending_pings.insert(leg_id, Instant::now());
}
pub async fn record_pong(&self, leg_id: u32) {
if let Some((_, start_time)) = self.pending_pings.remove(&leg_id) {
let rtt = start_time.elapsed().as_millis() as u32;
if let Some(leg) = self.legs.get(&leg_id) {
// Обновляем атомик, который потом прочитает принт топологии
leg.stats.rtt_ms.store(rtt, Ordering::Relaxed);
trace!(leg_id, rtt, "💓 [Muxer] RTT updated for leg");
}
}
}
pub async fn send_to_network(&self, message: MuxMessage) -> Result<(), String> {
let stream_id = message.stream_id;
let size = message.data.len() as u64;
+4 -8
View File
@@ -11,7 +11,7 @@ pub const UDP_IDLE_TIMEOUT: Duration = Duration::from_secs(60); // Смерть
pub const GLOBAL_IDLE_TIMEOUT: Duration = Duration::from_secs(120); // Очистка Tracker-ом
pub const HEALTH_CHECK_INTERVAL: Duration = Duration::from_secs(5); // Частота пинга Leg-ов
pub const HEALTH_CHECK_TIMEOUT: Duration = Duration::from_secs(15);
pub const LEG_RECONNECT_DELAY: Duration = Duration::from_secs(30); // Пауза перед реконнектом Leg
pub const LEG_RECONNECT_DELAY: Duration = Duration::from_secs(5); // Пауза перед реконнектом Leg
pub const BRIDGE_IDLE_TIMEOUT: Duration = Duration::from_secs(300); // Таймаут задач-бриджей
// --- Сетевые порты ---
@@ -20,10 +20,6 @@ pub const HTTP_PORT: u16 = 80;
pub const HTTPS_PORT: u16 = 443;
pub const NETBIOS_PORTS: [u16; 2] = [137, 138];
// --- Критические оверхеды (для MTU/MSS) ---
pub const IPV4_TCP_OVERHEAD: usize = 40; // IPv4(20) + TCP(20)
pub const NRXP_OVERHEAD: usize = 254; // Запас под заголовки твоего протокола и TLS
// --- Настройки безопасности ---
pub const AUTH_TIME_STEP: u64 = 60; // Шаг генерации токена (секунды)
pub const AUTH_WINDOW_SIZE: u64 = 2; // Допуск шагов времени (current +/- 2)
@@ -34,8 +30,8 @@ pub const TOPOLOGY_PRINT_INTERVAL: Duration = Duration::from_secs(15);
// --- Настройки Stealth Fallback (Маскировка) ---
pub const STEALTH_FALLBACK_HOST: &str = "ubuntu.com:443";
pub const FALLBACK_CONNECT_TIMEOUT: Duration = Duration::from_secs(3);
pub const FALLBACK_CONNECT_TIMEOUT: Duration = Duration::from_secs(5);
// --- Таймауты Handshake ---
pub const TLS_HELLO_TIMEOUT: Duration = Duration::from_secs(1);
pub const SECURE_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(3);
pub const TLS_HELLO_TIMEOUT: Duration = Duration::from_secs(10);
pub const SECURE_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(15);