auth tag by time fixes
This commit is contained in:
@@ -3,7 +3,7 @@ use smoltcp::iface::SocketHandle;
|
|||||||
use smoltcp::socket::tcp;
|
use smoltcp::socket::tcp;
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio::net::TcpStream; // Твой код парсера
|
use tokio::net::TcpStream; // Твой код парсера
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::{mpsc, oneshot};
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
use tracing::{debug, info, trace, warn};
|
use tracing::{debug, info, trace, warn};
|
||||||
|
|
||||||
@@ -21,6 +21,7 @@ pub struct TcpConnection {
|
|||||||
rx: mpsc::UnboundedReceiver<Vec<u8>>,
|
rx: mpsc::UnboundedReceiver<Vec<u8>>,
|
||||||
pending_data: Vec<u8>,
|
pending_data: Vec<u8>,
|
||||||
token: CancellationToken,
|
token: CancellationToken,
|
||||||
|
handshake_rx: Option<oneshot::Receiver<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_PENDING: usize = 256 * 1024;
|
const MAX_PENDING: usize = 256 * 1024;
|
||||||
@@ -29,6 +30,7 @@ impl TcpConnection {
|
|||||||
pub fn new(handle: SocketHandle, proxy_addr: String, target_addr: TargetAddress) -> Self {
|
pub fn new(handle: SocketHandle, proxy_addr: String, target_addr: TargetAddress) -> Self {
|
||||||
let (tx_to_proxy, mut rx_from_smol) = mpsc::unbounded_channel::<Vec<u8>>();
|
let (tx_to_proxy, mut rx_from_smol) = mpsc::unbounded_channel::<Vec<u8>>();
|
||||||
let (tx_to_smol, rx_from_proxy) = mpsc::unbounded_channel::<Vec<u8>>();
|
let (tx_to_smol, rx_from_proxy) = mpsc::unbounded_channel::<Vec<u8>>();
|
||||||
|
let (handshake_tx, handshake_rx) = oneshot::channel();
|
||||||
|
|
||||||
let token = CancellationToken::new();
|
let token = CancellationToken::new();
|
||||||
let task_token = token.clone();
|
let task_token = token.clone();
|
||||||
@@ -52,6 +54,8 @@ impl TcpConnection {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = handshake_tx.send(());
|
||||||
|
|
||||||
debug!(%handle, "SOCKS handshake successful, starting data bridge");
|
debug!(%handle, "SOCKS handshake successful, starting data bridge");
|
||||||
|
|
||||||
// 3. Копирование данных (Bridge)
|
// 3. Копирование данных (Bridge)
|
||||||
@@ -95,15 +99,32 @@ impl TcpConnection {
|
|||||||
rx: rx_from_proxy,
|
rx: rx_from_proxy,
|
||||||
pending_data: vec![],
|
pending_data: vec![],
|
||||||
token,
|
token,
|
||||||
|
handshake_rx: Some(handshake_rx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, socket: &mut tcp::Socket) -> bool {
|
pub fn tick(&mut self, socket: &mut tcp::Socket) -> bool {
|
||||||
let state = socket.state();
|
let state = socket.state();
|
||||||
//trace!(handle=%self.handle, ?state, "Tick");
|
//trace!(handle=%self.handle, ?state, "Tick");
|
||||||
|
|
||||||
match self.state {
|
match self.state {
|
||||||
ConnectionState::Handshaking => {
|
ConnectionState::Handshaking => {
|
||||||
return true;
|
if let Some(rx) = &mut self.handshake_rx {
|
||||||
|
match rx.try_recv() {
|
||||||
|
Ok(_) => {
|
||||||
|
self.state = ConnectionState::Active;
|
||||||
|
self.handshake_rx = None;
|
||||||
|
return true; // Успех
|
||||||
|
}
|
||||||
|
Err(oneshot::error::TryRecvError::Empty) => return true, // Ждем
|
||||||
|
Err(oneshot::error::TryRecvError::Closed) => {
|
||||||
|
self.state = ConnectionState::Closed; // ФЕЙЛ
|
||||||
|
return false; // СКАЗАТЬ МЕНЕДЖЕРУ УДАЛИТЬ НАС
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false; // Если rx пропал, но мы не Active — закрываем
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionState::Active => {
|
ConnectionState::Active => {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ pub struct ConnectionManager {
|
|||||||
//active_udp_sessions: HashMap<SocketHandle, UdpSession>,
|
//active_udp_sessions: HashMap<SocketHandle, UdpSession>,
|
||||||
fake_ip_store: FakeIpStore,
|
fake_ip_store: FakeIpStore,
|
||||||
proxy_ip: String,
|
proxy_ip: String,
|
||||||
|
failed_until: HashMap<SocketHandle, StdInstant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectionManager {
|
impl ConnectionManager {
|
||||||
@@ -31,6 +32,7 @@ impl ConnectionManager {
|
|||||||
active_tcp_sessions: HashMap::new(),
|
active_tcp_sessions: HashMap::new(),
|
||||||
proxy_ip: ip,
|
proxy_ip: ip,
|
||||||
fake_ip_store: FakeIpStore::new(),
|
fake_ip_store: FakeIpStore::new(),
|
||||||
|
failed_until: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn start_listening(&mut self, socket_set: &mut SocketSet) {
|
pub fn start_listening(&mut self, socket_set: &mut SocketSet) {
|
||||||
@@ -116,6 +118,12 @@ impl ConnectionManager {
|
|||||||
|
|
||||||
// 1. Если сокет закрыт, просто чистим и возвращаем в LISTEN
|
// 1. Если сокет закрыт, просто чистим и возвращаем в LISTEN
|
||||||
if socket.state() == State::Closed {
|
if socket.state() == State::Closed {
|
||||||
|
if let Some(until) = self.failed_until.get(&handle) {
|
||||||
|
if StdInstant::now() < *until {
|
||||||
|
return; // Сокет в штрафе, не открываем его
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.active_tcp_sessions.remove(&handle);
|
self.active_tcp_sessions.remove(&handle);
|
||||||
socket.abort();
|
socket.abort();
|
||||||
let _ = socket.listen(443);
|
let _ = socket.listen(443);
|
||||||
@@ -144,12 +152,15 @@ impl ConnectionManager {
|
|||||||
if let Some(conn) = self.active_tcp_sessions.get_mut(&handle) {
|
if let Some(conn) = self.active_tcp_sessions.get_mut(&handle) {
|
||||||
if !conn.tick(socket) {
|
if !conn.tick(socket) {
|
||||||
// Если tick вернул false, значит сессия завершена или произошла ошибка в tokio-задаче
|
// Если tick вернул false, значит сессия завершена или произошла ошибка в tokio-задаче
|
||||||
|
debug!(%handle, "Connection handshake failed or closed, aborting socket.");
|
||||||
self.active_tcp_sessions.remove(&handle);
|
self.active_tcp_sessions.remove(&handle);
|
||||||
socket.abort(); // Принудительно закрываем "битый" сокет
|
socket.abort(); // Принудительно закрываем "битый" сокет
|
||||||
|
self.failed_until
|
||||||
|
.insert(handle, StdInstant::now() + Duration::from_secs(5));
|
||||||
}
|
}
|
||||||
} else if socket.state() == State::Established {
|
} else if socket.state() == State::Established {
|
||||||
// Если мы дошли сюда, значит сессия была, но удалилась (tick вернул false),
|
self.failed_until
|
||||||
// а сокет всё еще висит в Established. Убиваем его.
|
.insert(handle, StdInstant::now() + Duration::from_secs(5));
|
||||||
socket.abort();
|
socket.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +187,7 @@ impl ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_tcp_socket<'a>() -> tcp::Socket<'a> {
|
fn create_tcp_socket<'a>() -> tcp::Socket<'a> {
|
||||||
const BUF_SIZE: usize = 65535;
|
const BUF_SIZE: usize = 16384;
|
||||||
tcp::Socket::new(
|
tcp::Socket::new(
|
||||||
tcp::SocketBuffer::new(vec![0; BUF_SIZE]),
|
tcp::SocketBuffer::new(vec![0; BUF_SIZE]),
|
||||||
tcp::SocketBuffer::new(vec![0; BUF_SIZE]),
|
tcp::SocketBuffer::new(vec![0; BUF_SIZE]),
|
||||||
@@ -184,7 +195,7 @@ impl ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_udp_socket<'a>() -> udp::Socket<'a> {
|
fn create_udp_socket<'a>() -> udp::Socket<'a> {
|
||||||
const BUF_SIZE: usize = 65535;
|
const BUF_SIZE: usize = 16384;
|
||||||
udp::Socket::new(
|
udp::Socket::new(
|
||||||
udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY; 16], vec![0; BUF_SIZE]),
|
udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY; 16], vec![0; BUF_SIZE]),
|
||||||
udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY; 16], vec![0; BUF_SIZE]),
|
udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY; 16], vec![0; BUF_SIZE]),
|
||||||
|
|||||||
@@ -203,20 +203,23 @@ impl SessionKeys {
|
|||||||
|
|
||||||
let current_step = now / 60;
|
let current_step = now / 60;
|
||||||
|
|
||||||
// 1. Проверяем текущую минуту (самый вероятный случай)
|
// Вставляем цикл проверки расширенного окна [-2, +2]
|
||||||
if &Self::compute_tag(&self.auth_key, current_step) == received_tag {
|
// Это дает запас по времени в обе стороны
|
||||||
|
for step in (current_step.saturating_sub(2))..=(current_step.saturating_add(2)) {
|
||||||
|
if &Self::compute_tag(&self.auth_key, step) == received_tag {
|
||||||
|
// Если подошел не текущий, а другой шаг — логируем это для диагностики
|
||||||
|
if step != current_step {
|
||||||
|
tracing::debug!(expected = %current_step, matched = %step, "Auth tag valid with time offset");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Проверяем предыдущую минуту (на случай стыка минут или задержки сети)
|
|
||||||
if &Self::compute_tag(&self.auth_key, current_step - 1) == received_tag {
|
|
||||||
tracing::debug!("Auth tag valid (matched previous minute window)");
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если ни один не подошел — тег невалиден
|
// Если ни один не подошел — логируем для отладки
|
||||||
|
tracing::warn!(
|
||||||
|
current_step = %current_step,
|
||||||
|
"AUTH MISMATCH: All tags rejected for current window"
|
||||||
|
);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Вспомогательная функция для генерации конкретного тега
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user