diagnostics, recconections fix and bufferbloat fixes

This commit is contained in:
2026-06-25 17:14:26 +07:00
parent b6056b2a66
commit 47208853c9
25 changed files with 1231 additions and 232 deletions
+11 -3
View File
@@ -77,14 +77,14 @@ impl AeadPacker for ChaChaStream {
}
fn decrypt(&mut self, data: &mut BytesMut) -> Result<(), chacha20poly1305::aead::Error> {
let current_counter = self.state.counter;
let saved_counter = self.state.counter;
let nonce = self.state.next_nonce();
let data_len = data.len();
match self.cipher.decrypt_in_place(&nonce, &nonce, data) {
Ok(_) => {
netrunner_logger::trace!(
counter = current_counter,
counter = saved_counter,
nonce = %hex::encode(nonce),
len = data_len,
"Decryption successful"
@@ -92,13 +92,21 @@ impl AeadPacker for ChaChaStream {
Ok(())
}
Err(e) => {
// Roll back the counter: the plaintext was not produced, so the
// peer's TX counter is still at saved_counter. If the caller
// decides to retry (e.g., after a corrective re-read) rather
// than drop the connection, the next decrypt attempt will use
// the same nonce and succeed. In practice we always Drop on
// AEAD failure, but correctness requires the rollback.
self.state.counter = saved_counter;
let data_prefix = if data.len() >= 8 {
hex::encode(&data[..8])
} else {
hex::encode(data.as_ref())
};
netrunner_logger::error!(
counter = current_counter,
counter = saved_counter,
nonce = %hex::encode(nonce),
len = data_len,
prefix = %data_prefix,
+34 -12
View File
@@ -233,7 +233,11 @@ impl SessionAuth {
pub fn generate_current_tag(&self) -> [u8; 16] {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
// NTP step-back can make this return Err; saturate to 0 so the
// writer task doesn't panic. The peer's verify_tag will accept
// tags up to AUTH_WINDOW_SIZE steps away, so a brief clock skew
// is tolerated without a reconnect.
.unwrap_or_default()
.as_secs();
Self::compute_tag(&self.auth_key, now / AUTH_TIME_STEP)
@@ -242,26 +246,44 @@ impl SessionAuth {
pub fn verify_tag(&self, received_tag: &[u8; 16]) -> bool {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("Time went backwards")
// NTP step-back can make duration_since return an error. Saturate to 0
// rather than panic; the tag comparison will fail and we log AUTH MISMATCH.
.unwrap_or_default()
.as_secs();
let current_step = now / AUTH_TIME_STEP;
// Constant-time path: always evaluate ALL 2*AUTH_WINDOW_SIZE+1 candidates
// so the loop duration doesn't leak which step (if any) matched.
let mut matched_step: Option<u64> = None;
for step in (current_step.saturating_sub(AUTH_WINDOW_SIZE))
..=(current_step.saturating_add(AUTH_WINDOW_SIZE))
{
if &Self::compute_tag(&self.auth_key, step) == received_tag {
if step != current_step {
netrunner_logger::debug!(expected = %current_step, matched = %step, "Auth tag valid with time offset");
}
return true;
let candidate = Self::compute_tag(&self.auth_key, step);
let mut diff = 0u8;
for (a, b) in candidate.iter().zip(received_tag.iter()) {
diff |= a ^ b;
}
if diff == 0 && matched_step.is_none() {
matched_step = Some(step);
// Do NOT break — iterate full window for constant time.
}
}
netrunner_logger::warn!(
current_step = %current_step,
"AUTH MISMATCH: All tags rejected for current window"
);
false
match matched_step {
Some(step) => {
if step != current_step {
netrunner_logger::debug!(expected = %current_step, matched = %step, "Auth tag valid with time offset");
}
true
}
None => {
netrunner_logger::warn!(
current_step = %current_step,
"AUTH MISMATCH: All tags rejected for current window"
);
false
}
}
}
}