Files
fips/src/node/handlers/encrypted.rs
T
Johnathan Corgan cc29c51cac Refactor node/handlers.rs and node/tests.rs into subdirectories
Split handlers.rs (986 lines) into handlers/ with 5 subfiles organized
by responsibility: rx_loop, encrypted, handshake, dispatch, timeout.

Split tests.rs (2350 lines) into tests/ with 4 subfiles: unit tests,
handshake integration, spanning tree convergence, and bloom filter tests.
Shared test helpers extracted to tests/mod.rs.

Visibility adjusted from pub(super) to pub(in crate::node) for handler
methods now two levels deep. Unused imports cleaned up in node/mod.rs.

All 316 tests pass, zero warnings.
2026-02-11 03:49:45 +00:00

84 lines
2.8 KiB
Rust

//! Encrypted frame handling (hot path).
use crate::node::Node;
use crate::transport::ReceivedPacket;
use crate::wire::EncryptedHeader;
use tracing::{debug, warn};
impl Node {
/// Handle an encrypted frame (discriminator 0x00).
///
/// This is the hot path for established sessions. We use O(1)
/// index-based lookup to find the session, then decrypt.
pub(in crate::node) async fn handle_encrypted_frame(&mut self, packet: ReceivedPacket) {
// Parse header (fail fast)
let header = match EncryptedHeader::parse(&packet.data) {
Some(h) => h,
None => return, // Malformed, drop silently
};
// O(1) session lookup by our receiver index
let key = (packet.transport_id, header.receiver_idx.as_u32());
let node_addr = match self.peers_by_index.get(&key) {
Some(id) => *id,
None => {
// Unknown index - could be stale session or attack
debug!(
receiver_idx = %header.receiver_idx,
transport_id = %packet.transport_id,
"Unknown session index, dropping"
);
return;
}
};
let peer = match self.peers.get_mut(&node_addr) {
Some(p) => p,
None => {
// Peer removed but index not cleaned up - fix it
self.peers_by_index.remove(&key);
return;
}
};
// Get the session (peer must have one for index-based lookup)
let session = match peer.noise_session_mut() {
Some(s) => s,
None => {
warn!(
node_addr = %node_addr,
"Peer in index map has no session"
);
return;
}
};
// Decrypt with replay check (this is the expensive part)
let ciphertext = &packet.data[header.ciphertext_offset..];
let plaintext = match session.decrypt_with_replay_check(ciphertext, header.counter) {
Ok(p) => p,
Err(e) => {
debug!(
node_addr = %node_addr,
counter = header.counter,
error = %e,
"Decryption failed"
);
return;
}
};
// === PACKET IS AUTHENTIC ===
// Update address for roaming support
peer.set_current_addr(packet.transport_id, packet.remote_addr.clone());
// Update statistics
peer.link_stats_mut().record_recv(packet.data.len(), packet.timestamp_ms);
peer.touch(packet.timestamp_ms);
// Dispatch to link message handler
self.dispatch_link_message(&node_addr, &plaintext).await;
}
}