fallback and address change

This commit is contained in:
2026-03-22 12:46:31 +07:00
parent d0576bddf3
commit b325e6cbec
2 changed files with 80 additions and 36 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ async fn main() -> anyhow::Result<()> {
}) })
.expect("Failed to initialize TUN device"); .expect("Failed to initialize TUN device");
let remote_address: String = "62.60.244.156:443".into(); let remote_address: String = "147.45.43.70:443".into();
let _ = setup_platform_routing(&remote_address); let _ = setup_platform_routing(&remote_address);
info!("TUN interface is UP: 10.0.0.1/24"); info!("TUN interface is UP: 10.0.0.1/24");
+79 -35
View File
@@ -17,8 +17,8 @@ use crate::{
}, },
tlseng::profile::BrowserProfile, tlseng::profile::BrowserProfile,
}; };
use bytes::BytesMut; use bytes::{Bytes, BytesMut};
use netrunner_logger::info; use netrunner_logger::{info, warn};
use tokio::{ use tokio::{
io::{AsyncReadExt, AsyncWriteExt}, io::{AsyncReadExt, AsyncWriteExt},
net::{ net::{
@@ -260,35 +260,72 @@ pub struct ServerHandler {
pub conn: Connection, pub conn: Connection,
pub token: CancellationToken, pub token: CancellationToken,
} }
impl ServerHandler { impl ServerHandler {
async fn handle_fallback(outbound: &mut OwnedWriteHalf) { async fn handle_stealth_fallback(
let fallback_response = "HTTP/1.1 302 Found\r\n\ mut client_inbound: OwnedReadHalf,
Server: nginx/1.18.0 (Ubuntu)\r\n\ mut client_outbound: OwnedWriteHalf,
Location: https://www.ubuntu.com/\r\n\ initial_data: bytes::Bytes,
Content-Length: 0\r\n\ ) {
Connection: close\r\n\ let target_host = "ubuntu.com:443";
\r\n"; info!(target = %target_host, "Stealth fallback: bridging to Target");
let _ = outbound.write_all(fallback_response.as_bytes()).await; // 1. Пытаемся подключиться с коротким таймаутом
let _ = outbound.flush().await; let target_stream = tokio::time::timeout(
let _ = outbound.shutdown().await; std::time::Duration::from_secs(3),
TcpStream::connect(target_host),
)
.await;
match target_stream {
Ok(Ok(mut target_server)) => {
let (mut server_read, mut server_write) = target_server.into_split();
// 2. Скармливаем те байты, которые уже вычитали (Client Hello)
if !initial_data.is_empty() {
if let Err(e) = server_write.write_all(&initial_data).await {
warn!("Failed to push initial data to fallback: {}", e);
return;
}
}
// 3. Запускаем bidirectional copy
// Это создаст две задачи, которые будут перекачивать байты, пока одна сторона не закроется
let res = tokio::io::copy_bidirectional(
&mut tokio::io::join(&mut client_inbound, &mut client_outbound),
&mut tokio::io::join(&mut server_read, &mut server_write),
)
.await;
match res {
Ok((from_client, from_server)) => {
info!(
"Fallback closed. Sent: {} bytes, Recv: {} bytes",
from_client, from_server
);
}
Err(e) => warn!("Fallback bridge error: {}", e),
}
}
Ok(Err(e)) => warn!("Fallback connect error: {}", e),
Err(_) => warn!("Fallback connection timed out (Target unreachable)"),
}
} }
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl TunnelHandler for ServerHandler { impl TunnelHandler for ServerHandler {
async fn run(mut self) -> Result<(), String> { async fn run(mut self) -> Result<(), String> {
info!("Acting as TLS Server"); info!("Acting as TLS Server with Stealth Fallback");
// --- ИЗМЕНЕНИЕ ДЛЯ НОВОГО MUXER ---
let (control_tx, control_rx) = mpsc::channel(MESSAGE_CHANNEL_SIZE); let (control_tx, control_rx) = mpsc::channel(MESSAGE_CHANNEL_SIZE);
let (data_tx, data_rx) = mpsc::channel(MESSAGE_CHANNEL_SIZE); let (data_tx, data_rx) = mpsc::channel(MESSAGE_CHANNEL_SIZE);
let muxer = Muxer::new(control_tx, data_tx, false); let muxer = Muxer::new(control_tx, data_tx, false);
let handshake_timeout = std::time::Duration::from_secs(5); let handshake_timeout = std::time::Duration::from_secs(1);
let hello = loop { let hello = loop {
let buf_snapshot = self.conn.read_buf.clone().freeze();
match self match self
.conn .conn
.codec .codec
@@ -303,35 +340,42 @@ impl TunnelHandler for ServerHandler {
.await; .await;
match read_res { match read_res {
Ok(Ok(n)) if n == 0 => { Ok(Ok(n)) if n == 0 => return Err("Client closed".into()),
return Err("Client closed connection before handshake".into()); Ok(Ok(_)) => continue,
} Ok(Err(e)) => return Err(e.to_string()),
Ok(Ok(_)) => {
continue;
}
Ok(Err(e)) => {
return Err(format!("Socket read error: {}", e));
}
Err(_) => { Err(_) => {
netrunner_logger::warn!( warn!("Handshake timeout. Going stealth.");
"Handshake timeout (Scanner detected). Triggering fallback." // Используем наш снимок, так как основной буфер мог быть частично съеден
); ServerHandler::handle_stealth_fallback(
ServerHandler::handle_fallback(&mut self.conn.outbound).await; self.conn.inbound,
self.conn.outbound,
buf_snapshot,
)
.await;
return Ok(()); return Ok(());
} }
} }
} }
Err(e) => { Err(e) => {
netrunner_logger::warn!( warn!("Auth/Format failed: {:?}. Going stealth.", e);
error = ?e, // ВАЖНО: используем сохраненный buf_snapshot
"Invalid handshake format (Scanner detected). Triggering fallback." info!(
"DEBUG: Restoring {} bytes from snapshot for fallback",
buf_snapshot.len()
); );
ServerHandler::handle_fallback(&mut self.conn.outbound).await;
ServerHandler::handle_stealth_fallback(
self.conn.inbound,
self.conn.outbound,
buf_snapshot,
)
.await;
return Ok(()); return Ok(());
} }
} }
}; };
// Если дошли сюда — значит это наш клиент, шлем Server Hello
self.conn self.conn
.outbound .outbound
.write_all(&hello) .write_all(&hello)
@@ -345,8 +389,8 @@ impl TunnelHandler for ServerHandler {
outbound: self.conn.outbound, outbound: self.conn.outbound,
codec: self.conn.codec, codec: self.conn.codec,
read_buf: self.conn.read_buf, read_buf: self.conn.read_buf,
control_rx, // Передаем оба ресивера в Engine control_rx,
data_rx, // Передаем оба ресивера в Engine data_rx,
handler, handler,
token: self.token, token: self.token,
} }