mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 16:24:45 +00:00
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.
84 lines
2.8 KiB
Rust
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;
|
|
}
|
|
}
|