update processes and code style

This commit is contained in:
2026-03-01 17:49:58 +07:00
parent 3590d1a435
commit 322dc5b6b0
20 changed files with 547 additions and 769 deletions
+9 -12
View File
@@ -75,14 +75,13 @@ impl AeadPacker for ChaChaCipher {
// Сначала получаем текущий counter для лога (до того, как next_nonce его инкрементирует)
let current_counter = self.encrypt_state.counter;
let nonce = self.encrypt_state.next_nonce();
let nonce_hex = hex::encode(nonce);
let data_len = data.len();
match self.encrypt_cipher.encrypt_in_place(&nonce, &[], data) {
Ok(_) => {
tracing::trace!(
counter = current_counter,
nonce = %nonce_hex,
nonce = %hex::encode(nonce),
len = data_len,
"Encryption successful"
);
@@ -91,7 +90,7 @@ impl AeadPacker for ChaChaCipher {
Err(e) => {
tracing::error!(
counter = current_counter,
nonce = %nonce_hex,
nonce = %hex::encode(nonce),
len = data_len,
error = ?e,
"AEAD encryption failure"
@@ -104,29 +103,27 @@ impl AeadPacker for ChaChaCipher {
fn decrypt(&mut self, data: &mut BytesMut) -> Result<Bytes, chacha20poly1305::aead::Error> {
let current_counter = self.decrypt_state.counter;
let nonce = self.decrypt_state.next_nonce();
let nonce_hex = hex::encode(nonce);
let data_len = data.len();
let data_prefix = if data.len() >= 8 {
hex::encode(&data[..8])
} else {
hex::encode(data.as_ref())
};
match self.decrypt_cipher.decrypt_in_place(&nonce, &[], data) {
Ok(_) => {
tracing::trace!(
counter = current_counter,
nonce = %nonce_hex,
nonce = %hex::encode(nonce),
len = data_len,
"Decryption successful"
);
Ok(data.split().freeze())
}
Err(e) => {
let data_prefix = if data.len() >= 8 {
hex::encode(&data[..8])
} else {
hex::encode(data.as_ref())
};
tracing::error!(
counter = current_counter,
nonce = %nonce_hex,
nonce = %hex::encode(nonce),
len = data_len,
prefix = %data_prefix,
error = ?e,
+1 -1
View File
@@ -7,7 +7,7 @@ pub fn logger_init() {
.with_line_number(true); // Показывать строку кода (очень полезно для дебага)
let filter_layer = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new("trace")) // По умолчанию уровень info
.or_else(|_| EnvFilter::try_new("info")) // По умолчанию уровень info
.unwrap();
tracing_subscriber::registry()
@@ -168,12 +168,6 @@ impl TlsBridge {
}
}
/// Вспомогательный метод для упаковки уже готового Handshake-сообщения в TlsRecord
pub fn pack_handshake(payload: Bytes) -> Bytes {
let record = TlsRecord::new(ContentType::Handshake, ProtocolVersion::Tls12, payload);
record.serialize()
}
pub fn pack_app_data(buffer: Bytes) -> Bytes {
TlsRecord::build_application_data(buffer)
}
-2
View File
@@ -1,2 +0,0 @@
pub mod netr_bridge;
pub mod tls_bridge;
+36 -62
View File
@@ -3,7 +3,7 @@ use bytes::{Bytes, BytesMut};
use crate::crypto::aead::AeadPacker;
use crate::crypto::chacha::ChaChaCipher;
use crate::crypto::session::SessionKeys;
use crate::protocol::codec::bridges::tls_bridge::TlsBridge;
use crate::protocol::codec::bridge::TlsBridge;
use crate::protocol::codec::frame::{Frame, FrameHeader, FrameType};
use crate::protocol::codec::padding::Padding;
use crate::protocol::errors::{ErrorAction, ErrorStage, TlsError};
@@ -24,30 +24,24 @@ impl Codec {
staging: BytesMut::new(),
}
}
//maybe generator?
//should anwer socks5 and open connection to proxy server
/// Логика для Клиента: Генерирует байты ClientHello для инициализации соединения.
/// Клиент: генерирует TLS Record [ ClientHello ]
pub fn make_client_handshake(
&mut self,
profile: &BrowserProfile,
host: &str,
) -> Result<Bytes, TlsError> {
// 1. Извлекаем публичный ключ нашей текущей сессии
let my_pub_key = self.session_keys.ecdh.public_key.to_bytes();
// (Убедись, что метод возвращает [u8; 32])
let pub_key = self.session_keys.ecdh.public_key.to_bytes();
// 2. Передаем его в мост
Ok(TlsBridge::wrap_client_hello(
profile,
host,
&my_pub_key,
&pub_key,
self.session_keys.salt.get_local(),
))
}
/// Сервер: берет буфер, достает ClientHello и генерирует в ответ TLS Record [ ServerHello ]
pub fn make_server_handshake(&mut self, buffer: &mut BytesMut) -> Result<Bytes, TlsError> {
// 1. Распаковываем сообщение клиента
let client_msg = TlsBridge::unpack_handshake(buffer)?.ok_or_else(|| {
TlsError::new(
ErrorStage::Handshake("No CH"),
@@ -56,7 +50,6 @@ impl Codec {
)
})?;
// 2. Генерируем ответный ServerHello рекорд
let server_pub_key = self.session_keys.ecdh.public_key.to_bytes();
let server_hello_record = TlsBridge::wrap_server_hello(
&client_msg,
@@ -64,8 +57,6 @@ impl Codec {
self.session_keys.salt.get_local(),
)?;
// 3. ОБНОВЛЕНИЕ КЛЮЧЕЙ НА СЕРВЕРЕ
// Передаем true, так как сервер ПАРСИТ ClientHello (смещение 6 байт)
let (w_key, w_iv, r_key, r_iv) = self
.session_keys
.update_keys(client_msg.random(), client_msg.extensions(), true)
@@ -170,68 +161,51 @@ impl Codec {
}
pub fn inbound(&mut self, buffer: &mut BytesMut) -> Result<Option<Frame>, TlsError> {
// Логгируем входящее состояние сетевого буфера (TLS слой)
if !buffer.is_empty() {
let header = &buffer[..std::cmp::min(buffer.len(), 5)];
tracing::debug!(
buf_len = buffer.len(),
header_hex = %hex::encode(header),
"RAW TLS buffer state"
);
// 1. Сначала проверяем, нет ли уже готового фрейма в staging с прошлого раза
if !self.staging.is_empty() {
if let Some(frame) = self.try_parse_frame()? {
return Ok(Some(frame));
}
}
// --- ШАГ 1: Извлекаем ВСЕ доступные TLS-рекорды и расшифровываем в staging ---
// Мы крутим цикл, пока TlsBridge может "откусить" целый TLS-рекорд из buffer
// 2. Распаковываем ВСЕ доступные TLS-рекорды из сетевого буфера
while let Some(app_data) = TlsBridge::unpack_app_data(buffer)? {
let mut encrypted_chunk = BytesMut::from(app_data.payload.as_ref());
let raw_len = encrypted_chunk.len();
// Берем Bytes напрямую (app_data.payload — это уже Bytes)
let mut data_to_decrypt = BytesMut::from(app_data.payload);
// Расшифровываем кусок
let decrypted_chunk = self.crypto.decrypt(&mut encrypted_chunk).map_err(|e| {
tracing::error!(len = raw_len, "Decryption failed: {:?}", e);
// Дешифруем "на месте" (In-place decryption)
// Твоя библиотека ChaCha скорее всего поддерживает дешифровку прямо в том же буфере
let decrypted = self.crypto.decrypt(&mut data_to_decrypt).map_err(|_| {
TlsError::new(
ErrorStage::Tls("Decryption error"),
ErrorStage::Tls("Decr error"),
ErrorAction::Drop,
Bytes::new(),
)
})?;
// КЛАДЕМ В ЧИСТУЮ ЗОНУ: расшифрованный поток байтов нашего протокола
self.staging.extend_from_slice(&decrypted_chunk);
// ВАЖНО: Вместо extend_from_slice (копирование), используем split_off/unsplit или просто Bytes
// Если staging — это BytesMut, используй put или reserve
self.staging.extend_from_slice(&decrypted); // Увы, BytesMut требует копирования для конкатенации
tracing::debug!(
added = decrypted_chunk.len(),
total_staging = self.staging.len(),
"Decrypted data moved to staging"
);
}
// --- ШАГ 2: Парсим Frame из "чистых" данных в staging ---
if !self.staging.is_empty() {
// Важно: Frame::parse должен вызывать advance() или split_to() у staging
match Frame::parse(&mut self.staging) {
Ok(Some(frame)) => {
tracing::info!(
stream_id = frame.header.stream_id,
"Frame successfully parsed from staging"
);
return Ok(Some(frame));
}
Ok(None) => {
tracing::debug!("Frame is incomplete in staging, waiting for more TLS records");
return Ok(None);
}
Err(e) => {
tracing::error!("Frame parse error: {:?}", e);
return Err(TlsError::new(
ErrorStage::Tls("Frame parse error"),
ErrorAction::Drop,
Bytes::new(),
));
}
// НО! Мы можем попытаться распарсить фрейм сразу после добавления каждого рекорда
if let Some(frame) = self.try_parse_frame()? {
return Ok(Some(frame));
}
}
Ok(None)
}
// Выносим парсинг в отдельный метод, чтобы не дублировать код
fn try_parse_frame(&mut self) -> Result<Option<Frame>, TlsError> {
match Frame::parse(&mut self.staging) {
Ok(Some(frame)) => Ok(Some(frame)),
Ok(None) => Ok(None),
Err(_) => Err(TlsError::new(
ErrorStage::Tls("Parse error"),
ErrorAction::Drop,
Bytes::new(),
)),
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
mod bridges;
mod bridge;
pub mod codec;
pub mod frame;
mod padding;
+44
View File
@@ -1,5 +1,7 @@
use bytes::{BufMut, Bytes, BytesMut};
use crate::protocol::parser::parser::Parser;
pub const SOCKS5_VERSION: u8 = 0x05;
pub const REPLY_SUCCESS: u8 = 0x00;
pub const REPLY_AUTH_FAILURE: u8 = 0xFF;
@@ -17,6 +19,48 @@ pub enum SocksRequest {
Connect { command: u8, target: SocksTarget },
Unknown,
}
impl SocksRequest {
pub async fn handle_handshake<S>(
stream: &mut S,
buf: &mut BytesMut,
) -> Result<SocksTarget, String>
where
S: tokio::io::AsyncReadExt + tokio::io::AsyncWriteExt + Unpin,
{
// 1. Handshake Phase
loop {
// Используем трейт Parser
if let Some(req) = Self::parse(buf)? {
if let SocksRequest::Handshake { .. } = req {
let mut reply = BytesMut::with_capacity(2);
SocksReply::HandshakeSelect { method: 0x00 }.write_to(&mut reply);
stream.write_all(&reply).await.map_err(|e| e.to_string())?;
break;
}
return Err("Expected Handshake, got something else".into());
}
if stream.read_buf(buf).await.map_err(|e| e.to_string())? == 0 {
return Err("Client closed during greeting".into());
}
}
// 2. Connect Request Phase
loop {
if let Some(req) = Self::parse(buf)? {
if let SocksRequest::Connect { command, target } = req {
// Проверяем, что это именно CONNECT (0x01)
if command != 0x01 {
return Err(format!("Unsupported SOCKS command: 0x{:02X}", command));
}
return Ok(target);
}
}
if stream.read_buf(buf).await.map_err(|e| e.to_string())? == 0 {
return Err("Client closed during connect request".into());
}
}
}
}
#[derive(Debug)]
pub enum SocksReply {
+70
View File
@@ -0,0 +1,70 @@
use crate::protocol::codec::frame::FrameType;
use crate::proxy::connection::muxer::{MuxMessage, Muxer};
use bytes::{Bytes, BytesMut};
use tokio::sync::mpsc;
use tracing::{debug, error};
pub async fn run_proxy_bridge<R, W>(
stream_id: u32,
mut reader: R,
mut writer: W,
muxer: Muxer,
mut v_rx: mpsc::Receiver<Bytes>,
) where
R: tokio::io::AsyncReadExt + Unpin,
W: tokio::io::AsyncWriteExt + Unpin,
{
let mut buf = BytesMut::with_capacity(16384);
loop {
tokio::select! {
res = reader.read_buf(&mut buf) => {
match res {
Ok(0) => {
debug!(stream_id, "Socket closed (EOF)");
break;
}
Ok(_) => {
let msg = MuxMessage {
stream_id,
frame_type: FrameType::Data,
data: buf.split().freeze(),
};
if muxer.to_network.send(msg).await.is_err() { break; }
}
Err(e) => {
error!(stream_id, error = %e, "Socket read error");
break;
}
}
}
// Читаем из туннеля (v_rx) -> шлем в сокет
maybe_data = v_rx.recv() => {
match maybe_data {
Some(data) => {
if data.is_empty() { break; } // EOF от другой стороны
if let Err(e) = writer.write_all(&data).await {
error!(stream_id, error = %e, "Socket write error");
break;
}
}
None => {
debug!(stream_id, "Virtual channel closed");
break;
}
}
}
}
}
// Финализация (общая для всех)
let _ = muxer
.to_network
.send(MuxMessage {
stream_id,
frame_type: FrameType::Close,
data: Bytes::new(),
})
.await;
muxer.remove_stream(stream_id).await;
}
-43
View File
@@ -1,43 +0,0 @@
use bytes::BytesMut;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf}; // <--- ОБЯЗАТЕЛЬНО ТУТ
pub struct BufPair {
pub write_buf: BytesMut,
pub read_buf: BytesMut,
}
const BUF_SIZE: usize = 4096;
impl BufPair {
pub fn new() -> Self {
let write_buf = BytesMut::with_capacity(BUF_SIZE);
let read_buf = BytesMut::with_capacity(BUF_SIZE);
Self {
write_buf,
read_buf,
}
}
pub async fn read_from(&mut self, reader: &mut OwnedReadHalf) -> Result<usize, String> {
let n = reader
.read_buf(&mut self.read_buf)
.await
.map_err(|e| e.to_string())?;
if n == 0 {
return Err("Connection closed by peer".to_string());
}
Ok(n)
}
pub async fn write_from(&mut self, writer: &mut OwnedWriteHalf) -> Result<(), String> {
writer
.write_all_buf(&mut self.write_buf)
.await
.map_err(|e| e.to_string())
}
pub fn reset(&mut self) {
self.read_buf.clear();
self.write_buf.clear();
}
}
+173 -176
View File
@@ -1,6 +1,6 @@
use bytes::{Bytes, BytesMut};
use tracing::{instrument, info, debug, error, trace, warn};
use std::{collections::HashMap, net::SocketAddr};
use std::{net::SocketAddr};
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::{
@@ -21,22 +21,16 @@ use crate::{
parser::parser::Parser,
},
proxy::connection::{
buf_pair::BufPair,
engine::TunnelEngine,
handler::spawn_client_local_handler_with_rx,
muxer::{MuxMessage, Muxer},
bridge::run_proxy_bridge, engine::TunnelEngine, handler::StreamHandler, muxer::{MuxMessage, Muxer}
},
};
pub struct VirtualStreams {
pub channels: HashMap<u32, tokio::sync::mpsc::Sender<Bytes>>,
pub struct BufPair {
pub write_buf: BytesMut,
pub read_buf: BytesMut,
}
pub const BUF_SIZE: usize = 16384;
pub enum ConnectionState {
Authorize,
Tunnel(VirtualStreams),
Close,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ConnectionRole {
@@ -48,7 +42,7 @@ pub struct Connection {
addr: SocketAddr,
pub inbound: OwnedReadHalf,
pub outbound: OwnedWriteHalf,
pub buffers: BufPair,
pub read_buf: BytesMut,
pub codec: Codec,
}
@@ -63,194 +57,197 @@ impl Connection {
addr,
inbound,
outbound,
buffers: BufPair::new(),
read_buf: BytesMut::with_capacity(BUF_SIZE),
codec: Codec::new(init),
}
}
/// Читает и парсит запрос SOCKS5 из входящего потока
async fn read_socks_request(&mut self) -> Result<SocksRequest, String> {
loop {
// Попытка парсинга из текущего буфера
match SocksRequest::parse(&mut self.buffers.read_buf) {
Ok(Some(req)) => {
// Используем Debug-вывод (?req), так как SocksRequest обычно Enum
info!(client = %self.addr, request = ?req, "SOCKS request successfully parsed");
return Ok(req);
async fn read_socks_request(&mut self) -> Result<SocksRequest, String> {
loop {
// Попытка парсинга из текущего буфера
match SocksRequest::parse(&mut self.read_buf) {
Ok(Some(req)) => {
// Используем Debug-вывод (?req), так как SocksRequest обычно Enum
info!(client = %self.addr, request = ?req, "SOCKS request successfully parsed");
return Ok(req);
}
Ok(None) => {
// Это не ошибка, просто данных в сокете пока меньше, чем размер структуры SOCKS
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));
}
}
Ok(None) => {
// Это не ошибка, просто данных в сокете пока меньше, чем размер структуры SOCKS
trace!(client = %self.addr, buffer_len = self.buffers.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));
}
}
// Чтение новых данных из сокета
let n = self
.inbound
.read_buf(&mut self.buffers.read_buf)
// Чтение новых данных из сокета
let n = self
.inbound
.read_buf(&mut self.read_buf)
.await
.map_err(|e| {
error!(client = %self.addr, error = %e, "Failed to read from socket during SOCKS handshake");
e.to_string()
})?;
if n == 0 {
warn!(client = %self.addr, "Client closed connection prematurely during SOCKS handshake");
return Err("Client closed connection during SOCKS handshake".into());
}
trace!(client = %self.addr, read_bytes = n, "Read data from client for SOCKS handshake");
}
}
/// Отправляет SOCKS ответ
async fn send_socks_reply(&mut self, reply: SocksReply) -> Result<(), String> {
let mut buf = BytesMut::with_capacity(24);
debug!(client = %self.addr, reply = ?reply, "Sending SOCKS reply to client");
reply.write_to(&mut buf);
self.outbound
.write_all(&buf)
.await
.map_err(|e| {
error!(client = %self.addr, error = %e, "Failed to read from socket during SOCKS handshake");
error!(client = %self.addr, error = %e, "Failed to send SOCKS reply");
e.to_string()
})?;
if n == 0 {
warn!(client = %self.addr, "Client closed connection prematurely during SOCKS handshake");
return Err("Client closed connection during SOCKS handshake".into());
}
trace!(client = %self.addr, read_bytes = n, "Read data from client for SOCKS handshake");
Ok(())
}
}
/// Отправляет SOCKS ответ
async fn send_socks_reply(&mut self, reply: SocksReply) -> Result<(), String> {
let mut buf = BytesMut::with_capacity(24);
debug!(client = %self.addr, reply = ?reply, "Sending SOCKS reply to client");
reply.write_to(&mut buf);
#[instrument(
name = "socks_handler",
skip(self, muxer),
fields(addr = %self.addr)
)]
pub async fn handle_socks_client(mut self, muxer: Muxer) -> Result<(), String> {
info!("Starting SOCKS multiplexed handling");
self.outbound
.write_all(&buf)
.await
.map_err(|e| {
error!(client = %self.addr, error = %e, "Failed to send SOCKS reply");
e.to_string()
// 1. SOCKS Handshake
debug!("Reading SOCKS handshake request");
let _ = self.read_socks_request().await.map_err(|e| {
error!("SOCKS handshake failed: {}", e);
e
})?;
Ok(())
}
#[instrument(
name = "socks_handler",
skip(self, muxer),
fields(addr = %self.addr)
)]
pub async fn handle_socks_client(mut self, muxer: Muxer) -> Result<(), String> {
info!("Starting SOCKS multiplexed handling");
// 1. SOCKS Handshake
debug!("Reading SOCKS handshake request");
let _ = self.read_socks_request().await.map_err(|e| {
error!("SOCKS handshake failed: {}", e);
e
})?;
self.send_socks_reply(SocksReply::HandshakeSelect { method: 0x00 }).await?;
// 2. SOCKS Connect
// 2. SOCKS Connect - читаем, КУДА хочет браузер
let req = self.read_socks_request().await?;
let target = if let SocksRequest::Connect { target, .. } = req {
target
} else {
return Err("Expected Connect".into());
};
let stream_id = muxer.next_id();
let target_str = match &target {
SocksTarget { host, port } => format!("{}:{}", String::from_utf8_lossy(host), port),
};
// --- НОВАЯ ЛОГИКА ОЖИДАНИЯ ---
// Регистрируем временный канал, чтобы получить Connect-подтверждение от сервера
let (v_tx, mut v_rx) = mpsc::channel::<Bytes>(100);
muxer.register_stream(stream_id, v_tx).await;
// Отправляем Connect-кадр на сервер
muxer.to_network.send(MuxMessage {
stream_id,
frame_type: FrameType::Connect,
data: Bytes::from(target_str),
}).await.map_err(|e| e.to_string())?;
let first_payload = 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.ok();
return Err("Target connection failed".into());
}
};
// Проверяем код ответа (второй байт в SOCKS5)
if first_payload.len() >= 2 && first_payload[1] == 0x00 {
debug!(stream_id, "Server confirmed connection, forwarding SOCKS reply to browser");
// ВАЖНО: Отправляем браузеру ТО, что прислал сервер (те самые 10 байт)
// Не создаем новый SocksReply вручную, а пробрасываем байты сервера
self.outbound.write_all(&first_payload).await.map_err(|e| e.to_string())?;
} else {
// Если сервер прислал ошибку (reply_code != 0), тоже пробрасываем её браузеру и выходим
self.outbound.write_all(&first_payload).await.ok();
return Err("Server rejected connection".into());
self.send_socks_reply(SocksReply::HandshakeSelect { method: 0x00 }).await?;
// 2. SOCKS Connect
// 2. SOCKS Connect - читаем, КУДА хочет браузер
let req = self.read_socks_request().await?;
let target = if let SocksRequest::Connect { target, .. } = req {
target
} else {
return Err("Expected Connect".into());
};
let stream_id = muxer.next_id();
let target_str = match &target {
SocksTarget { host, port } => format!("{}:{}", String::from_utf8_lossy(host), port),
};
// --- НОВАЯ ЛОГИКА ОЖИДАНИЯ ---
// Регистрируем временный канал, чтобы получить Connect-подтверждение от сервера
let (v_tx, mut v_rx) = mpsc::channel::<Bytes>(1024);
muxer.register_stream(stream_id, v_tx).await;
// Отправляем Connect-кадр на сервер
muxer.to_network.send(MuxMessage {
stream_id,
frame_type: FrameType::Connect,
data: Bytes::from(target_str),
}).await.map_err(|e| e.to_string())?;
let first_payload = 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.ok();
return Err("Target connection failed".into());
}
};
// Проверяем код ответа (второй байт в SOCKS5)
if first_payload.len() >= 2 && first_payload[1] == 0x00 {
debug!(stream_id, "Server confirmed connection, forwarding SOCKS reply to browser");
// ВАЖНО: Отправляем браузеру ТО, что прислал сервер (те самые 10 байт)
// Не создаем новый SocksReply вручную, а пробрасываем байты сервера
self.outbound.write_all(&first_payload).await.map_err(|e| e.to_string())?;
} else {
// Если сервер прислал ошибку (reply_code != 0), тоже пробрасываем её браузеру и выходим
self.outbound.write_all(&first_payload).await.ok();
return Err("Server rejected connection".into());
}
// 4. Разбираем self и запускаем хендлер
let Self { inbound: browser_in, outbound: browser_out, .. } = self;
let muxer_clone = muxer.clone();
tokio::spawn(async move {
run_proxy_bridge(stream_id, browser_in, browser_out, muxer_clone, v_rx).await;
});
Ok(())
}
// 4. Разбираем self и запускаем хендлер
let Self { inbound: browser_in, outbound: browser_out, .. } = self;
// Передаем v_rx (в котором уже могут быть данные от сервера после "OK") в хендлер
spawn_client_local_handler_with_rx(stream_id, browser_in, browser_out, muxer.clone(), v_rx);
#[instrument(
name = "server_tunnel",
skip(self),
fields(addr = %self.addr)
)]
pub async fn handle_server_tunnel(mut self) -> Result<(), String> {
info!("Acting as TLS Server, waiting for ClientHello");
Ok(())
}
// Создаем Muxer для сервера
let (mux_tx, mux_rx) = mpsc::channel(16384);
let muxer = Muxer::new(mux_tx.clone(), false); // false, так как это Сервер
#[instrument(
name = "server_tunnel",
skip(self),
fields(addr = %self.addr)
)]
pub async fn handle_server_tunnel(mut self) -> Result<(), String> {
info!("Acting as TLS Server, waiting for ClientHello");
// 1. TLS Handshake
let server_hello_bytes = loop {
match self.codec.make_server_handshake(&mut self.read_buf) {
Ok(bytes) => {
info!("ClientHello received, sending ServerHello");
break bytes;
},
Err(e) if e.action == ErrorAction::Wait => {
let n = self.inbound.read_buf(&mut self.read_buf).await
.map_err(|err| format!("Read error: {}", err))?;
// Создаем Muxer для сервера
let (mux_tx, mux_rx) = mpsc::channel(1024);
let muxer = Muxer::new(mux_tx.clone(), false); // false, так как это Сервер
// 1. TLS Handshake
let server_hello_bytes = loop {
match self.codec.make_server_handshake(&mut self.buffers.read_buf) {
Ok(bytes) => {
info!("ClientHello received, sending ServerHello");
break bytes;
},
Err(e) if e.action == ErrorAction::Wait => {
let n = self.inbound.read_buf(&mut self.buffers.read_buf).await
.map_err(|err| format!("Read error: {}", err))?;
if n == 0 { return Err("Client closed connection".into()); }
if n == 0 { return Err("Client closed connection".into()); }
}
Err(e) => return Err(format!("TLS error: {:?}", e)),
}
Err(e) => return Err(format!("TLS error: {:?}", e)),
}
};
};
self.outbound.write_all(&server_hello_bytes).await.map_err(|e| e.to_string())?;
info!("TLS Tunnel established as server");
self.outbound.write_all(&server_hello_bytes).await.map_err(|e| e.to_string())?;
info!("TLS Tunnel established as server");
// 2. Передача управления в TunnelEngine
debug!("Handover to TunnelEngine");
let engine = TunnelEngine {
inbound: self.inbound,
outbound: self.outbound,
codec: self.codec,
buffers: self.buffers,
mux_rx,
muxer,
role: ConnectionRole::Server,
};
let handler = std::sync::Arc::new(StreamHandler::new(muxer.clone(), ConnectionRole::Server));
engine.run().await.map_err(|e| {
error!("TunnelEngine error: {}", e);
e
})
}
// 2. Передача управления в TunnelEngine
debug!("Handover to TunnelEngine");
let engine = TunnelEngine {
inbound: self.inbound,
outbound: self.outbound,
codec: self.codec,
read_buf: self.read_buf,
mux_rx,
handler
};
engine.run().await.map_err(|e| {
error!("TunnelEngine error: {}", e);
e
})
}
}
+67 -107
View File
@@ -1,149 +1,109 @@
use crate::{
protocol::{
codec::{
codec::Codec,
frame::{Frame, FrameType},
},
errors::ErrorAction,
},
proxy::connection::{
buf_pair::BufPair,
connection::ConnectionRole,
handler::spawn_server_target_handler,
muxer::{MuxMessage, Muxer},
},
use std::sync::Arc;
use bytes::BytesMut;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::tcp::{OwnedReadHalf, OwnedWriteHalf},
sync::mpsc::Receiver,
};
use tracing::error;
use crate::{
protocol::{codec::codec::Codec, errors::ErrorAction},
proxy::connection::{handler::StreamHandler, muxer::MuxMessage},
};
use bytes::Bytes;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
use tokio::sync::mpsc::Receiver;
use tracing::{debug, error, info, trace, warn};
pub struct TunnelEngine {
pub inbound: OwnedReadHalf,
pub outbound: OwnedWriteHalf,
pub codec: Codec,
pub buffers: BufPair,
pub read_buf: BytesMut,
pub mux_rx: Receiver<MuxMessage>,
pub muxer: Muxer,
pub role: ConnectionRole,
pub handler: Arc<StreamHandler>, // Добавь это вместо прямого вызова логики
}
impl TunnelEngine {
pub async fn run(mut self) -> Result<(), String> {
info!(role = ?self.role, "TunnelEngine spinning up");
pub async fn run(self) -> Result<(), String> {
let mut inbound = self.inbound;
let mut outbound = self.outbound;
let mut codec = self.codec;
let mut read_buf = self.read_buf;
let mut mux_rx = self.mux_rx;
let handler = self.handler;
loop {
tokio::select! {
// 1. Физический Inbound (Сеть -> Muxer)
// Теперь возвращает Vec<Frame>, чтобы обработать всё накопленное
res = Self::process_inbound(&mut self.inbound, &mut self.codec, &mut self.buffers) => {
match res {
Ok(frames) => {
for frame in frames {
self.handle_incoming_frame(frame).await;
}
}
Err(e) => {
if e == "EOF" {
info!("Physical connection closed by remote (EOF)");
} else {
error!(error = %e, "Critical error in process_inbound");
}
return Err(e);
}
}
res = Self::process_inbound(&mut inbound, &mut codec, &mut read_buf, &handler) => {
res?
}
// 2. Физический Outbound (Muxer -> Сеть)
Some(msg) = self.mux_rx.recv() => {
if let Err(e) = self.handle_outbound_msg(msg).await {
return Err(e);
}
// НУЖНО ОТПРАВИТЬ В СЕТЬ (В сторону удаленного прокси)
Some(msg) = mux_rx.recv() => {
Self::handle_outbound( &mut outbound, &mut codec, msg).await?;
}
}
}
}
/// Логика обработки конкретного фрейма (разгружаем основной loop)
async fn handle_incoming_frame(&mut self, frame: Frame) {
let stream_id = frame.header.stream_id;
let frame_type = frame.header.frame_type;
trace!(stream_id = frame.header.stream_id, f_type = ?frame.header.frame_type, len = frame.payload.len(), "Engine received frame from network");
match frame_type {
FrameType::Connect => {
match self.role {
ConnectionRole::Server => {
let target = String::from_utf8_lossy(&frame.payload);
info!(stream_id, target = %target, "New Connect request received");
spawn_server_target_handler(stream_id, frame.payload, self.muxer.clone())
.await;
}
ConnectionRole::Client => {
// Тот самый фикс: клиент получает Connect как подтверждение (ACK)
debug!(stream_id, "Connection confirmed by server");
self.muxer.dispatch_to_local(stream_id, frame.payload).await;
}
}
}
FrameType::Data => {
self.muxer.dispatch_to_local(stream_id, frame.payload).await;
}
FrameType::Close => {
info!(stream_id, "Received Close frame, tearing down stream");
// Важно: muxer должен не просто удалить, а послать EOF в локальный канал
self.muxer.dispatch_to_local(stream_id, Bytes::new()).await;
self.muxer.remove_stream(stream_id).await;
}
_ => debug!(stream_id, ?frame_type, "Received unhandled frame type"),
}
}
/// Вспомогательная функция для чтения из сети
async fn process_inbound(
inbound: &mut OwnedReadHalf,
codec: &mut Codec,
buffers: &mut BufPair,
) -> Result<Vec<Frame>, String> {
let mut frames = Vec::new();
// Сначала читаем данные из сокета в буфер
read_buf: &mut BytesMut,
handler: &Arc<StreamHandler>,
) -> Result<(), String> {
let n = inbound
.read_buf(&mut buffers.read_buf)
.read_buf(read_buf)
.await
.map_err(|e| e.to_string())?;
if n == 0 && buffers.read_buf.is_empty() {
if n == 0 && read_buf.is_empty() {
return Err("EOF".into());
}
// Теперь пытаемся достать столько фреймов, сколько получится
loop {
match codec.inbound(&mut buffers.read_buf) {
Ok(Some(frame)) => frames.push(frame),
Ok(None) => break, // Больше полных фреймов нет
Err(e) if e.action == ErrorAction::Wait => break,
Err(e) => return Err(format!("Codec error: {:?}", e)),
match codec.inbound(read_buf) {
// 1. Успешно достали фрейм
Ok(Some(frame)) => {
handler.handle(frame).await;
}
// 2. Данных в буфере недостаточно (нужно подождать еще)
Ok(None) => break,
// 3. Ошибка кодека
Err(e) => {
// Если кодек говорит "подожди", выходим из цикла парсинга
if e.action == ErrorAction::Wait {
break;
}
// Иначе — это реальная проблема (кривой TLS и т.д.)
return Err(format!("Codec error: {:?}", e));
}
}
}
Ok(frames)
Ok(())
}
async fn handle_outbound_msg(&mut self, msg: MuxMessage) -> Result<(), String> {
match self
.codec
.encrypt_data(msg.stream_id, msg.frame_type, msg.data)
{
async fn handle_outbound(
outbound: &mut OwnedWriteHalf,
codec: &mut Codec,
msg: MuxMessage,
) -> Result<(), String> {
// 1. Шифруем данные, используя только кодек
match codec.encrypt_data(msg.stream_id, msg.frame_type, msg.data) {
Ok(pkt) => {
self.outbound
// 2. Пишем в сокет, используя только outbound
outbound
.write_all(&pkt)
.await
.map_err(|e| e.to_string())?;
.map_err(|e| {
error!(stream_id = msg.stream_id, error = %e, "Failed to write encrypted data to network");
e.to_string()
})?;
Ok(())
}
Err(e) => Err(format!("Encryption error: {:?}", e)),
Err(e) => {
error!(stream_id = msg.stream_id, error = ?e, "Encryption failed for outbound message");
Err(format!("Encryption error: {:?}", e))
}
}
}
}
+82 -174
View File
@@ -1,190 +1,98 @@
use crate::protocol::codec::frame::FrameType;
use crate::protocol::codec::socks::{SocksReply, ATYP_IPV4, REPLY_SUCCESS};
use crate::proxy::connection::muxer::{MuxMessage, Muxer};
use bytes::{Bytes, BytesMut};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
use tokio::net::TcpStream;
use tokio::sync::mpsc;
use tracing::{debug, error, info, trace, warn};
use tracing::{debug, error, info};
pub fn spawn_client_local_handler_with_rx(
stream_id: u32,
mut r: OwnedReadHalf,
mut w: OwnedWriteHalf,
use crate::{
protocol::codec::{
frame::{Frame, FrameType},
socks::SocksReply,
},
proxy::connection::{bridge::run_proxy_bridge, connection::ConnectionRole, muxer::Muxer},
};
// proxy/connection/stream_handler.rs
pub struct StreamHandler {
muxer: Muxer,
mut v_rx: mpsc::Receiver<Bytes>, // Используем эту читалку, она уже зарегистрирована!
) {
// ВНИМАНИЕ: Здесь больше не создаем канал и не вызываем register_stream,
// так как это уже сделал handle_socks_client до вызова этой функции.
tokio::spawn(async move {
let mut buf = BytesMut::with_capacity(8192);
debug!(
stream_id,
"Spawned client local handler with existing receiver"
);
loop {
tokio::select! {
// 1. Читаем из браузера -> Шлем в общий туннель
res = r.read_buf(&mut buf) => {
match res {
Ok(0) => {
debug!(stream_id, "Browser closed connection (EOF)");
break;
}
Err(e) => {
error!(stream_id, error = %e, "Read error from browser");
break;
}
Ok(n) => {
let msg = MuxMessage {
stream_id,
frame_type: FrameType::Data,
data: buf.split().freeze(),
};
if muxer.to_network.send(msg).await.is_err() { break; }
}
}
}
// 2. Читаем из виртуального канала (данные из туннеля) -> Шлем браузеру
maybe_data = v_rx.recv() => {
match maybe_data {
Some(data) => {
if let Err(e) = w.write_all(&data).await {
error!(stream_id, error = %e, "Write error to browser");
break;
}
}
None => {
debug!(stream_id, "Virtual channel closed by Muxer");
break;
}
}
}
}
}
// КРИТИЧНО: Сообщаем серверу, что мы закрываем этот конкретный стрим
let _ = muxer
.to_network
.send(MuxMessage {
stream_id,
frame_type: FrameType::Close,
data: Bytes::new(),
})
.await;
// Чистим за собой в таблице стримов
muxer.remove_stream(stream_id).await;
info!(stream_id, "Client handler terminated");
});
role: ConnectionRole,
}
pub async fn spawn_server_target_handler(stream_id: u32, target_raw: Bytes, muxer: Muxer) {
let addr = String::from_utf8_lossy(&target_raw).to_string();
let (v_tx, mut v_rx) = mpsc::channel::<Bytes>(100);
muxer.register_stream(stream_id, v_tx).await;
tokio::spawn(async move {
info!(stream_id, target = %addr, "Attempting to connect to target");
impl StreamHandler {
pub fn new(muxer: Muxer, role: ConnectionRole) -> Self {
Self { muxer, role }
}
match TcpStream::connect(&addr).await {
Ok(stream) => {
// Формируем SOCKS5 Success Reply используя структуру
let mut reply_buf = BytesMut::with_capacity(10);
let reply = SocksReply::ConnectResult {
reply_code: REPLY_SUCCESS,
atyp: ATYP_IPV4,
addr: [0, 0, 0, 0],
port: 0,
};
reply.write_to(&mut reply_buf);
pub async fn handle(&self, frame: Frame) {
let stream_id = frame.header.stream_id;
// Отправляем подтверждение в сеть
let _ = muxer
.to_network
.send(MuxMessage {
stream_id,
frame_type: FrameType::Connect,
data: reply_buf.freeze(),
})
.await;
match frame.header.frame_type {
FrameType::Connect => self.on_connect(stream_id, frame.payload).await,
FrameType::Data => self.on_data(stream_id, frame.payload).await,
FrameType::Close => self.on_close(stream_id).await,
_ => debug!(stream_id, "Unhandled frame type"),
}
}
info!(stream_id, target = %addr, "Connected to target host, SOCKS reply sent");
async fn on_connect(&self, stream_id: u32, payload: Bytes) {
if self.role == ConnectionRole::Server {
let target_str = String::from_utf8_lossy(&payload).to_string();
let muxer = self.muxer.clone();
let (mut r, mut w) = stream.into_split();
let mut buf = BytesMut::with_capacity(8192);
let (v_tx, v_rx) = tokio::sync::mpsc::channel(100);
muxer.register_stream(stream_id, v_tx).await;
loop {
tokio::select! {
// Сеть -> Прокси -> Интернет (Запись в целевой хост)
Some(data) = v_rx.recv() => {
if data.is_empty() { break; } // EOF от локального клиента
if let Err(e) = w.write_all(&data).await {
warn!(stream_id, error = ?e, "Target write failed");
break;
}
}
// Интернет -> Прокси -> Сеть (Чтение из целевого хоста)
res = r.read_buf(&mut buf) => {
match res {
Ok(0) => {
debug!(stream_id, "Target host closed connection (EOF)");
break;
}
Ok(n) => {
let msg = MuxMessage {
stream_id,
frame_type: FrameType::Data,
data: buf.split().freeze(),
};
if muxer.to_network.send(msg).await.is_err() { break; }
}
Err(e) => {
error!(stream_id, error = %e, "Target read error");
break;
}
}
}
tokio::spawn(async move {
info!(stream_id, target = %target_str, "Attempting remote connection");
match tokio::net::TcpStream::connect(&target_str).await {
Ok(stream) => {
// --- ШАГ 2: ШЛЕМ ПОДТВЕРЖДЕНИЕ ---
let mut reply_buf = BytesMut::with_capacity(10);
let reply = SocksReply::ConnectResult {
reply_code: 0x00,
atyp: 0x01,
addr: [0, 0, 0, 0],
port: 0,
};
reply.write_to(&mut reply_buf);
let _ = muxer
.send_control(stream_id, FrameType::Connect, reply_buf.freeze())
.await;
// --- ШАГ 3: ЗАПУСКАЕМ МОСТ ---
let (r, w) = stream.into_split();
run_proxy_bridge(stream_id, r, w, muxer, v_rx).await;
}
Err(e) => {
error!(stream_id, error = %e, "Connection failed");
// Если не подключились — удаляем стрим, чтобы не висел в мапе
muxer.remove_stream(stream_id).await;
let mut reply_buf = BytesMut::with_capacity(10);
let reply = SocksReply::ConnectResult {
reply_code: 0x01,
atyp: 0x01,
addr: [0, 0, 0, 0],
port: 0,
};
reply.write_to(&mut reply_buf);
let _ = muxer
.send_control(stream_id, FrameType::Connect, reply_buf.freeze())
.await;
}
}
}
Err(e) => {
error!(stream_id, target = %addr, error = %e, "Connection to target failed");
// Формируем SOCKS5 Failure Reply (0x01 - General failure)
let mut reply_buf = BytesMut::with_capacity(10);
let reply = SocksReply::ConnectResult {
reply_code: 0x01,
atyp: ATYP_IPV4,
addr: [0, 0, 0, 0],
port: 0,
};
reply.write_to(&mut reply_buf);
let _ = muxer
.to_network
.send(MuxMessage {
stream_id,
frame_type: FrameType::Connect,
data: reply_buf.freeze(),
})
.await;
}
});
} else {
// Логика для клиента (проброс ответа сервера браузеру)
self.muxer.dispatch_to_local(stream_id, payload).await;
}
}
// Финализация: уведомляем сеть о закрытии и чистим муксер
let _ = muxer
.to_network
.send(MuxMessage {
stream_id,
frame_type: FrameType::Close,
data: Bytes::new(),
})
.await;
async fn on_data(&self, stream_id: u32, payload: Bytes) {
self.muxer.dispatch_to_local(stream_id, payload).await;
}
muxer.remove_stream(stream_id).await;
info!(stream_id, "Server target handler closed");
});
async fn on_close(&self, stream_id: u32) {
self.muxer.dispatch_to_local(stream_id, Bytes::new()).await;
self.muxer.remove_stream(stream_id).await;
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
pub mod buf_pair;
pub mod bridge;
pub mod connection;
pub mod engine;
pub mod handler;
+16 -1
View File
@@ -46,7 +46,6 @@ impl Muxer {
}
}
// Прокси-метод для получения ID
pub fn next_id(&self) -> u32 {
self.id_gen.next()
}
@@ -65,6 +64,22 @@ impl Muxer {
self.streams.write().await.remove(&stream_id);
}
pub async fn send_control(
&self,
stream_id: u32,
f_type: FrameType,
data: Bytes,
) -> Result<(), String> {
self.to_network
.send(MuxMessage {
stream_id,
frame_type: f_type,
data,
})
.await
.map_err(|e| e.to_string())
}
/// Отправляет входящие данные конкретному локальному обработчику
pub async fn dispatch_to_local(&self, stream_id: u32, data: Bytes) {
// Асинхронный лок сам умеет корректно работать с .await
+42 -60
View File
@@ -36,34 +36,26 @@ impl Network {
match self.role {
ConnectionRole::Client => {
// --- ЛОГИКА КЛИЕНТА ---
// 1. Создаем ОДИН туннель до прокси-сервера при старте
info!("Starting Client mode: Initializing persistent tunnel to proxy...");
let muxer = match self.initialize_client_tunnel().await {
Ok(m) => m,
Err(e) => {
error!(error = %e, "Failed to initialize global tunnel. Exiting.");
error!(error = %e, "Global tunnel failed. Exit.");
return;
}
};
// 2. Теперь слушаем SOCKS-запросы от браузера
let listener = TcpListener::bind(&addr)
.await
.expect("Failed to bind SOCKS port");
info!(socks_addr = %addr, "SOCKS5 server ready for browser connections");
let listener = TcpListener::bind(&addr).await.expect("SOCKS bind failed");
info!(socks_addr = %addr, "SOCKS5 ready");
loop {
if let Ok((stream, client_addr)) = listener.accept().await {
let current_muxer = muxer.clone();
tokio::spawn(async move {
// Используем новый метод handle_socks_client
// Здесь мы просто создаем Connection и сразу в SOCKS
let connection = Connection::new(stream, client_addr, false);
if let Err(e) = connection.handle_socks_client(current_muxer).await {
error!(client = %client_addr, error = %e, "SOCKS stream error");
}
let _ = connection.handle_socks_client(current_muxer).await;
});
}
}
@@ -93,71 +85,61 @@ impl Network {
/// Вспомогательный метод для Клиента: создает TLS туннель и запускает TunnelEngine
async fn initialize_client_tunnel(&self) -> Result<Muxer, String> {
let server_addr = self
.remote_proxy_addr
.as_ref()
.ok_or("Remote proxy address not configured")?;
let server_addr = self.remote_proxy_addr.as_ref().ok_or("No proxy addr")?;
// 1. Устанавливаем TCP соединение с сервером
// Вместо создания Connection (который нужен для обработки клиентов),
// работаем напрямую с TcpStream для первичного TLS-хендшейка.
let stream = TcpStream::connect(server_addr)
.await
.map_err(|e| format!("Connect to proxy failed: {}", e))?;
.map_err(|e| e.to_string())?;
let (mut inbound, mut outbound) = stream.into_split();
// 2. Создаем временный Connection
let dummy_addr = server_addr.parse().unwrap_or("0.0.0.0:0".parse().unwrap());
// Передаем stream (Connection сам сделает into_split внутри, если у тебя так написано в new)
let mut conn = Connection::new(stream, dummy_addr, false);
// Кодек создаем «с чистого листа»
let mut codec = crate::protocol::codec::codec::Codec::new(false);
// 3. TLS Handshake (Клиентская часть)
debug!("Starting persistent TLS handshake with proxy");
let ch = conn
.codec
// --- TLS Handshake ---
let ch = codec
.make_client_handshake(&BrowserProfile::CHROME_131, "proxy.server")
.map_err(|e| format!("{:?}", e))?;
conn.outbound
.write_all(&ch)
.await
.map_err(|e| e.to_string())?;
outbound.write_all(&ch).await.map_err(|e| e.to_string())?;
let mut sh_buf = BytesMut::with_capacity(2048);
while let Err(e) = conn.codec.process_handshake(&mut sh_buf) {
if e.action != ErrorAction::Wait {
return Err(format!("Fatal handshake error: {:?}", e));
}
// Теперь read_buf найдется, так как мы импортировали AsyncReadExt
let n = conn
.inbound
.read_buf(&mut sh_buf)
.await
.map_err(|e| e.to_string())?;
if n == 0 {
return Err("Server closed connection during handshake".into());
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)),
}
}
info!("Persistent TLS Tunnel established successfully!");
// 4. Инициализируем Muxer и TunnelEngine
// Явно указываем тип сообщения для канала, чтобы убрать "cannot infer type"
let (mux_tx, mux_rx) = tokio::sync::mpsc::channel::<MuxMessage>(1024);
// --- Запуск инфраструктуры ---
let (mux_tx, mux_rx) = tokio::sync::mpsc::channel(16384);
let muxer = Muxer::new(mux_tx, true);
// 5. Запускаем TunnelEngine в фоне.
let handler = std::sync::Arc::new(crate::proxy::connection::handler::StreamHandler::new(
muxer.clone(),
ConnectionRole::Client,
));
let engine = TunnelEngine {
inbound: conn.inbound,
outbound: conn.outbound,
codec: conn.codec,
buffers: conn.buffers,
inbound,
outbound,
codec,
read_buf: sh_buf, // Передаем остатки данных из буфера хендшейка в движок!
mux_rx,
muxer: muxer.clone(),
role: ConnectionRole::Client,
handler,
};
tokio::spawn(async move {
if let Err(e) = engine.run().await {
error!("Main TunnelEngine died: {}", e);
}
});
tokio::spawn(async move { engine.run().await });
Ok(muxer)
}
+3 -15
View File
@@ -1,4 +1,3 @@
use aead::rand_core::RngCore;
use bytes::{BufMut, Bytes, BytesMut};
use crate::{
@@ -98,25 +97,16 @@ impl ClientHello {
public_key: &[u8; 32],
salt: [u8; 32],
) -> Bytes {
// 1. Key Exchange: Generate ECDH pair and get public key
let tls_random = salt;
// 2. Authentication: Generate 32 bytes for TLS Random
// [16 bytes entropy] + [16 bytes HMAC(timestamp)]
let mut tls_random = salt;
//todo
let auth_token = [0; 16]; //generate_auth_tag(&[]);
// tls_random[16..32].copy_from_slice(&auth_token);
// 3. Extensions: Build the extensions block using the profile
let mut ext_builder = ExtensionBuilder::new();
// Pass the public key into the KeyShare extension via apply_profile
ext_builder.apply_profile(profile, host, public_key);
let extensions_bytes = ext_builder.build();
let mut session_id = BytesMut::with_capacity(32);
session_id.put_slice(&[0u8; 32]);
// 4. Assemble ClientHello Handshake message
let client_hello = ClientHello {
version: ProtocolVersion::Tls12, // Legacy version for compatibility
random: tls_random,
@@ -125,14 +115,12 @@ impl ClientHello {
extensions: extensions_bytes,
};
// 5. Wrap ClientHello into a TLS Record
let record = TlsRecord::new(
ContentType::Handshake,
ProtocolVersion::Tls10,
client_hello.serialize(),
);
// Final result: Byte buffer ready for the wire
record.serialize()
}
}
@@ -151,7 +139,7 @@ impl ServerHello {
server_public_key: &[u8],
salt: [u8; 32],
) -> Self {
let mut server_random = salt;
let server_random = salt;
let selected_suite = client_hello
.cipher_suites