comments remove
This commit is contained in:
@@ -56,7 +56,7 @@ pub struct SessionKeys {
|
||||
pub ecdh: ECDH,
|
||||
pub auth_key: [u8; 32],
|
||||
pub current_aead: Option<([u8; 32], [u8; 12], [u8; 32], [u8; 12])>,
|
||||
is_initiator: bool, // Сохраним роль для правильного возврата параметров
|
||||
is_initiator: bool,
|
||||
}
|
||||
|
||||
impl SessionKeys {
|
||||
@@ -159,7 +159,6 @@ impl SessionKeys {
|
||||
|
||||
self.auth_key = HKDF::expand_key::<32>(&hkdf, b"auth_key").map_err(|e| e.to_string())?;
|
||||
|
||||
// Определяем порядок: (Write Key, Write IV, Read Key, Read IV)
|
||||
let keys = if is_server {
|
||||
(s_key, s_iv, c_key, c_iv)
|
||||
} else {
|
||||
|
||||
@@ -144,7 +144,6 @@ impl TlsBridge {
|
||||
profile: &ServerProfile,
|
||||
) -> Result<Bytes, TlsError> {
|
||||
if let HandshakeMessage::Client { base, extensions } = client_msg {
|
||||
// 1. Проверка Auth Tag в Session ID (последние 16 байт)
|
||||
if base.session_id.len() != 32 {
|
||||
return Err(TlsError::new(
|
||||
ErrorStage::Handshake("Invalid SessionID len"),
|
||||
@@ -165,8 +164,6 @@ impl TlsBridge {
|
||||
));
|
||||
}
|
||||
|
||||
// 2. Выполняем Key Exchange (находим KeyShare клиента и считаем Shared Secret)
|
||||
// Это обновит внутреннее состояние keys (auth_key и AEAD ключи)
|
||||
keys.update_keys(base.random, extensions, true)
|
||||
.map_err(|e| {
|
||||
netrunner_logger::error!(error = %e, "Server failed key update");
|
||||
@@ -177,7 +174,6 @@ impl TlsBridge {
|
||||
)
|
||||
})?;
|
||||
|
||||
// 3. Генерируем ServerHello, используя наш свежий публичный ключ и локальную соль
|
||||
let server_pub_key = keys.ecdh.public_key.to_bytes();
|
||||
|
||||
Ok(ServerHello::make_server_hello(
|
||||
|
||||
@@ -46,16 +46,12 @@ impl Codec {
|
||||
)
|
||||
})?;
|
||||
|
||||
// ВАЖНО: TlsBridge сам проверит Auth Tag в Session ID клиента
|
||||
// и вызовет update_keys для генерации общего секрета.
|
||||
let server_hello_record = TlsBridge::wrap_server_hello(
|
||||
&client_msg,
|
||||
&mut self.session_keys,
|
||||
&ServerProfile::MODERN,
|
||||
)?;
|
||||
|
||||
// Ключи уже обновлены внутри session_keys.
|
||||
// Просто забираем их и устанавливаем в AEAD шифратор.
|
||||
let (w_key, w_iv, r_key, r_iv) = self.session_keys.get_aead_parameters();
|
||||
self.crypto.set_keys(w_key, w_iv, r_key, r_iv);
|
||||
|
||||
|
||||
@@ -115,29 +115,25 @@ impl Parser for ClientHello {
|
||||
fn can_parse(bytes: &BytesMut) -> bool {
|
||||
let mut reader = &bytes[..];
|
||||
|
||||
// 1. Version (2) + Random (32) + SessionID Len (1) = 35
|
||||
if reader.len() < 35 {
|
||||
return false;
|
||||
}
|
||||
reader.advance(34);
|
||||
|
||||
// 2. Session ID
|
||||
let sid_len = reader[0] as usize;
|
||||
reader.advance(1);
|
||||
if reader.len() < sid_len + 2 {
|
||||
return false;
|
||||
} // +2 для Cipher Suites Len
|
||||
}
|
||||
reader.advance(sid_len);
|
||||
|
||||
// 3. Cipher Suites
|
||||
let ciphers_len = u16::from_be_bytes([reader[0], reader[1]]) as usize;
|
||||
reader.advance(2);
|
||||
if reader.len() < ciphers_len + 1 {
|
||||
return false;
|
||||
} // +1 для Compression Len
|
||||
}
|
||||
reader.advance(ciphers_len);
|
||||
|
||||
// 4. Compression Methods
|
||||
let comp_len = reader[0] as usize;
|
||||
reader.advance(1);
|
||||
if reader.len() < comp_len {
|
||||
@@ -145,7 +141,6 @@ impl Parser for ClientHello {
|
||||
}
|
||||
reader.advance(comp_len);
|
||||
|
||||
// 5. Extensions (опционально в TLS, но обычно есть)
|
||||
if reader.len() >= 2 {
|
||||
let ext_len = u16::from_be_bytes([reader[0], reader[1]]) as usize;
|
||||
reader.advance(2);
|
||||
@@ -158,8 +153,6 @@ impl Parser for ClientHello {
|
||||
}
|
||||
|
||||
fn parse(bytes: &mut BytesMut) -> Result<Option<Self>, Self::Error> {
|
||||
// Мы уже проверили всё в can_parse, поэтому здесь просто
|
||||
// последовательно забираем данные через get_*
|
||||
if !Self::can_parse(bytes) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ impl Connection {
|
||||
|
||||
pub fn new_raw(inbound: OwnedReadHalf, outbound: OwnedWriteHalf) -> Self {
|
||||
Self {
|
||||
addr: "0.0.0.0:0".parse().unwrap(), // заглушка, если адрес не важен
|
||||
addr: "0.0.0.0:0".parse().unwrap(),
|
||||
inbound,
|
||||
outbound,
|
||||
read_buf: BytesMut::with_capacity(BUF_SIZE),
|
||||
@@ -105,7 +105,6 @@ pub struct ClientHandler {
|
||||
pub muxer: Muxer,
|
||||
}
|
||||
|
||||
// Внутри connection.rs или где у тебя ClientHandler
|
||||
impl ClientHandler {
|
||||
pub async fn connect(
|
||||
remote_proxy_addr: &str,
|
||||
@@ -118,7 +117,6 @@ impl ClientHandler {
|
||||
|
||||
let mut conn = Connection::new_raw(inbound, outbound);
|
||||
|
||||
// TLS Handshake
|
||||
let ch = conn
|
||||
.codec
|
||||
.make_client_handshake(&BrowserProfile::CHROME_131, "google.com")
|
||||
@@ -177,7 +175,6 @@ impl ClientHandler {
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
loop {
|
||||
// Просто ждем, пока клиент не разорвет TCP-соединение
|
||||
if self
|
||||
.conn
|
||||
.inbound
|
||||
@@ -198,17 +195,14 @@ impl TunnelHandler for ClientHandler {
|
||||
async fn run(mut self) -> Result<(), String> {
|
||||
info!("Starting SOCKS multiplexed handling");
|
||||
|
||||
// 1. Приветствие (Handshake)
|
||||
self.conn.read_socks_request().await?;
|
||||
self.conn
|
||||
.send_socks_reply(SocksReply::HandshakeSelect { method: 0x00 })
|
||||
.await?;
|
||||
|
||||
// 2. Получаем основной запрос (Connect или UDP Associate)
|
||||
let req = self.conn.read_socks_request().await?;
|
||||
|
||||
match req {
|
||||
// Ветка TCP CONNECT
|
||||
SocksRequest::Connect {
|
||||
command: 0x01,
|
||||
target,
|
||||
@@ -253,13 +247,11 @@ impl TunnelHandler for ClientHandler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Ветка UDP ASSOCIATE
|
||||
SocksRequest::Connect { command: 0x03, .. } => {
|
||||
info!("Handling UDP Associate request");
|
||||
self.handle_udp_associate().await
|
||||
}
|
||||
|
||||
// Всё остальное (BIND и т.д.)
|
||||
_ => Err("Unsupported SOCKS command".into()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ impl StreamHandler {
|
||||
let target_str = String::from_utf8_lossy(&payload).to_string();
|
||||
let muxer = self.muxer.clone();
|
||||
|
||||
// Канал для передачи данных из мультиплексора в мост (bridge)
|
||||
let (v_tx, v_rx) = tokio::sync::mpsc::channel(512);
|
||||
muxer.register_stream(stream_id, v_tx).await;
|
||||
|
||||
@@ -43,7 +42,6 @@ impl StreamHandler {
|
||||
let start = std::time::Instant::now();
|
||||
info!(stream_id, target = %target_str, "Attempting remote connection");
|
||||
|
||||
// Обертываем коннект в таймаут, чтобы не плодить зомби-таски
|
||||
let connect_timeout = tokio::time::timeout(
|
||||
std::time::Duration::from_secs(5),
|
||||
tokio::net::TcpStream::connect(&target_str),
|
||||
@@ -62,7 +60,7 @@ impl StreamHandler {
|
||||
|
||||
let mut reply_buf = BytesMut::with_capacity(10);
|
||||
let reply = SocksReply::ConnectResult {
|
||||
reply_code: 0x00, // Success
|
||||
reply_code: 0x00,
|
||||
atyp: 0x01,
|
||||
addr: [0, 0, 0, 0],
|
||||
port: 0,
|
||||
@@ -78,11 +76,11 @@ impl StreamHandler {
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
error!(stream_id, target = %target_str, error = %e, "TCP connection failed");
|
||||
Self::send_error_reply(&muxer, stream_id, 0x01).await; // 0x01 = General failure
|
||||
Self::send_error_reply(&muxer, stream_id, 0x01).await;
|
||||
}
|
||||
Err(_) => {
|
||||
error!(stream_id, target = %target_str, "Connection timed out (DNS/TCP)");
|
||||
Self::send_error_reply(&muxer, stream_id, 0x04).await; // 0x04 = Host unreachable
|
||||
Self::send_error_reply(&muxer, stream_id, 0x04).await;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -260,14 +260,13 @@ impl ExtensionBuilder {
|
||||
TlsExtensions::RENEGOTIATION_INFO => self.renegotiation_info(),
|
||||
TlsExtensions::PADDING => {
|
||||
if profile.target_padding_len > 0 {
|
||||
// Передаем накопленный оверхед всего пакета
|
||||
self.padding(profile.target_padding_len as usize, overhead);
|
||||
}
|
||||
}
|
||||
|
||||
id if TlsExtensions::is_grease(id) => {
|
||||
if profile.has_grease {
|
||||
self.grease_with_id(id); // Используем конкретный ID из ExtensionOrder
|
||||
self.grease_with_id(id);
|
||||
}
|
||||
}
|
||||
_ => self.apply_generic_extension(ext_id, profile),
|
||||
|
||||
@@ -36,36 +36,29 @@ impl ClientHello {
|
||||
|
||||
buf.put_u8(HANDSHAKE_TYPE_CLIENT_HELLO);
|
||||
|
||||
// Резервируем 3 байта под длину Handshake (U24)
|
||||
let length_pos = buf.len();
|
||||
buf.put_bytes(0, 3);
|
||||
|
||||
buf.put_u16(0x0303); // Legacy Version
|
||||
buf.put_u16(0x0303);
|
||||
buf.put_slice(&self.random);
|
||||
|
||||
// Session ID
|
||||
buf.put_u8(self.session_id.len() as u8);
|
||||
buf.put_slice(&self.session_id);
|
||||
|
||||
// Cipher Suites
|
||||
buf.put_u16((self.cipher_suites.len() * 2) as u16);
|
||||
for &suite in &self.cipher_suites {
|
||||
buf.put_u16(suite);
|
||||
}
|
||||
|
||||
// Compression Methods (всегда 0x01 0x00 для маскировки)
|
||||
buf.put_u8(1);
|
||||
buf.put_u8(0x00);
|
||||
|
||||
// Extensions
|
||||
buf.put_u16(self.extensions.len() as u16);
|
||||
buf.put_slice(&self.extensions);
|
||||
|
||||
// ПРАВИЛЬНЫЙ РАСЧЕТ ДЛИНЫ:
|
||||
// Длина сообщения Handshake не включает сам тип (1 байт) и поле длины (3 байта)
|
||||
let total_len = (buf.len() - length_pos - 3) as u32;
|
||||
let len_bytes = total_len.to_be_bytes();
|
||||
// Записываем 3 байта длины (Big Endian)
|
||||
|
||||
buf[length_pos..length_pos + 3].copy_from_slice(&len_bytes[1..4]);
|
||||
|
||||
buf.freeze()
|
||||
@@ -126,14 +119,12 @@ impl ServerHello {
|
||||
salt: [u8; 32],
|
||||
profile: &ServerProfile,
|
||||
) -> Bytes {
|
||||
// Создаем инстанс ServerHello
|
||||
let server_hello = Self::from_client_hello(client_hello, server_public_key, salt, profile);
|
||||
|
||||
// Оборачиваем в Record Layer
|
||||
let record = TlsRecord::new(
|
||||
ContentType::Handshake,
|
||||
profile.record_layer_version, // 0x0303 обычно
|
||||
server_hello.serialize(), // Сериализация самого SH
|
||||
profile.record_layer_version,
|
||||
server_hello.serialize(),
|
||||
);
|
||||
|
||||
record.serialize()
|
||||
@@ -145,10 +136,8 @@ impl ServerHello {
|
||||
salt: [u8; 32],
|
||||
profile: &ServerProfile,
|
||||
) -> Self {
|
||||
// 1. Используем соль как рандом сервера
|
||||
let server_random = salt;
|
||||
|
||||
// 2. Выбор Cipher Suite (твой код здесь хорош, оставляем)
|
||||
let selected_suite = if profile.honor_cipher_order {
|
||||
profile
|
||||
.cipher_suites
|
||||
@@ -167,27 +156,22 @@ impl ServerHello {
|
||||
|
||||
let mut extensions = BytesMut::new();
|
||||
|
||||
// 3. Работа с версией.
|
||||
// Выбираем макс. версию из профиля (например, TLS 1.3)
|
||||
let selected_version = profile.versions.max();
|
||||
|
||||
// Добавляем расширение Supported Versions (обязательно для TLS 1.3)
|
||||
extensions.put_u16(0x002b);
|
||||
extensions.put_u16(2);
|
||||
extensions.put_u16(selected_version as u16);
|
||||
|
||||
// 4. Key Share (исправляем расчет длины, чтобы не было как в прошлый раз)
|
||||
let key_len = server_public_key.len() as u16;
|
||||
extensions.put_u16(0x0033);
|
||||
extensions.put_u16(key_len + 4); // Группа(2) + Длина(2) + Ключ
|
||||
extensions.put_u16(0x001d); // x25519
|
||||
extensions.put_u16(key_len + 4);
|
||||
extensions.put_u16(0x001d);
|
||||
extensions.put_u16(key_len);
|
||||
extensions.put_slice(server_public_key);
|
||||
|
||||
Self {
|
||||
// Это поле будет использоваться как legacy_version (0x0303)
|
||||
version: ProtocolVersion::Tls12,
|
||||
random: server_random, // ИСПОЛЬЗУЕМ переменную
|
||||
random: server_random,
|
||||
session_id: client_hello.session_id.clone(),
|
||||
cipher_suite: selected_suite,
|
||||
extensions,
|
||||
@@ -199,26 +183,20 @@ impl ServerHello {
|
||||
|
||||
buf.put_u8(HANDSHAKE_TYPE_SERVER_HELLO);
|
||||
|
||||
// Резервируем место под длину Handshake (3 байта)
|
||||
let length_pos = buf.len();
|
||||
buf.put_slice(&[0, 0, 0]);
|
||||
|
||||
// Используем версию из структуры (Legacy Version)
|
||||
buf.put_u16(self.version as u16);
|
||||
|
||||
// Используем рандом из структуры
|
||||
buf.put_slice(&self.random);
|
||||
|
||||
// Session ID (Echo)
|
||||
buf.put_u8(self.session_id.len() as u8);
|
||||
buf.put_slice(&self.session_id);
|
||||
|
||||
buf.put_u16(self.cipher_suite);
|
||||
|
||||
// Compression (0x00)
|
||||
buf.put_u8(0x00);
|
||||
|
||||
// Extensions
|
||||
if !self.extensions.is_empty() {
|
||||
buf.put_u16(self.extensions.len() as u16);
|
||||
buf.put_slice(&self.extensions);
|
||||
@@ -226,7 +204,6 @@ impl ServerHello {
|
||||
buf.put_u16(0);
|
||||
}
|
||||
|
||||
// Заполняем длину handshake-сообщения
|
||||
let total_handshake_body_len = (buf.len() - length_pos - 3) as u32;
|
||||
let len_bytes = total_handshake_body_len.to_be_bytes();
|
||||
buf[length_pos..length_pos + 3].copy_from_slice(&len_bytes[1..4]);
|
||||
|
||||
@@ -25,49 +25,41 @@ impl BrowserProfile {
|
||||
delegated_signatures: TlsSignatures::BROWSER_STANDARD,
|
||||
versions: TlsVersions::TLS_13_ONLY,
|
||||
|
||||
// 0x0301 (TLS 1.0) — классика для ClientHello в исполнении Chrome
|
||||
record_layer_version: ProtocolVersion::Tls10,
|
||||
|
||||
cipher_suites: &[
|
||||
0x1301, 0x1302, 0x1303, // TLS 1.3 Suites
|
||||
0xc02b, 0xc02f, 0xc02c, 0xc030, // ECDHE-RSA/ECDSA
|
||||
0xcca9, 0xcca8, // ChaCha20
|
||||
0x1301, 0x1302, 0x1303, 0xc02b, 0xc02f, 0xc02c, 0xc030, 0xcca9, 0xcca8,
|
||||
],
|
||||
|
||||
alpn: &["h2", "http/1.1"],
|
||||
extension_order: ExtensionOrder::CHROMIUM_131,
|
||||
|
||||
// --- НОВЫЕ ПОЛЯ ДЛЯ ГИБКОСТИ ---
|
||||
is_chromium: true,
|
||||
has_grease: true,
|
||||
|
||||
// Chrome активно использует ALPS для ускорения HTTP/2 настроек
|
||||
alps_protocols: &["h2"],
|
||||
|
||||
// Chrome старается сделать ClientHello "пухлым",
|
||||
// чтобы избежать проблем с некоторыми старыми Middleboxes
|
||||
target_padding_len: 512,
|
||||
};
|
||||
|
||||
pub const FIREFOX_130: Self = Self {
|
||||
name: "Firefox 130 (Windows)",
|
||||
groups: TlsGroups::MODERN, // У FF свой набор предпочтений
|
||||
groups: TlsGroups::MODERN,
|
||||
signatures: TlsSignatures::BROWSER_STANDARD,
|
||||
delegated_signatures: TlsSignatures::BROWSER_STANDARD,
|
||||
versions: TlsVersions::MODERN, // FF часто шлет 1.3 + 1.2
|
||||
versions: TlsVersions::MODERN,
|
||||
|
||||
// Firefox обычно пишет 0x0303 (TLS 1.2) в Record Layer
|
||||
record_layer_version: ProtocolVersion::Tls12,
|
||||
|
||||
cipher_suites: &[0x1301, 0x1302, 0x1303, 0xc02b, 0xc02f, 0xc02c, 0xc030],
|
||||
|
||||
alpn: &["h2", "http/1.1"],
|
||||
extension_order: ExtensionOrder::EDGE_130, // Тут стоит подставить личный порядок FF
|
||||
extension_order: ExtensionOrder::EDGE_130,
|
||||
|
||||
is_chromium: false,
|
||||
has_grease: false, // Firefox НЕ использует GREASE
|
||||
alps_protocols: &[], // Firefox пока не так активно внедряет ALPS
|
||||
target_padding_len: 0, // Firefox обычно не делает принудительный Padding до 512
|
||||
has_grease: false,
|
||||
alps_protocols: &[],
|
||||
target_padding_len: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,8 +67,7 @@ pub struct ServerProfile {
|
||||
pub name: &'static str,
|
||||
pub versions: TlsVersions,
|
||||
|
||||
// ДОБАВЛЯЕМ:
|
||||
pub record_layer_version: ProtocolVersion, // Что сервер пишет в ответном Record
|
||||
pub record_layer_version: ProtocolVersion,
|
||||
|
||||
pub cipher_suites: &'static [u16],
|
||||
pub groups: TlsGroups,
|
||||
@@ -91,7 +82,6 @@ impl ServerProfile {
|
||||
name: "Modern-Secure",
|
||||
versions: TlsVersions::MODERN,
|
||||
|
||||
// Сервера обычно отвечают 0x0303 (TLS 1.2) в Record Layer
|
||||
record_layer_version: ProtocolVersion::Tls12,
|
||||
|
||||
cipher_suites: &[0x1301, 0x1302, 0x1303],
|
||||
|
||||
@@ -146,7 +146,7 @@ impl TlsExtensions {
|
||||
if (id & 0x0f0f) != 0x0a0a {
|
||||
return false;
|
||||
}
|
||||
// Убеждаемся, что оба байта идентичны (0x1A1A, а не 0x1A2A)
|
||||
|
||||
(id & 0xff) == (id >> 8)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user