connection refactoring

This commit is contained in:
2026-03-17 14:27:07 +07:00
parent b7c254e9c5
commit bf6e621f14
7 changed files with 210 additions and 181 deletions
Generated
+1
View File
@@ -1217,6 +1217,7 @@ name = "netrunner-core"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"aead", "aead",
"async-trait",
"bytes", "bytes",
"chacha20poly1305", "chacha20poly1305",
"hex", "hex",
+1
View File
@@ -16,4 +16,5 @@ tokio = "1.49.0"
rand = "0.10.0" rand = "0.10.0"
hex = "0.4.3" hex = "0.4.3"
tokio-util = { version = "0.7", features = ["rt"] } tokio-util = { version = "0.7", features = ["rt"] }
async-trait = "0.1.89"
netrunner-logger = { path = "../tools/log" } netrunner-logger = { path = "../tools/log" }
+2 -3
View File
@@ -30,7 +30,7 @@ pub async fn run_proxy_bridge<R, W>(
frame_type: FrameType::Data, frame_type: FrameType::Data,
data: buf.split().freeze(), data: buf.split().freeze(),
}; };
if muxer.to_network.send(msg).await.is_err() { break; } if muxer.send_to_netwrok(msg).await.is_err() { break; }
} }
Err(e) => { Err(e) => {
error!(stream_id, error = %e, "Socket read error"); error!(stream_id, error = %e, "Socket read error");
@@ -58,8 +58,7 @@ pub async fn run_proxy_bridge<R, W>(
} }
let _ = muxer let _ = muxer
.to_network .send_to_netwrok(MuxMessage {
.send(MuxMessage {
stream_id, stream_id,
frame_type: FrameType::Close, frame_type: FrameType::Close,
data: Bytes::new(), data: Bytes::new(),
+169 -134
View File
@@ -1,16 +1,3 @@
use bytes::{Bytes, BytesMut};
use netrunner_logger::{debug, error, info, instrument, trace, warn};
use std::net::SocketAddr;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::{
tcp::{OwnedReadHalf, OwnedWriteHalf},
TcpStream,
},
sync::mpsc::{self},
};
use tokio_util::sync::CancellationToken;
use crate::{ use crate::{
protocol::{ protocol::{
codec::{ codec::{
@@ -27,7 +14,20 @@ use crate::{
handler::StreamHandler, handler::StreamHandler,
muxer::{MuxMessage, Muxer}, muxer::{MuxMessage, Muxer},
}, },
tlseng::profile::BrowserProfile,
}; };
use bytes::{Bytes, BytesMut};
use netrunner_logger::{debug, error, info, trace, warn};
use std::net::SocketAddr;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::{
tcp::{OwnedReadHalf, OwnedWriteHalf},
TcpStream,
},
sync::mpsc,
};
use tokio_util::sync::CancellationToken;
pub const BUF_SIZE: usize = 16384; pub const BUF_SIZE: usize = 16384;
@@ -37,6 +37,11 @@ pub enum ConnectionRole {
Server, Server,
} }
#[async_trait::async_trait]
pub trait TunnelHandler {
async fn run(self) -> Result<(), String>;
}
pub struct Connection { pub struct Connection {
addr: SocketAddr, addr: SocketAddr,
pub inbound: OwnedReadHalf, pub inbound: OwnedReadHalf,
@@ -57,188 +62,218 @@ impl Connection {
} }
} }
async fn read_socks_request(&mut self) -> Result<SocksRequest, String> { pub fn new_raw(inbound: OwnedReadHalf, outbound: OwnedWriteHalf) -> Self {
loop { Self {
match SocksRequest::parse(&mut self.read_buf) { addr: "0.0.0.0:0".parse().unwrap(), // заглушка, если адрес не важен
Ok(Some(req)) => { inbound,
info!(client = %self.addr, request = ?req, "SOCKS request successfully parsed"); outbound,
return Ok(req); read_buf: BytesMut::with_capacity(BUF_SIZE),
} codec: Codec::new(false),
Ok(None) => {
trace!(client = %self.addr, buffer_len = self.read_buf.len(), "SOCKS parse: need more data");
}
Err(e) => {
error!(client = %self.addr, error = %e, "SOCKS protocol violation");
return Err(format!("Socks parse error: {}", e));
} }
} }
pub async fn read_socks_request(&mut self) -> Result<SocksRequest, String> {
loop {
match SocksRequest::parse(&mut self.read_buf) {
Ok(Some(req)) => return Ok(req),
Ok(None) => {}
Err(e) => return Err(format!("Socks parse error: {}", e)),
}
let n = self let n = self
.inbound .inbound
.read_buf(&mut self.read_buf) .read_buf(&mut self.read_buf)
.await .await
.map_err(|e| { .map_err(|e| e.to_string())?;
error!(client = %self.addr, error = %e, "Failed to read from socket during SOCKS handshake");
e.to_string()
})?;
if n == 0 { if n == 0 {
warn!(client = %self.addr, "Client closed connection prematurely during SOCKS handshake"); return Err("Client closed connection".into());
return Err("Client closed connection during SOCKS handshake".into());
} }
trace!(client = %self.addr, read_bytes = n, "Read data from client for SOCKS handshake");
} }
} }
async fn send_socks_reply(&mut self, reply: SocksReply) -> Result<(), String> { pub async fn send_socks_reply(&mut self, reply: SocksReply) -> Result<(), String> {
let mut buf = BytesMut::with_capacity(24); let mut buf = BytesMut::with_capacity(24);
debug!(client = %self.addr, reply = ?reply, "Sending SOCKS reply to client");
reply.write_to(&mut buf); reply.write_to(&mut buf);
self.outbound
self.outbound.write_all(&buf).await.map_err(|e| { .write_all(&buf)
error!(client = %self.addr, error = %e, "Failed to send SOCKS reply"); .await
e.to_string() .map_err(|e| e.to_string())
})?; }
Ok(())
} }
pub async fn handle_socks_client(mut self, muxer: Muxer) -> Result<(), String> { pub struct ClientHandler {
pub conn: Connection,
pub muxer: Muxer,
}
// Внутри connection.rs или где у тебя ClientHandler
impl ClientHandler {
pub async fn connect(
remote_proxy_addr: &str,
token: CancellationToken,
) -> Result<Muxer, String> {
let stream = TcpStream::connect(remote_proxy_addr)
.await
.map_err(|e| e.to_string())?;
let (inbound, outbound) = stream.into_split();
let mut conn = Connection::new_raw(inbound, outbound);
// TLS Handshake
let ch = conn
.codec
.make_client_handshake(&BrowserProfile::CHROME_131, "google.com")
.map_err(|e| format!("{:?}", e))?;
conn.outbound
.write_all(&ch)
.await
.map_err(|e| e.to_string())?;
loop {
match conn.codec.process_handshake(&mut conn.read_buf) {
Ok(_) => break,
Err(e) if e.action == ErrorAction::Wait => {
let n = conn
.inbound
.read_buf(&mut conn.read_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 (mux_tx, mux_rx) = mpsc::channel(BUF_SIZE);
let muxer = Muxer::new(mux_tx, true);
let handler =
std::sync::Arc::new(StreamHandler::new(muxer.clone(), ConnectionRole::Client));
let engine = TunnelEngine {
inbound: conn.inbound,
outbound: conn.outbound,
codec: conn.codec,
read_buf: conn.read_buf,
mux_rx,
handler,
token: token.clone(),
};
tokio::spawn(async move { engine.run().await });
Ok(muxer)
}
}
#[async_trait::async_trait]
impl TunnelHandler for ClientHandler {
async fn run(mut self) -> Result<(), String> {
info!("Starting SOCKS multiplexed handling"); info!("Starting SOCKS multiplexed handling");
self.conn.read_socks_request().await?;
debug!("Reading SOCKS handshake request"); self.conn
let _ = self.read_socks_request().await.map_err(|e| { .send_socks_reply(SocksReply::HandshakeSelect { method: 0x00 })
error!("SOCKS handshake failed: {}", e);
e
})?;
self.send_socks_reply(SocksReply::HandshakeSelect { method: 0x00 })
.await?; .await?;
let req = self.read_socks_request().await?; let req = self.conn.read_socks_request().await?;
let target = if let SocksRequest::Connect { target, .. } = req { let target = if let SocksRequest::Connect { target, .. } = req {
target target
} else { } else {
return Err("Expected Connect".into()); return Err("Expected Connect".into());
}; };
let stream_id = muxer.next_id(); let stream_id = self.muxer.next_id();
let target_str = target.to_string(); let (v_tx, mut v_rx) = mpsc::channel::<bytes::Bytes>(1024);
self.muxer.register_stream(stream_id, v_tx).await;
let (v_tx, mut v_rx) = mpsc::channel::<Bytes>(1024); self.muxer
muxer.register_stream(stream_id, v_tx).await; .send_to_netwrok(MuxMessage {
muxer
.to_network
.send(MuxMessage {
stream_id, stream_id,
frame_type: FrameType::Connect, frame_type: FrameType::Connect,
data: Bytes::from(target_str), data: bytes::Bytes::from(target.to_string()),
}) })
.await .await
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
let first_payload = let first_payload = tokio::time::timeout(std::time::Duration::from_secs(10), v_rx.recv())
match tokio::time::timeout(std::time::Duration::from_secs(10), v_rx.recv()).await {
Ok(Some(data)) => data,
_ => {
error!(
stream_id,
"Server timeout or failed to send Connect confirmation"
);
self.send_socks_reply(SocksReply::ConnectResult {
reply_code: 0x01,
atyp: 0x01,
addr: [0, 0, 0, 0],
port: 0,
})
.await .await
.ok(); .map_err(|_| "Timeout")?
return Err("Target connection failed".into()); .ok_or("No data")?;
}
};
if first_payload.len() >= 2 && first_payload[1] == 0x00 { if first_payload.len() >= 2 && first_payload[1] == 0x00 {
debug!( self.conn
stream_id, .outbound
"Server confirmed connection, forwarding SOCKS reply to browser"
);
self.outbound
.write_all(&first_payload) .write_all(&first_payload)
.await .await
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
} else { } else {
self.outbound.write_all(&first_payload).await.ok(); self.conn.outbound.write_all(&first_payload).await.ok();
return Err("Server rejected connection".into()); return Err("Rejected".into());
} }
let Self { let browser_in = self.conn.inbound;
inbound: browser_in, let browser_out = self.conn.outbound;
outbound: browser_out, let muxer = self.muxer;
..
} = self;
let muxer_clone = muxer.clone();
tokio::spawn(async move { tokio::spawn(async move {
run_proxy_bridge(stream_id, browser_in, browser_out, muxer_clone, v_rx).await; run_proxy_bridge(stream_id, browser_in, browser_out, muxer, v_rx).await;
}); });
Ok(()) Ok(())
} }
}
pub async fn handle_server_tunnel(mut self, token: CancellationToken) -> Result<(), String> { pub struct ServerHandler {
info!("Acting as TLS Server, waiting for ClientHello"); pub conn: Connection,
pub token: CancellationToken,
}
#[async_trait::async_trait]
impl TunnelHandler for ServerHandler {
async fn run(mut self) -> Result<(), String> {
info!("Acting as TLS Server");
let (mux_tx, mux_rx) = mpsc::channel(BUF_SIZE); let (mux_tx, mux_rx) = mpsc::channel(BUF_SIZE);
let muxer = Muxer::new(mux_tx.clone(), false); let muxer = Muxer::new(mux_tx, false);
let server_hello_bytes = loop { let hello = loop {
match self.codec.make_server_handshake(&mut self.read_buf) { match self
Ok(bytes) => { .conn
info!("ClientHello received, sending ServerHello"); .codec
break bytes; .make_server_handshake(&mut self.conn.read_buf)
} {
Ok(b) => break b,
Err(e) if e.action == ErrorAction::Wait => { Err(e) if e.action == ErrorAction::Wait => {
let n = self if self
.conn
.inbound .inbound
.read_buf(&mut self.read_buf) .read_buf(&mut self.conn.read_buf)
.await .await
.map_err(|err| format!("Read error: {}", err))?; .map_err(|e| e.to_string())?
== 0
if n == 0 { {
return Err("Client closed connection".into()); return Err("Closed".into());
} }
} }
Err(e) => return Err(format!("TLS error: {:?}", e)), Err(e) => return Err(format!("{:?}", e)),
} }
}; };
self.outbound self.conn
.write_all(&server_hello_bytes) .outbound
.write_all(&hello)
.await .await
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
info!("TLS Tunnel established as server");
let handler = let handler = std::sync::Arc::new(StreamHandler::new(muxer, ConnectionRole::Server));
std::sync::Arc::new(StreamHandler::new(muxer.clone(), ConnectionRole::Server)); TunnelEngine {
inbound: self.conn.inbound,
debug!("Handover to TunnelEngine"); outbound: self.conn.outbound,
let engine = TunnelEngine { codec: self.conn.codec,
inbound: self.inbound, read_buf: self.conn.read_buf,
outbound: self.outbound,
codec: self.codec,
read_buf: self.read_buf,
mux_rx, mux_rx,
handler, handler,
token, token: self.token,
}; }
.run()
engine.run().await.map_err(|e| { .await
error!("TunnelEngine error: {}", e);
e
})
} }
} }
+1 -1
View File
@@ -35,7 +35,7 @@ impl StreamHandler {
let target_str = String::from_utf8_lossy(&payload).to_string(); let target_str = String::from_utf8_lossy(&payload).to_string();
let muxer = self.muxer.clone(); let muxer = self.muxer.clone();
let (v_tx, v_rx) = tokio::sync::mpsc::channel(100); let (v_tx, v_rx) = tokio::sync::mpsc::channel(1024);
muxer.register_stream(stream_id, v_tx).await; muxer.register_stream(stream_id, v_tx).await;
tokio::spawn(async move { tokio::spawn(async move {
+6 -2
View File
@@ -1,9 +1,9 @@
use crate::protocol::codec::frame::FrameType; use crate::protocol::codec::frame::FrameType;
use bytes::Bytes; use bytes::Bytes;
use netrunner_logger::{debug, error};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc::error::SendError;
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
use tokio::sync::RwLock; use tokio::sync::RwLock;
@@ -32,7 +32,7 @@ pub struct MuxMessage {
#[derive(Clone)] #[derive(Clone)]
pub struct Muxer { pub struct Muxer {
pub to_network: Sender<MuxMessage>, to_network: Sender<MuxMessage>,
streams: Arc<RwLock<HashMap<u32, Sender<Bytes>>>>, streams: Arc<RwLock<HashMap<u32, Sender<Bytes>>>>,
id_gen: Arc<IdGenerator>, id_gen: Arc<IdGenerator>,
} }
@@ -50,6 +50,10 @@ impl Muxer {
self.id_gen.next() self.id_gen.next()
} }
pub async fn send_to_netwrok(&self, message: MuxMessage) -> Result<(), SendError<MuxMessage>> {
self.to_network.send(message).await
}
pub async fn register_stream(&self, stream_id: u32, tx: Sender<Bytes>) { pub async fn register_stream(&self, stream_id: u32, tx: Sender<Bytes>) {
let mut lock = self.streams.write().await; let mut lock = self.streams.write().await;
lock.insert(stream_id, tx); lock.insert(stream_id, tx);
+26 -37
View File
@@ -1,14 +1,16 @@
use crate::{ use crate::{
protocol::errors::ErrorAction, protocol::errors::ErrorAction,
proxy::connection::{ proxy::connection::{
connection::{Connection, ConnectionRole, BUF_SIZE}, connection::{
ClientHandler, Connection, ConnectionRole, ServerHandler, TunnelHandler, BUF_SIZE,
},
engine::TunnelEngine, engine::TunnelEngine,
muxer::Muxer, muxer::Muxer,
}, },
tlseng::profile::BrowserProfile, tlseng::profile::BrowserProfile,
}; };
use bytes::BytesMut; use bytes::BytesMut;
use netrunner_logger::{error, info, instrument}; use netrunner_logger::{error, info};
use tokio::{ use tokio::{
io::{AsyncReadExt, AsyncWriteExt}, io::{AsyncReadExt, AsyncWriteExt},
net::{TcpListener, TcpStream}, net::{TcpListener, TcpStream},
@@ -21,7 +23,6 @@ pub struct Network {
role: ConnectionRole, role: ConnectionRole,
remote_proxy_addr: Option<String>, remote_proxy_addr: Option<String>,
} }
impl Network { impl Network {
pub fn new( pub fn new(
host: String, host: String,
@@ -42,65 +43,53 @@ impl Network {
match self.role { match self.role {
ConnectionRole::Client => { ConnectionRole::Client => {
info!("Starting Client mode: Initializing persistent tunnel to proxy..."); info!("Starting Client mode");
let server_addr = self
let muxer = match self.initialize_client_tunnel(token.clone()).await { .remote_proxy_addr
.as_ref()
.ok_or("No proxy addr")
.unwrap();
let muxer = match ClientHandler::connect(server_addr, token.clone()).await {
Ok(m) => m, Ok(m) => m,
Err(e) => { Err(e) => {
error!(error = %e, "Global tunnel failed. Exit."); error!(error = %e, "Global tunnel failed.");
return; return;
} }
}; };
let listener = TcpListener::bind(&addr).await.expect("SOCKS bind failed"); let listener = TcpListener::bind(&addr).await.expect("SOCKS bind failed");
info!(socks_addr = %addr, "SOCKS5 ready");
loop { loop {
tokio::select! { tokio::select! {
_ = token.cancelled() => { _ = token.cancelled() => break,
info!("SOCKS listener: Shutting down...");
break;
}
res = listener.accept() => { res = listener.accept() => {
if let Ok((stream, client_addr)) = listener.accept().await { if let Ok((stream, client_addr)) = res {
let current_muxer = muxer.clone(); let conn = Connection::new(stream, client_addr, false);
let handler = ClientHandler{ conn, muxer: muxer.clone() };
tokio::spawn(async move { tokio::spawn(async move {
let connection = Connection::new(stream, client_addr, false); if let Err(e) = handler.run().await {
let _ = connection.handle_socks_client(current_muxer).await; error!(error = %e, "Client handler error");
}
}); });
} }
} }
} }
} }
} }
ConnectionRole::Server => { ConnectionRole::Server => {
let listener = TcpListener::bind(&addr) let listener = TcpListener::bind(&addr).await.expect("Server bind failed");
.await
.expect("Failed to bind Server port");
info!(listen_addr = %addr, "Proxy Server listening for incoming tunnels");
loop { loop {
tokio::select! { tokio::select! {
_ = token.cancelled() => { _ = token.cancelled() => break,
info!("Server listener: Shutting down...");
break;
}
res = listener.accept() => { res = listener.accept() => {
match res { if let Ok((stream, client_addr)) = res {
Ok((stream, client_addr)) => { let conn = Connection::new(stream, client_addr, true);
let connection = Connection::new(stream, client_addr, true); let handler = ServerHandler { conn, token: token.clone() };
let connection_token = token.clone();
tokio::spawn(async move { tokio::spawn(async move {
if let Err(e) = connection.handle_server_tunnel(connection_token).await { if let Err(e) = handler.run().await {
error!(client = %client_addr, error = %e, "Tunnel error"); error!(client = %client_addr, error = %e, "Server handler error");
} }
}); });
} }
Err(e) => {
error!(error = %e, "Failed to accept connection");
}
}
} }
} }
} }