mirror of
https://github.com/telemt/telemt.git
synced 2026-04-17 10:34:11 +03:00
Middle-End protocol hardening
- Secure framing / hot-path fix: enforced a single length + padding contract across the framing layer. Replaced legacy runtime `len % 4` recovery with strict validation to eliminate undefined behavior paths. - ME RPC aligned with C reference contract: handshake now includes `flags + sender_pid + peer_pid`. Added negotiated CRC mode (CRC32 / CRC32C) and applied the negotiated mode consistently in read/write paths. - Sequence fail-fast semantics: immediate connection termination on first sequence mismatch with dedicated counter increment. - Keepalive reworked to RPC ping/pong: removed raw CBC keepalive frames. Introduced stale ping tracker with proper timeout accounting. - Route/backpressure observability improvements: increased per-connection route queue to 4096. Added `RouteResult` with explicit failure reasons (NoConn, ChannelClosed, QueueFull) and per-reason counters. - Direct-DC secure mode-gate relaxation: removed TLS/secure conflict in Direct-DC handshake path.
This commit is contained in:
@@ -253,7 +253,11 @@ where
|
||||
|
||||
let mode_ok = match proto_tag {
|
||||
ProtoTag::Secure => {
|
||||
if is_tls { config.general.modes.tls } else { config.general.modes.secure }
|
||||
if is_tls {
|
||||
config.general.modes.tls || config.general.modes.secure
|
||||
} else {
|
||||
config.general.modes.secure || config.general.modes.tls
|
||||
}
|
||||
}
|
||||
ProtoTag::Intermediate | ProtoTag::Abridged => config.general.modes.classic,
|
||||
};
|
||||
|
||||
@@ -165,6 +165,7 @@ where
|
||||
frame_limit,
|
||||
&user,
|
||||
&mut frame_counter,
|
||||
&stats,
|
||||
).await {
|
||||
Ok(Some((payload, quickack))) => {
|
||||
trace!(conn_id, bytes = payload.len(), "C->ME frame");
|
||||
@@ -238,6 +239,7 @@ async fn read_client_payload<R>(
|
||||
max_frame: usize,
|
||||
user: &str,
|
||||
frame_counter: &mut u64,
|
||||
stats: &Stats,
|
||||
) -> Result<Option<(Vec<u8>, bool)>>
|
||||
where
|
||||
R: AsyncRead + Unpin + Send + 'static,
|
||||
@@ -326,18 +328,29 @@ where
|
||||
)));
|
||||
}
|
||||
|
||||
let secure_payload_len = if proto_tag == ProtoTag::Secure {
|
||||
match secure_payload_len_from_wire_len(len) {
|
||||
Some(payload_len) => payload_len,
|
||||
None => {
|
||||
stats.increment_secure_padding_invalid();
|
||||
return Err(ProxyError::Proxy(format!(
|
||||
"Invalid secure frame length: {len}"
|
||||
)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
len
|
||||
};
|
||||
|
||||
let mut payload = vec![0u8; len];
|
||||
client_reader
|
||||
.read_exact(&mut payload)
|
||||
.await
|
||||
.map_err(ProxyError::Io)?;
|
||||
|
||||
// Secure Intermediate: remove random padding (last len%4 bytes)
|
||||
// Secure Intermediate: strip validated trailing padding bytes.
|
||||
if proto_tag == ProtoTag::Secure {
|
||||
let rem = len % 4;
|
||||
if rem != 0 && payload.len() >= rem {
|
||||
payload.truncate(len - rem);
|
||||
}
|
||||
payload.truncate(secure_payload_len);
|
||||
}
|
||||
*frame_counter += 1;
|
||||
return Ok(Some((payload, quickack)));
|
||||
@@ -400,6 +413,12 @@ where
|
||||
}
|
||||
ProtoTag::Intermediate | ProtoTag::Secure => {
|
||||
let padding_len = if proto_tag == ProtoTag::Secure {
|
||||
if !is_valid_secure_payload_len(data.len()) {
|
||||
return Err(ProxyError::Proxy(format!(
|
||||
"Secure payload must be 4-byte aligned, got {}",
|
||||
data.len()
|
||||
)));
|
||||
}
|
||||
secure_padding_len(data.len(), rng)
|
||||
} else {
|
||||
0
|
||||
|
||||
Reference in New Issue
Block a user