mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 16:24:45 +00:00
Fix rekey dual-initiation, parent selection, peer reconnect, and control socket
Rekey dual-initiation race (FMP + FSP): When both sides' rekey timers fire simultaneously on high-latency links (Tor ~700ms RTT), both msg1s cross in flight before dampening can suppress the second initiation. Each node acts as both initiator and responder, with set_pending_session() from the responder path destroying the initiator's in-progress state. Each side ends up with a pending_new_session from a different Noise handshake, causing AEAD verification failure after cutover and link death. Fix: deterministic tie-breaker in both FMP msg1 handler and FSP SessionSetup handler (smaller NodeAddr wins as initiator). Also guard against pending session overwrite from retransmitted msg1s. Parent selection SRTT gate: Peers without MMP RTT data are excluded from parent candidacy via has_srtt() filter, preventing freshly reconnected peers from appearing artificially attractive. First-RTT triggers immediate parent re-eval. The gate in evaluate_parent() skips unmeasured candidates when any peer has cost data, but falls back to default cost 1.0 during cold start when no peer has MMP data yet. Auto-reconnect on all peer removal paths: The excessive-decryption-failure and peer-restart epoch-mismatch removal paths were missing schedule_reconnect() calls, causing auto-connect peers to be permanently abandoned after those events. Control socket accessibility: Socket and parent directory chowned to root:fips with mode 0770/0750 so group members can use fipsctl/fipstop without root. Log level changes: Default RUST_LOG changed to debug in systemd service files. "Unknown session index" log reduced from debug to trace.
This commit is contained in:
+7
-1
@@ -211,8 +211,11 @@ impl Node {
|
||||
self.bloom_state.mark_update_needed(*from);
|
||||
}
|
||||
|
||||
// Re-evaluate parent selection with current link costs
|
||||
// Re-evaluate parent selection with current link costs.
|
||||
// Exclude peers without MMP RTT data — they are not yet eligible
|
||||
// as parent candidates (prevents oscillation from optimistic defaults).
|
||||
let peer_costs: HashMap<NodeAddr, f64> = self.peers.iter()
|
||||
.filter(|(_, peer)| peer.has_srtt())
|
||||
.map(|(addr, peer)| (*addr, peer.link_cost()))
|
||||
.collect();
|
||||
if let Some(new_parent) = self.tree_state.evaluate_parent(&peer_costs) {
|
||||
@@ -263,6 +266,7 @@ impl Node {
|
||||
"Parent ancestry contains us — loop detected, dropping parent"
|
||||
);
|
||||
let peer_costs: HashMap<NodeAddr, f64> = self.peers.iter()
|
||||
.filter(|(_, peer)| peer.has_srtt())
|
||||
.map(|(addr, peer)| (*addr, peer.link_cost()))
|
||||
.collect();
|
||||
if self.tree_state.handle_parent_lost(&peer_costs) {
|
||||
@@ -354,6 +358,7 @@ impl Node {
|
||||
self.last_parent_reeval = Some(now);
|
||||
|
||||
let peer_costs: HashMap<NodeAddr, f64> = self.peers.iter()
|
||||
.filter(|(_, peer)| peer.has_srtt())
|
||||
.map(|(addr, peer)| (*addr, peer.link_cost()))
|
||||
.collect();
|
||||
|
||||
@@ -410,6 +415,7 @@ impl Node {
|
||||
if was_parent {
|
||||
self.stats_mut().tree.parent_losses += 1;
|
||||
let peer_costs: HashMap<NodeAddr, f64> = self.peers.iter()
|
||||
.filter(|(_, peer)| peer.has_srtt())
|
||||
.map(|(addr, peer)| (*addr, peer.link_cost()))
|
||||
.collect();
|
||||
let changed = self.tree_state.handle_parent_lost(&peer_costs);
|
||||
|
||||
Reference in New Issue
Block a user