1use crate::bloom::BloomFilter;
7use crate::node::REKEY_JITTER_SECS;
8use crate::noise::{HandshakeState as NoiseHandshakeState, NoiseError, NoiseSession};
9use crate::transport::{LinkId, LinkStats, TransportAddr, TransportId};
10use crate::tree::{ParentDeclaration, TreeCoordinate};
11use crate::utils::index::SessionIndex;
12use crate::{FipsAddress, NodeAddr, PeerIdentity};
13use rand::RngExt;
14use secp256k1::XOnlyPublicKey;
15use std::fmt;
16use std::time::{Duration, Instant};
17
18fn draw_rekey_jitter() -> i64 {
19 rand::rng().random_range(-REKEY_JITTER_SECS..=REKEY_JITTER_SECS)
20}
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26pub enum ConnectivityState {
27 Connected,
29 Stale,
31 Reconnecting,
33 Disconnected,
35}
36
37impl ConnectivityState {
38 pub fn can_send(&self) -> bool {
40 matches!(
41 self,
42 ConnectivityState::Connected | ConnectivityState::Stale
43 )
44 }
45
46 pub fn is_terminal(&self) -> bool {
48 matches!(self, ConnectivityState::Disconnected)
49 }
50
51 pub fn is_healthy(&self) -> bool {
53 matches!(self, ConnectivityState::Connected)
54 }
55}
56
57impl fmt::Display for ConnectivityState {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 let s = match self {
60 ConnectivityState::Connected => "connected",
61 ConnectivityState::Stale => "stale",
62 ConnectivityState::Reconnecting => "reconnecting",
63 ConnectivityState::Disconnected => "disconnected",
64 };
65 write!(f, "{}", s)
66 }
67}
68
69pub struct ActivePeerSession {
71 pub session: NoiseSession,
72 pub our_index: SessionIndex,
73 pub their_index: SessionIndex,
74 pub transport_id: TransportId,
75 pub current_addr: TransportAddr,
76 pub link_stats: LinkStats,
77 pub is_initiator: bool,
78 pub remote_epoch: Option<[u8; 8]>,
79}
80
81#[derive(Debug)]
90pub struct ActivePeer {
91 identity: PeerIdentity,
94
95 link_id: LinkId,
98 connectivity: ConnectivityState,
100
101 noise_session: Option<NoiseSession>,
104 our_index: Option<SessionIndex>,
106 their_index: Option<SessionIndex>,
108 transport_id: Option<TransportId>,
110 current_addr: Option<TransportAddr>,
112 preferred_send_addr: Option<TransportAddr>,
120
121 declaration: Option<ParentDeclaration>,
124 ancestry: Option<TreeCoordinate>,
126
127 tree_announce_min_interval_ms: u64,
130 last_tree_announce_sent_ms: u64,
132 pending_tree_announce: bool,
134
135 inbound_filter: Option<BloomFilter>,
138 filter_sequence: u64,
140 filter_received_at: u64,
142 pending_filter_update: bool,
144
145 session_start: Instant,
149 session_generation: u64,
151
152 link_stats: LinkStats,
155 authenticated_at: u64,
157 last_seen: u64,
159
160 remote_epoch: Option<[u8; 8]>,
163
164 fmp_mmp_is_initiator: bool,
167
168 last_heartbeat_sent: Option<Instant>,
171
172 handshake_msg2: Option<Vec<u8>>,
176
177 replay_suppressed_count: u32,
180 consecutive_decrypt_failures: u32,
182
183 session_established_at: Instant,
186 rekey_jitter_secs: i64,
188 current_k_bit: bool,
190 previous_session: Option<NoiseSession>,
192 previous_our_index: Option<SessionIndex>,
194 previous_transport_id: Option<TransportId>,
196 drain_started: Option<Instant>,
198 pending_new_session: Option<NoiseSession>,
200 pending_our_index: Option<SessionIndex>,
202 pending_their_index: Option<SessionIndex>,
204 pending_rekey_initiator: bool,
206 pending_rekey_completed_at: Option<Instant>,
208 rekey_in_progress: bool,
210 last_peer_rekey: Option<Instant>,
212 rekey_handshake: Option<NoiseHandshakeState>,
214 rekey_our_index: Option<SessionIndex>,
216 rekey_msg1: Option<Vec<u8>>,
218 rekey_msg1_next_resend: u64,
220 rekey_msg1_resend_count: u32,
222}
223
224impl ActivePeer {
225 pub fn new(identity: PeerIdentity, link_id: LinkId, authenticated_at: u64) -> Self {
230 let now = Instant::now();
231 Self {
232 identity,
233 link_id,
234 connectivity: ConnectivityState::Connected,
235 noise_session: None,
236 our_index: None,
237 their_index: None,
238 transport_id: None,
239 current_addr: None,
240 preferred_send_addr: None,
241 declaration: None,
242 ancestry: None,
243 tree_announce_min_interval_ms: 500,
244 last_tree_announce_sent_ms: 0,
245 pending_tree_announce: false,
246 inbound_filter: None,
247 filter_sequence: 0,
248 filter_received_at: 0,
249 pending_filter_update: true, session_start: now,
251 session_generation: authenticated_at.max(1),
252 link_stats: LinkStats::new(),
253 authenticated_at,
254 last_seen: authenticated_at,
255 remote_epoch: None,
256 fmp_mmp_is_initiator: false,
257 last_heartbeat_sent: None,
258 handshake_msg2: None,
259 replay_suppressed_count: 0,
260 consecutive_decrypt_failures: 0,
261 session_established_at: now,
262 rekey_jitter_secs: draw_rekey_jitter(),
263 current_k_bit: false,
264 previous_session: None,
265 previous_our_index: None,
266 previous_transport_id: None,
267 drain_started: None,
268 pending_new_session: None,
269 pending_our_index: None,
270 pending_their_index: None,
271 pending_rekey_initiator: false,
272 pending_rekey_completed_at: None,
273 rekey_in_progress: false,
274 last_peer_rekey: None,
275 rekey_handshake: None,
276 rekey_our_index: None,
277 rekey_msg1: None,
278 rekey_msg1_next_resend: 0,
279 rekey_msg1_resend_count: 0,
280 }
281 }
282
283 pub fn with_stats(
288 identity: PeerIdentity,
289 link_id: LinkId,
290 authenticated_at: u64,
291 link_stats: LinkStats,
292 ) -> Self {
293 let mut peer = Self::new(identity, link_id, authenticated_at);
294 peer.link_stats = link_stats;
295 peer
296 }
297
298 pub fn with_session(
303 identity: PeerIdentity,
304 link_id: LinkId,
305 authenticated_at: u64,
306 session: ActivePeerSession,
307 ) -> Self {
308 let now = Instant::now();
309 Self {
310 identity,
311 link_id,
312 connectivity: ConnectivityState::Connected,
313 noise_session: Some(session.session),
314 our_index: Some(session.our_index),
315 their_index: Some(session.their_index),
316 transport_id: Some(session.transport_id),
317 current_addr: Some(session.current_addr),
318 preferred_send_addr: None,
319 declaration: None,
320 ancestry: None,
321 tree_announce_min_interval_ms: 500,
322 last_tree_announce_sent_ms: 0,
323 pending_tree_announce: false,
324 inbound_filter: None,
325 filter_sequence: 0,
326 filter_received_at: 0,
327 pending_filter_update: true,
328 session_start: now,
329 session_generation: authenticated_at.max(1),
330 link_stats: session.link_stats,
331 authenticated_at,
332 last_seen: authenticated_at,
333 remote_epoch: session.remote_epoch,
334 fmp_mmp_is_initiator: session.is_initiator,
335 last_heartbeat_sent: None,
336 handshake_msg2: None,
337 replay_suppressed_count: 0,
338 consecutive_decrypt_failures: 0,
339 session_established_at: now,
340 rekey_jitter_secs: draw_rekey_jitter(),
341 current_k_bit: false,
342 previous_session: None,
343 previous_our_index: None,
344 previous_transport_id: None,
345 drain_started: None,
346 pending_new_session: None,
347 pending_our_index: None,
348 pending_their_index: None,
349 pending_rekey_initiator: false,
350 pending_rekey_completed_at: None,
351 rekey_in_progress: false,
352 last_peer_rekey: None,
353 rekey_handshake: None,
354 rekey_our_index: None,
355 rekey_msg1: None,
356 rekey_msg1_next_resend: 0,
357 rekey_msg1_resend_count: 0,
358 }
359 }
360
361 pub fn identity(&self) -> &PeerIdentity {
365 &self.identity
366 }
367
368 pub fn node_addr(&self) -> &NodeAddr {
370 self.identity.node_addr()
371 }
372
373 pub fn address(&self) -> &FipsAddress {
375 self.identity.address()
376 }
377
378 pub fn pubkey(&self) -> XOnlyPublicKey {
380 self.identity.pubkey()
381 }
382
383 pub fn npub(&self) -> String {
385 self.identity.npub()
386 }
387
388 pub fn link_id(&self) -> LinkId {
392 self.link_id
393 }
394
395 pub fn connectivity(&self) -> ConnectivityState {
397 self.connectivity
398 }
399
400 pub fn can_send(&self) -> bool {
402 self.connectivity.can_send()
403 }
404
405 pub fn is_healthy(&self) -> bool {
407 self.connectivity.is_healthy()
408 }
409
410 pub fn is_disconnected(&self) -> bool {
412 self.connectivity.is_terminal()
413 }
414
415 pub fn has_session(&self) -> bool {
419 self.noise_session.is_some()
420 }
421
422 pub fn noise_session(&self) -> Option<&NoiseSession> {
424 self.noise_session.as_ref()
425 }
426
427 pub fn noise_session_mut(&mut self) -> Option<&mut NoiseSession> {
429 self.noise_session.as_mut()
430 }
431
432 pub fn our_index(&self) -> Option<SessionIndex> {
434 self.our_index
435 }
436
437 pub fn their_index(&self) -> Option<SessionIndex> {
439 self.their_index
440 }
441
442 pub fn set_their_index(&mut self, index: SessionIndex) {
446 self.their_index = Some(index);
447 }
448
449 pub fn replace_session(
459 &mut self,
460 new_session: NoiseSession,
461 new_our_index: SessionIndex,
462 new_their_index: SessionIndex,
463 ) -> Option<SessionIndex> {
464 self.reset_replay_suppressed();
465 let old_our_index = self.our_index;
466 self.previous_session = self.noise_session.take();
467 self.previous_our_index = old_our_index.filter(|old| *old != new_our_index);
468 self.previous_transport_id = self.transport_id;
469 self.drain_started = self.previous_our_index.map(|_| Instant::now());
470 self.noise_session = Some(new_session);
471 self.our_index = Some(new_our_index);
472 self.their_index = Some(new_their_index);
473 self.session_established_at = Instant::now();
474 self.session_start = Instant::now();
475 self.session_generation = self.session_generation.wrapping_add(1).max(1);
476 self.rekey_in_progress = false;
477 self.rekey_msg1_resend_count = 0;
478 self.rekey_jitter_secs = draw_rekey_jitter();
479 self.last_heartbeat_sent = None;
480 old_our_index
481 }
482
483 pub fn transport_id(&self) -> Option<TransportId> {
485 self.transport_id
486 }
487
488 pub fn current_addr(&self) -> Option<&TransportAddr> {
490 self.current_addr.as_ref()
491 }
492
493 pub fn preferred_send_addr(&self) -> Option<&TransportAddr> {
496 self.preferred_send_addr.as_ref()
497 }
498
499 pub fn send_addr(&self) -> Option<&TransportAddr> {
501 self.preferred_send_addr
502 .as_ref()
503 .or(self.current_addr.as_ref())
504 }
505
506 pub fn set_preferred_send_addr(&mut self, addr: TransportAddr) -> bool {
508 if self.preferred_send_addr.as_ref() == Some(&addr) {
509 return false;
510 }
511 self.preferred_send_addr = Some(addr);
512 true
513 }
514
515 pub fn clear_preferred_send_addr(&mut self) -> bool {
517 self.preferred_send_addr.take().is_some()
518 }
519
520 pub fn set_current_addr(&mut self, transport_id: TransportId, addr: &TransportAddr) -> bool {
534 if self.transport_id == Some(transport_id) && self.current_addr.as_ref() == Some(addr) {
535 return false;
536 }
537 self.transport_id = Some(transport_id);
538 self.current_addr = Some(addr.clone());
539 true
540 }
541
542 pub fn set_handshake_msg2(&mut self, msg2: Vec<u8>) {
546 self.handshake_msg2 = Some(msg2);
547 }
548
549 pub fn handshake_msg2(&self) -> Option<&[u8]> {
551 self.handshake_msg2.as_deref()
552 }
553
554 pub fn clear_handshake_msg2(&mut self) {
556 self.handshake_msg2 = None;
557 }
558
559 pub fn increment_replay_suppressed(&mut self) -> u32 {
563 self.replay_suppressed_count += 1;
564 self.replay_suppressed_count
565 }
566
567 pub fn reset_replay_suppressed(&mut self) -> u32 {
569 let count = self.replay_suppressed_count;
570 self.replay_suppressed_count = 0;
571 count
572 }
573
574 pub fn replay_suppressed_count(&self) -> u32 {
576 self.replay_suppressed_count
577 }
578
579 pub fn increment_decrypt_failures(&mut self) -> u32 {
583 self.consecutive_decrypt_failures += 1;
584 self.consecutive_decrypt_failures
585 }
586
587 pub fn reset_decrypt_failures(&mut self) {
589 self.consecutive_decrypt_failures = 0;
590 }
591
592 pub fn consecutive_decrypt_failures(&self) -> u32 {
594 self.consecutive_decrypt_failures
595 }
596
597 pub fn remote_epoch(&self) -> Option<[u8; 8]> {
601 self.remote_epoch
602 }
603
604 pub(crate) fn set_remote_epoch(&mut self, remote_epoch: Option<[u8; 8]>) {
608 self.remote_epoch = remote_epoch;
609 }
610
611 pub fn coords(&self) -> Option<&TreeCoordinate> {
615 self.ancestry.as_ref()
616 }
617
618 pub fn declaration(&self) -> Option<&ParentDeclaration> {
620 self.declaration.as_ref()
621 }
622
623 pub fn has_tree_position(&self) -> bool {
625 self.declaration.is_some() && self.ancestry.is_some()
626 }
627
628 pub fn inbound_filter(&self) -> Option<&BloomFilter> {
632 self.inbound_filter.as_ref()
633 }
634
635 pub fn filter_sequence(&self) -> u64 {
637 self.filter_sequence
638 }
639
640 pub fn filter_is_stale(&self, current_time_ms: u64, stale_threshold_ms: u64) -> bool {
642 if self.filter_received_at == 0 {
643 return true;
644 }
645 current_time_ms.saturating_sub(self.filter_received_at) > stale_threshold_ms
646 }
647
648 pub fn may_reach(&self, node_addr: &NodeAddr) -> bool {
650 match &self.inbound_filter {
651 Some(filter) => filter.contains(node_addr),
652 None => false,
653 }
654 }
655
656 pub fn needs_filter_update(&self) -> bool {
658 self.pending_filter_update
659 }
660
661 pub fn link_stats(&self) -> &LinkStats {
665 &self.link_stats
666 }
667
668 pub fn link_stats_mut(&mut self) -> &mut LinkStats {
670 &mut self.link_stats
671 }
672
673 pub fn fmp_mmp_is_initiator(&self) -> bool {
675 self.fmp_mmp_is_initiator
676 }
677
678 pub(crate) fn set_fmp_mmp_is_initiator(&mut self, is_initiator: bool) {
679 self.fmp_mmp_is_initiator = is_initiator;
680 }
681
682 pub fn authenticated_at(&self) -> u64 {
684 self.authenticated_at
685 }
686
687 pub fn last_seen(&self) -> u64 {
689 self.last_seen
690 }
691
692 pub fn idle_time(&self, current_time_ms: u64) -> u64 {
694 current_time_ms.saturating_sub(self.last_seen)
695 }
696
697 pub fn connection_duration(&self, current_time_ms: u64) -> u64 {
699 current_time_ms.saturating_sub(self.authenticated_at)
700 }
701
702 pub fn session_elapsed_ms(&self) -> u32 {
707 self.session_start.elapsed().as_millis() as u32
708 }
709
710 pub fn session_generation(&self) -> u64 {
712 self.session_generation
713 }
714
715 pub fn session_start(&self) -> Instant {
717 self.session_start
718 }
719
720 pub fn last_heartbeat_sent(&self) -> Option<Instant> {
724 self.last_heartbeat_sent
725 }
726
727 pub fn mark_heartbeat_sent(&mut self, now: Instant) {
729 self.last_heartbeat_sent = Some(now);
730 }
731
732 pub fn touch(&mut self, current_time_ms: u64) {
736 self.last_seen = current_time_ms;
737 if self.connectivity == ConnectivityState::Stale {
741 self.connectivity = ConnectivityState::Connected;
742 }
743 }
744
745 pub fn mark_stale(&mut self) {
747 if self.connectivity == ConnectivityState::Connected {
748 self.connectivity = ConnectivityState::Stale;
749 }
750 }
751
752 pub fn mark_reconnecting(&mut self) {
754 self.connectivity = ConnectivityState::Reconnecting;
755 }
756
757 pub fn mark_disconnected(&mut self) {
759 self.connectivity = ConnectivityState::Disconnected;
760 }
761
762 pub fn mark_connected(&mut self, current_time_ms: u64) {
764 self.connectivity = ConnectivityState::Connected;
765 self.last_seen = current_time_ms;
766 }
767
768 pub fn set_link_id(&mut self, link_id: LinkId) {
770 self.link_id = link_id;
771 }
772
773 pub fn update_tree_position(
781 &mut self,
782 declaration: ParentDeclaration,
783 ancestry: TreeCoordinate,
784 ) {
785 self.declaration = Some(declaration);
786 self.ancestry = Some(ancestry);
787 }
788
789 pub fn clear_tree_position(&mut self) {
791 self.declaration = None;
792 self.ancestry = None;
793 }
794
795 pub fn set_tree_announce_min_interval_ms(&mut self, ms: u64) {
799 self.tree_announce_min_interval_ms = ms;
800 }
801
802 pub fn last_tree_announce_sent_ms(&self) -> u64 {
804 self.last_tree_announce_sent_ms
805 }
806
807 pub fn set_last_tree_announce_sent_ms(&mut self, ms: u64) {
809 self.last_tree_announce_sent_ms = ms;
810 }
811
812 pub fn can_send_tree_announce(&self, now_ms: u64) -> bool {
814 now_ms.saturating_sub(self.last_tree_announce_sent_ms) >= self.tree_announce_min_interval_ms
815 }
816
817 pub fn record_tree_announce_sent(&mut self, now_ms: u64) {
819 self.last_tree_announce_sent_ms = now_ms;
820 self.pending_tree_announce = false;
821 }
822
823 pub fn mark_tree_announce_pending(&mut self) {
825 self.pending_tree_announce = true;
826 }
827
828 pub fn has_pending_tree_announce(&self) -> bool {
830 self.pending_tree_announce
831 }
832
833 pub fn update_filter(&mut self, filter: BloomFilter, sequence: u64, current_time_ms: u64) {
837 self.inbound_filter = Some(filter);
838 self.filter_sequence = sequence;
839 self.filter_received_at = current_time_ms;
840 self.last_seen = current_time_ms;
841 }
842
843 pub fn clear_filter(&mut self) {
845 self.inbound_filter = None;
846 self.filter_sequence = 0;
847 self.filter_received_at = 0;
848 }
849
850 pub fn mark_filter_update_needed(&mut self) {
852 self.pending_filter_update = true;
853 }
854
855 pub fn clear_filter_update_needed(&mut self) {
857 self.pending_filter_update = false;
858 }
859}
860
861mod rekey;
862
863#[cfg(test)]
864mod tests;