1use std::collections::{HashMap, HashSet};
4use std::io;
5use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
6use std::sync::{Arc, Mutex};
7use std::time::{Duration, Instant};
8
9type MemoryRollup = (f64, f64, f64, f64, f64, f64, f64, f64);
10#[cfg(feature = "iface-backbone")]
11type BackboneCandidateOrder = (
12 std::cmp::Reverse<u8>,
13 u8,
14 u8,
15 u8,
16 std::cmp::Reverse<rns_core::stamp::StampValue>,
17 std::cmp::Reverse<u64>,
18 [u8; 32],
19);
20
21use rns_core::packet::RawPacket;
22use rns_core::transport::announce_verify_queue::{AnnounceVerifyQueue, OverflowPolicy};
23use rns_core::transport::tables::PathEntry;
24use rns_core::transport::types::{InterfaceId, ReceivedAnnounce, TransportAction, TransportConfig};
25use rns_core::transport::TransportEngine;
26use rns_crypto::{OsRng, Rng};
27
28#[cfg(feature = "hooks")]
29use crate::provider_bridge::ProviderBridge;
30use crate::stamper::PathRequestTarget;
31#[cfg(feature = "hooks")]
32use rns_hooks::{create_hook_slots, EngineAccess, HookContext, HookManager, HookPoint, HookSlot};
33
34#[cfg(feature = "hooks")]
35use crate::event::BackbonePeerHookEvent;
36use crate::event::{
37 BackbonePeerPoolMemberStatus, BackbonePeerPoolStatus, BackbonePeerStateEntry, BlackholeInfo,
38 DrainStatus, Event, EventReceiver, InterfaceStatsResponse, KnownDestinationEntry,
39 LifecycleState, LocalDestinationEntry, NextHopResponse, PathTableEntry, QueryRequest,
40 QueryResponse, RateTableEntry, RuntimeConfigApplyMode, RuntimeConfigEntry, RuntimeConfigError,
41 RuntimeConfigErrorCode, RuntimeConfigSource, RuntimeConfigValue, SingleInterfaceStat,
42 TrafficDetail,
43};
44use crate::holepunch::orchestrator::{HolePunchManager, HolePunchManagerAction};
45use crate::ifac;
46#[cfg(all(feature = "iface-auto", test))]
47use crate::interface::auto::AutoRuntime;
48#[cfg(feature = "iface-auto")]
49use crate::interface::auto::AutoRuntimeConfigHandle;
50#[cfg(feature = "iface-backbone")]
51use crate::interface::backbone::{
52 start_client_with_ifac, BackboneClientConfig, BackboneClientRuntime,
53 BackboneClientRuntimeConfigHandle, BackbonePeerStateHandle, BackboneRuntimeConfigHandle,
54};
55#[cfg(all(feature = "iface-backbone", target_os = "linux", test))]
56use crate::interface::backbone::{BackboneAbuseConfig, BackboneServerRuntime};
57#[cfg(all(feature = "iface-i2p", test))]
58use crate::interface::i2p::I2pRuntime;
59#[cfg(feature = "iface-i2p")]
60use crate::interface::i2p::I2pRuntimeConfigHandle;
61#[cfg(all(feature = "iface-pipe", test))]
62use crate::interface::pipe::PipeRuntime;
63#[cfg(feature = "iface-pipe")]
64use crate::interface::pipe::PipeRuntimeConfigHandle;
65#[cfg(feature = "iface-rnode")]
66use crate::interface::rnode::{
67 validate_sub_config, RNodeRuntime, RNodeRuntimeConfigHandle, RNodeSubConfig,
68};
69#[cfg(feature = "iface-tcp")]
70use crate::interface::tcp::TcpClientRuntimeConfigHandle;
71#[cfg(all(feature = "iface-tcp", test))]
72use crate::interface::tcp_server::TcpServerRuntime;
73#[cfg(feature = "iface-tcp")]
74use crate::interface::tcp_server::TcpServerRuntimeConfigHandle;
75#[cfg(all(feature = "iface-udp", test))]
76use crate::interface::udp::UdpRuntime;
77#[cfg(feature = "iface-udp")]
78use crate::interface::udp::UdpRuntimeConfigHandle;
79use crate::interface::{InterfaceEntry, InterfaceStats};
80use crate::link_manager::{LinkManager, LinkManagerAction};
81use crate::time;
82
83const DEFAULT_KNOWN_DESTINATIONS_TTL: f64 = 48.0 * 60.0 * 60.0;
84const DEFAULT_KNOWN_DESTINATIONS_MAX_ENTRIES: usize = 8192;
85const DEFAULT_RATE_LIMITER_TTL_SECS: f64 = 48.0 * 60.0 * 60.0;
86const DEFAULT_TICK_INTERVAL_MS: u64 = 1000;
87const DEFAULT_KNOWN_DESTINATIONS_CLEANUP_INTERVAL_TICKS: u32 = 3600;
88const KNOWN_DESTINATION_CLEANUP_BATCH_SIZE: usize = 64;
89const DEFAULT_ANNOUNCE_CACHE_CLEANUP_INTERVAL_TICKS: u32 = 3600;
90const DEFAULT_ANNOUNCE_CACHE_CLEANUP_BATCH_SIZE: usize = 10_000;
91const DEFAULT_DISCOVERY_CLEANUP_INTERVAL_TICKS: u32 = 3600;
92const DEFAULT_MANAGEMENT_ANNOUNCE_INTERVAL_SECS: f64 = 3600.0;
93const DEFAULT_LINK_TEARDOWN_FLUSH: Duration = Duration::from_millis(150);
94const SEND_RETRY_BACKOFF_MIN: Duration = Duration::from_millis(25);
95const SEND_RETRY_BACKOFF_MAX: Duration = Duration::from_millis(1000);
96
97#[derive(Debug, Clone, Copy, PartialEq)]
99pub struct AnnounceRateDefaults {
100 pub target: Option<f64>,
101 pub penalty: f64,
102 pub grace: u32,
103}
104
105impl Default for AnnounceRateDefaults {
106 fn default() -> Self {
107 Self {
108 target: Some(3600.0),
109 penalty: 0.0,
110 grace: 5,
111 }
112 }
113}
114
115mod announce_check;
116pub(crate) use announce_check::{check_pending_announce, AnnounceCheck};
117mod dispatch;
118mod events;
119mod hook_events;
120mod interface_management;
121mod lifecycle;
122mod link_stamps;
123mod queries;
124mod resource_preparation;
125mod rpc_service;
126pub(crate) use rpc_service::{RpcListener, RpcService};
127mod runtime_config;
128#[cfg(any(target_os = "linux", target_os = "android"))]
129mod tick_source;
130
131#[cfg(test)]
132pub(crate) mod tests;
133
134fn inject_transport_header(raw: &[u8], next_hop: &[u8; 16]) -> Vec<u8> {
135 if raw.len() < 18 {
136 return raw.to_vec();
137 }
138
139 let new_flags = (rns_core::constants::HEADER_2 << 6)
140 | (rns_core::constants::TRANSPORT_TRANSPORT << 4)
141 | (raw[0] & 0x0F);
142
143 let mut new_raw = Vec::with_capacity(raw.len() + 16);
144 new_raw.push(new_flags);
145 new_raw.push(raw[1]);
146 new_raw.extend_from_slice(next_hop);
147 new_raw.extend_from_slice(&raw[2..]);
148 new_raw
149}
150
151fn recover_mutex_guard<'a, T>(mutex: &'a Mutex<T>, label: &str) -> std::sync::MutexGuard<'a, T> {
152 match mutex.lock() {
153 Ok(guard) => guard,
154 Err(poisoned) => {
155 log::error!("recovering from poisoned mutex: {}", label);
156 poisoned.into_inner()
157 }
158 }
159}
160
161#[derive(Debug, Clone, Copy)]
162pub(crate) struct RuntimeConfigDefaults {
163 pub(crate) tick_interval_ms: u64,
164 pub(crate) known_destinations_ttl: f64,
165 pub(crate) rate_limiter_ttl_secs: f64,
166 pub(crate) known_destinations_cleanup_interval_ticks: u32,
167 pub(crate) announce_cache_cleanup_interval_ticks: u32,
168 pub(crate) announce_cache_cleanup_batch_size: usize,
169 pub(crate) discovery_cleanup_interval_ticks: u32,
170 pub(crate) management_announce_interval_secs: f64,
171 pub(crate) direct_connect_policy: crate::event::HolePunchPolicy,
172 pub(crate) stamp_destinations: bool,
174 pub(crate) stamp_path_requests: bool,
176 pub(crate) stamps_enforced: bool,
178 pub(crate) lr_stamps_enforced: bool,
180 pub(crate) stamp_link_requests: bool,
182 pub(crate) always_stamp_link_requests: bool,
184 #[cfg(feature = "hooks")]
185 pub(crate) provider_queue_max_events: usize,
186 #[cfg(feature = "hooks")]
187 pub(crate) provider_queue_max_bytes: usize,
188}
189
190#[cfg(feature = "iface-backbone")]
191#[derive(Debug, Clone)]
192pub(crate) struct BackboneDiscoveryRuntime {
193 pub(crate) discoverable: bool,
194 pub(crate) config: crate::discovery::DiscoveryConfig,
195 pub(crate) transport_enabled: bool,
196 pub(crate) ifac_netname: Option<String>,
197 pub(crate) ifac_netkey: Option<String>,
198}
199
200#[cfg(feature = "iface-backbone")]
201#[derive(Debug, Clone)]
202pub(crate) struct BackboneDiscoveryRuntimeHandle {
203 pub(crate) interface_name: String,
204 pub(crate) current: BackboneDiscoveryRuntime,
205 pub(crate) startup: BackboneDiscoveryRuntime,
206}
207
208#[cfg(feature = "iface-tcp")]
209#[derive(Debug, Clone)]
210pub(crate) struct TcpServerDiscoveryRuntime {
211 pub(crate) discoverable: bool,
212 pub(crate) config: crate::discovery::DiscoveryConfig,
213 pub(crate) transport_enabled: bool,
214 pub(crate) ifac_netname: Option<String>,
215 pub(crate) ifac_netkey: Option<String>,
216}
217
218#[cfg(feature = "iface-tcp")]
219#[derive(Debug, Clone)]
220pub(crate) struct TcpServerDiscoveryRuntimeHandle {
221 pub(crate) interface_name: String,
222 pub(crate) current: TcpServerDiscoveryRuntime,
223 pub(crate) startup: TcpServerDiscoveryRuntime,
224}
225
226#[derive(Debug, Clone, PartialEq, Eq)]
227pub(crate) struct IfacRuntimeConfig {
228 pub(crate) netname: Option<String>,
229 pub(crate) netkey: Option<String>,
230 pub(crate) size: usize,
231}
232
233#[cfg(feature = "iface-backbone")]
234impl BackboneDiscoveryRuntimeHandle {
235 pub(crate) fn from_parts(
236 interface_name: String,
237 startup_config: crate::discovery::DiscoveryConfig,
238 transport_enabled: bool,
239 ifac_netname: Option<String>,
240 ifac_netkey: Option<String>,
241 discoverable: bool,
242 ) -> Self {
243 let startup = BackboneDiscoveryRuntime {
244 discoverable,
245 config: startup_config,
246 transport_enabled,
247 ifac_netname,
248 ifac_netkey,
249 };
250 Self {
251 interface_name,
252 current: startup.clone(),
253 startup,
254 }
255 }
256}
257
258#[cfg(feature = "iface-tcp")]
259impl TcpServerDiscoveryRuntimeHandle {
260 pub(crate) fn from_parts(
261 interface_name: String,
262 startup_config: crate::discovery::DiscoveryConfig,
263 transport_enabled: bool,
264 ifac_netname: Option<String>,
265 ifac_netkey: Option<String>,
266 discoverable: bool,
267 ) -> Self {
268 let startup = TcpServerDiscoveryRuntime {
269 discoverable,
270 config: startup_config,
271 transport_enabled,
272 ifac_netname,
273 ifac_netkey,
274 };
275 Self {
276 interface_name,
277 current: startup.clone(),
278 startup,
279 }
280 }
281}
282
283impl IfacRuntimeConfig {
284 pub(crate) fn from_parts(netname: Option<String>, netkey: Option<String>, size: usize) -> Self {
285 Self {
286 netname,
287 netkey,
288 size,
289 }
290 }
291}
292
293#[cfg(feature = "iface-backbone")]
294#[derive(Debug, Clone)]
295pub struct BackbonePeerPoolSettings {
296 pub max_connected: usize,
297 pub failure_threshold: usize,
298 pub failure_window: Duration,
299 pub cooldown: Duration,
300}
301
302#[cfg(feature = "iface-backbone")]
303pub(crate) const BACKBONE_PEER_POOL_CONFIGURED_DEFAULT_PRIORITY: u8 = 60;
304#[cfg(feature = "iface-backbone")]
305pub(crate) const BACKBONE_PEER_POOL_DISCOVERED_PRIORITY: u8 = 40;
306
307#[cfg(feature = "iface-backbone")]
308pub(crate) struct BackbonePeerPoolCandidateConfig {
309 pub(crate) client: BackboneClientConfig,
310 pub(crate) mode: u8,
311 pub(crate) gravity: i64,
312 pub(crate) recursive_prs: bool,
313 pub(crate) announces_from_internal: bool,
314 pub(crate) announces_to_internal: Option<bool>,
315 pub(crate) ingress_control: rns_core::transport::types::IngressControlConfig,
316 pub(crate) stamp_costs: rns_core::transport::types::InterfaceStampCosts,
317 pub(crate) ifac_runtime: IfacRuntimeConfig,
318 pub(crate) ifac_enabled: bool,
319 pub(crate) interface_type_name: String,
320 pub(crate) source: BackbonePeerPoolCandidateSource,
321 pub(crate) priority: u8,
322 pub(crate) discovery: Option<BackbonePeerPoolDiscoveryCandidate>,
323}
324
325#[cfg(feature = "iface-backbone")]
326#[derive(Debug, Clone, Copy, PartialEq, Eq)]
327pub(crate) enum BackbonePeerPoolCandidateSource {
328 Configured,
329 Discovered,
330}
331
332#[cfg(feature = "iface-backbone")]
333impl BackbonePeerPoolCandidateSource {
334 fn as_str(self) -> &'static str {
335 match self {
336 Self::Configured => "configured",
337 Self::Discovered => "discovered",
338 }
339 }
340}
341
342#[cfg(feature = "iface-backbone")]
343#[derive(Debug, Clone)]
344pub(crate) struct BackbonePeerPoolDiscoveryCandidate {
345 pub(crate) discovery_hash: [u8; 32],
346 pub(crate) status: crate::discovery::DiscoveredStatus,
347 pub(crate) hops: u8,
348 pub(crate) stamp_value: rns_core::stamp::StampValue,
349 pub(crate) last_heard: f64,
350}
351
352#[cfg(feature = "iface-backbone")]
353struct BackbonePeerPool {
354 settings: BackbonePeerPoolSettings,
355 candidates: Vec<BackbonePeerPoolCandidate>,
356}
357
358#[cfg(feature = "iface-backbone")]
359struct BackbonePeerPoolCandidate {
360 config: BackbonePeerPoolCandidateConfig,
361 active_id: Option<InterfaceId>,
362 failures: Vec<f64>,
363 consecutive_failures: u32,
366 retry_after: Option<f64>,
367 cooldown_until: Option<f64>,
368 last_error: Option<String>,
369 control: Option<crate::interface::ListenerControl>,
371}
372
373#[cfg(feature = "hooks")]
375struct EngineRef<'a> {
376 engine: &'a TransportEngine,
377 interfaces: &'a crate::interface::InterfaceMap<InterfaceEntry>,
378 link_manager: &'a LinkManager,
379 now: f64,
380}
381
382#[cfg(feature = "hooks")]
383impl<'a> EngineAccess for EngineRef<'a> {
384 fn has_path(&self, dest: &[u8; 16]) -> bool {
385 self.engine.has_path(dest)
386 }
387 fn hops_to(&self, dest: &[u8; 16]) -> Option<u8> {
388 self.engine.hops_to(dest)
389 }
390 fn next_hop(&self, dest: &[u8; 16]) -> Option<[u8; 16]> {
391 self.engine.next_hop(dest)
392 }
393 fn is_blackholed(&self, identity: &[u8; 16]) -> bool {
394 self.engine.is_blackholed(identity, self.now)
395 }
396 fn interface_name(&self, id: u64) -> Option<String> {
397 self.interfaces
398 .get(&InterfaceId(id))
399 .map(|e| e.info.name.clone())
400 }
401 fn interface_mode(&self, id: u64) -> Option<u8> {
402 self.interfaces.get(&InterfaceId(id)).map(|e| e.info.mode)
403 }
404 fn identity_hash(&self) -> Option<[u8; 16]> {
405 self.engine.identity_hash().copied()
406 }
407 fn announce_rate(&self, id: u64) -> Option<i32> {
408 self.interfaces
409 .get(&InterfaceId(id))
410 .map(|e| (e.stats.outgoing_announce_freq() * 1000.0) as i32)
411 }
412 fn link_state(&self, link_hash: &[u8; 16]) -> Option<u8> {
413 use rns_core::link::types::LinkState;
414 self.link_manager.link_state(link_hash).map(|s| match s {
415 LinkState::Pending => 0,
416 LinkState::Handshake => 1,
417 LinkState::Active => 2,
418 LinkState::Stale => 3,
419 LinkState::Closed => 4,
420 })
421 }
422}
423
424#[cfg(any(test, feature = "hooks"))]
429fn extract_dest_hash(raw: &[u8]) -> [u8; 16] {
430 let mut dest = [0u8; 16];
431 if raw.is_empty() {
432 return dest;
433 }
434 let is_header2 = raw[0] & 0x40 != 0;
435 let start = if is_header2 { 18 } else { 2 };
436 let end = start + 16;
437 if raw.len() >= end {
438 dest.copy_from_slice(&raw[start..end]);
439 }
440 dest
441}
442
443#[cfg(feature = "hooks")]
445fn run_hook_inner(
446 programs: &mut [rns_hooks::LoadedProgram],
447 hook_manager: &Option<HookManager>,
448 engine_access: &dyn EngineAccess,
449 ctx: &HookContext,
450 now: f64,
451 provider_events_enabled: bool,
452) -> Option<rns_hooks::ExecuteResult> {
453 if programs.is_empty() {
454 return None;
455 }
456 let mgr = hook_manager.as_ref()?;
457 mgr.run_chain_with_provider_events(programs, ctx, engine_access, now, provider_events_enabled)
458}
459
460#[cfg(feature = "hooks")]
467pub(crate) enum PacketHookOutcome {
468 Keep,
470 Drop,
472 Replace(RawPacket),
475}
476
477#[cfg(feature = "hooks")]
480fn validate_hook_replacement(data: &[u8], max_len: usize) -> Result<RawPacket, &'static str> {
481 if data.is_empty() {
482 return Err("replacement is empty");
483 }
484 if data.len() > max_len {
485 return Err("replacement exceeds the packet size limit");
486 }
487 RawPacket::unpack(data).map_err(|_| "replacement does not decode as a packet")
488}
489
490#[cfg(feature = "hooks")]
491fn backbone_peer_hook_context(event: &BackbonePeerHookEvent) -> HookContext<'_> {
492 HookContext::BackbonePeer {
493 server_interface_id: event.server_interface_id.0,
494 peer_interface_id: event.peer_interface_id.map(|id| id.0),
495 peer_ip: event.peer_ip,
496 peer_port: event.peer_port,
497 connected_for: event.connected_for,
498 had_received_data: event.had_received_data,
499 penalty_level: event.penalty_level,
500 blacklist_for: event.blacklist_for,
501 }
502}
503
504#[cfg(feature = "hooks")]
506fn convert_injected_actions(actions: Vec<rns_hooks::ActionWire>) -> Vec<TransportAction> {
507 actions
508 .into_iter()
509 .map(|a| {
510 use rns_hooks::ActionWire;
511 match a {
512 ActionWire::SendOnInterface { interface, raw } => {
513 TransportAction::SendOnInterface {
514 interface: InterfaceId(interface),
515 raw: raw.into(),
516 }
517 }
518 ActionWire::BroadcastOnAllInterfaces {
519 raw,
520 exclude,
521 has_exclude,
522 } => TransportAction::BroadcastOnAllInterfaces {
523 raw: raw.into(),
524 exclude: if has_exclude != 0 {
525 Some(InterfaceId(exclude))
526 } else {
527 None
528 },
529 },
530 ActionWire::DeliverLocal {
531 destination_hash,
532 raw,
533 packet_hash,
534 receiving_interface,
535 } => TransportAction::DeliverLocal {
536 destination_hash,
537 raw: raw.into(),
538 packet_hash,
539 receiving_interface: InterfaceId(receiving_interface),
540 },
541 ActionWire::PathUpdated {
542 destination_hash,
543 hops,
544 next_hop,
545 interface,
546 } => TransportAction::PathUpdated {
547 destination_hash,
548 hops,
549 next_hop,
550 interface: InterfaceId(interface),
551 },
552 ActionWire::CacheAnnounce { packet_hash, raw } => TransportAction::CacheAnnounce {
553 packet_hash,
554 raw: raw.into(),
555 },
556 ActionWire::TunnelEstablished {
557 tunnel_id,
558 interface,
559 } => TransportAction::TunnelEstablished {
560 tunnel_id,
561 interface: InterfaceId(interface),
562 },
563 ActionWire::TunnelSynthesize {
564 interface,
565 data,
566 dest_hash,
567 } => TransportAction::TunnelSynthesize {
568 interface: InterfaceId(interface),
569 data,
570 dest_hash,
571 },
572 ActionWire::ForwardToLocalClients {
573 raw,
574 exclude,
575 has_exclude,
576 } => TransportAction::ForwardToLocalClients {
577 raw: raw.into(),
578 exclude: if has_exclude != 0 {
579 Some(InterfaceId(exclude))
580 } else {
581 None
582 },
583 },
584 ActionWire::ForwardPlainBroadcast {
585 raw,
586 to_local,
587 exclude,
588 has_exclude,
589 } => TransportAction::ForwardPlainBroadcast {
590 raw: raw.into(),
591 to_local: to_local != 0,
592 exclude: if has_exclude != 0 {
593 Some(InterfaceId(exclude))
594 } else {
595 None
596 },
597 },
598 ActionWire::AnnounceReceived {
599 destination_hash,
600 identity_hash,
601 public_key,
602 name_hash,
603 random_hash,
604 app_data,
605 hops,
606 receiving_interface,
607 } => TransportAction::AnnounceReceived(Box::new(ReceivedAnnounce {
608 destination_hash,
609 identity_hash,
610 public_key,
611 name_hash,
612 random_hash,
613 ratchet: None,
614 app_data,
615 stamp: None,
616 stamp_value: rns_core::stamp::StampValue::ZERO,
617 lr_cost: None,
618 hops,
619 receiving_interface: InterfaceId(receiving_interface),
620 rx: rns_core::transport::RxMetadata::default(),
621 })),
622 }
623 })
624 .collect()
625}
626
627fn infer_interface_type(name: &str) -> String {
631 if name.starts_with("TCPServerInterface") {
632 "TCPServerClientInterface".to_string()
633 } else if name.starts_with("BackboneInterface") {
634 "BackboneInterface".to_string()
635 } else if name.starts_with("LocalInterface") {
636 "LocalServerClientInterface".to_string()
637 } else if name.starts_with("WeaveInterfacePeer[") {
638 "WeaveInterfacePeer".to_string()
639 } else {
640 "AutoInterface".to_string()
643 }
644}
645
646pub use crate::common::callbacks::Callbacks;
647
648#[derive(Clone)]
649struct SharedAnnounceRecord {
650 name_hash: [u8; 10],
651 identity_prv_key: [u8; 64],
652 app_data: Option<Vec<u8>>,
653}
654
655type LocalPathResponseCache = HashMap<([u8; 16], Vec<u8>), (f64, Vec<u8>)>;
658
659#[derive(Debug, Clone)]
660pub(crate) struct KnownDestinationState {
661 announced: crate::destination::AnnouncedIdentity,
662 was_used: bool,
663 last_used_at: Option<f64>,
664 retained: bool,
665 stamp: Option<[u8; rns_core::constants::STAMP_LENGTH]>,
666 stamp_value: rns_core::stamp::StampValue,
667 lr_cost: Option<rns_core::stamp::StampCost>,
668}
669
670struct KnownDestinationCleanup {
671 candidates: Vec<[u8; 16]>,
672 cursor: usize,
673 started_at: Instant,
674 removed: usize,
675}
676
677#[derive(Debug, Clone, Copy)]
678pub(crate) struct TrafficSample {
679 sampled_at: f64,
680 rxb: u64,
681 txb: u64,
682 rx_packets: u64,
683 tx_packets: u64,
684 arxb: u64,
685 atxb: u64,
686 prxb: u64,
687 ptxb: u64,
688}
689
690impl TrafficSample {
691 fn from_stats(sampled_at: f64, stats: &crate::interface::InterfaceStats) -> Self {
692 Self {
693 sampled_at,
694 rxb: stats.rxb,
695 txb: stats.txb,
696 rx_packets: stats.rx_packets,
697 tx_packets: stats.tx_packets,
698 arxb: stats.arxb,
699 atxb: stats.atxb,
700 prxb: stats.prxb,
701 ptxb: stats.ptxb,
702 }
703 }
704}
705
706pub(crate) struct ManagedInterface {
708 pub(crate) parent_id: InterfaceId,
709 pub(crate) type_name: String,
710 pub(crate) control: Option<crate::interface::ListenerControl>,
711 pub(crate) static_ids: Vec<InterfaceId>,
712}
713
714pub(crate) const TRANSPORT_STATE_PERSIST_INTERVAL: Duration = Duration::from_secs(12 * 60 * 60);
716
717pub(crate) struct FoldedTimers {
720 pub(crate) next_tick: Instant,
721 pub(crate) next_persist: Instant,
722 pub(crate) persist_dir: Option<std::path::PathBuf>,
724 pub(crate) jobs: std::collections::VecDeque<FoldedJob>,
725 pub(crate) ticks_from_source: bool,
727 pub(crate) announces: std::collections::VecDeque<(
730 rns_core::transport::announce_verify_queue::AnnounceVerifyKey,
731 rns_core::transport::announce_verify_queue::PendingAnnounce,
732 )>,
733 pub(crate) announces_queued: bool,
735 pub(crate) compressions: std::collections::VecDeque<resource_preparation::FoldedCompression>,
737 pub(crate) next_compression_id: u64,
738}
739
740pub(crate) enum FoldedJob {
741 PersistTransportState,
742 CleanRatchets {
743 known_destinations: HashSet<[u8; 16]>,
744 now: f64,
745 expiry: f64,
746 },
747}
748
749impl FoldedTimers {
750 fn new() -> Self {
751 let now = Instant::now();
752 FoldedTimers {
753 next_tick: now + Duration::from_millis(DEFAULT_TICK_INTERVAL_MS),
754 next_persist: now + TRANSPORT_STATE_PERSIST_INTERVAL,
755 persist_dir: None,
756 jobs: std::collections::VecDeque::new(),
757 ticks_from_source: false,
758 announces: std::collections::VecDeque::new(),
759 announces_queued: false,
760 compressions: std::collections::VecDeque::new(),
761 next_compression_id: 0,
762 }
763 }
764}
765
766pub struct Driver {
767 resource_preparation: Option<resource_preparation::Worker>,
768 pub(crate) tracked_link_send: Option<([u8; 32], crate::link_send::Completion)>,
769 pub(crate) pending_link_frames: std::collections::VecDeque<PendingLinkFrame>,
770 pub(crate) engine: TransportEngine,
771 pub(crate) interfaces: crate::interface::InterfaceMap<InterfaceEntry>,
772 pub(crate) dynamic_interface_parents: HashMap<InterfaceId, InterfaceId>,
774 pub(crate) traffic_samples: HashMap<InterfaceId, TrafficSample>,
776 pub(crate) rng: OsRng,
777 pub(crate) rx: EventReceiver,
778 pub(crate) callbacks: Box<dyn Callbacks>,
779 pub(crate) started: f64,
780 pub(crate) lifecycle_state: LifecycleState,
781 pub(crate) accepting_work: Arc<AtomicBool>,
784 pub(crate) connected_to_shared_instance: bool,
788 pub(crate) drain_started_at: Option<Instant>,
789 pub(crate) drain_deadline: Option<Instant>,
790 pub(crate) listener_controls: Vec<crate::interface::ListenerControl>,
791 pub(crate) interface_management: Option<crate::node::InterfaceManagementConfig>,
792 pub(crate) managed_interfaces: HashMap<String, ManagedInterface>,
793 pub(crate) retired_interface_parents: HashSet<InterfaceId>,
794 pub(crate) writers_to_wake: Vec<InterfaceId>,
796 pub(crate) published_ingress_bursts: crate::interface::InterfaceMap<(Option<f64>, Option<f64>)>,
798 pub(crate) announce_cache: Option<crate::announce_cache::AnnounceCache>,
799 pub(crate) tunnel_synth_dest: [u8; 16],
801 pub(crate) transport_identity: Option<rns_crypto::identity::Identity>,
803 pub(crate) link_manager: LinkManager,
805 pub(crate) management_config: crate::management::ManagementConfig,
807 pub(crate) last_management_announce: f64,
809 pub(crate) initial_announce_sent: bool,
811 pub(crate) known_destinations: HashMap<[u8; 16], KnownDestinationState>,
813 pub(crate) ratchet_store: Option<Arc<dyn crate::storage::RatchetStore>>,
815 pub(crate) ratchet_expiry_secs: f64,
817 pub(crate) known_destinations_ttl: f64,
819 pub(crate) known_destinations_max_entries: usize,
821 pub(crate) rate_limiter_ttl_secs: f64,
823 pub(crate) path_request_dest: [u8; 16],
825 pub(crate) proof_strategies: HashMap<
828 [u8; 16],
829 (
830 rns_core::types::ProofStrategy,
831 Option<rns_crypto::identity::Identity>,
832 ),
833 >,
834 pub(crate) sent_packets: HashMap<[u8; 32], ([u8; 16], f64)>,
836 pub(crate) decrypted_destinations: HashMap<[u8; 16], Arc<rns_crypto::identity::Identity>>,
839 pub(crate) packet_proofs: Vec<crate::common::link_manager::ProofOutcome>,
841 pub(crate) transport_actions: crate::action_pool::ActionPool<TransportAction>,
843 pub(crate) link_actions: crate::action_pool::ActionPool<LinkManagerAction>,
845 pub(crate) completed_proofs: HashMap<[u8; 32], (f64, f64)>,
849 pub(crate) pending_probes: std::collections::HashSet<[u8; 32]>,
852 pub(crate) proof_keys: HashMap<[u8; 16], rns_crypto::ed25519::Ed25519PublicKey>,
856 pub(crate) local_destinations: HashMap<[u8; 16], u8>,
858 shared_announces: HashMap<[u8; 16], SharedAnnounceRecord>,
860 shared_reconnect_pending: HashMap<InterfaceId, bool>,
862 pub(crate) local_path_responses: LocalPathResponseCache,
866 pub(crate) holepunch_manager: HolePunchManager,
868 pub(crate) event_tx: crate::event::EventSender,
870 pub(crate) stamper: Arc<crate::stamper::Stamper>,
873 pub(crate) stamp_destinations: Arc<AtomicBool>,
876 pub(crate) stamp_settings: crate::config::StampsSection,
882 pub(crate) hop_limiter: u8,
886 pub(crate) interface_writer_queue_capacity: usize,
888 pub(crate) underlay_mark: Option<u32>,
890 pub(crate) announce_rate_defaults: AnnounceRateDefaults,
892 pub(crate) ingress_control_defaults: rns_core::transport::types::IngressControlConfig,
894 pub(crate) tick_interval_ms: Arc<AtomicU64>,
896 #[cfg(feature = "iface-backbone")]
898 pub(crate) backbone_runtime: HashMap<String, BackboneRuntimeConfigHandle>,
899 #[cfg(feature = "iface-backbone")]
901 pub(crate) backbone_peer_state: HashMap<String, BackbonePeerStateHandle>,
902 #[cfg(feature = "iface-backbone")]
904 pub(crate) backbone_client_runtime: HashMap<String, BackboneClientRuntimeConfigHandle>,
905 #[cfg(feature = "iface-backbone")]
907 pub(crate) backbone_discovery_runtime: HashMap<String, BackboneDiscoveryRuntimeHandle>,
908 #[cfg(feature = "iface-backbone")]
910 backbone_peer_pool: Option<BackbonePeerPool>,
911 pub(crate) next_dynamic_interface_id: Arc<AtomicU64>,
913 #[cfg(feature = "iface-tcp")]
915 pub(crate) tcp_server_runtime: HashMap<String, TcpServerRuntimeConfigHandle>,
916 #[cfg(feature = "iface-tcp")]
918 pub(crate) tcp_client_runtime: HashMap<String, TcpClientRuntimeConfigHandle>,
919 #[cfg(feature = "iface-tcp")]
921 pub(crate) tcp_server_discovery_runtime: HashMap<String, TcpServerDiscoveryRuntimeHandle>,
922 #[cfg(feature = "iface-udp")]
924 pub(crate) udp_runtime: HashMap<String, UdpRuntimeConfigHandle>,
925 #[cfg(feature = "iface-auto")]
927 pub(crate) auto_runtime: HashMap<String, AutoRuntimeConfigHandle>,
928 #[cfg(feature = "iface-i2p")]
930 pub(crate) i2p_runtime: HashMap<String, I2pRuntimeConfigHandle>,
931 #[cfg(feature = "iface-pipe")]
933 pub(crate) pipe_runtime: HashMap<String, PipeRuntimeConfigHandle>,
934 #[cfg(feature = "iface-rnode")]
936 pub(crate) rnode_runtime: HashMap<String, RNodeRuntimeConfigHandle>,
937 pub(crate) interface_runtime_defaults:
939 HashMap<String, rns_core::transport::types::InterfaceInfo>,
940 pub(crate) interface_ifac_runtime: HashMap<String, IfacRuntimeConfig>,
942 pub(crate) interface_ifac_runtime_defaults: HashMap<String, IfacRuntimeConfig>,
944 pub(crate) discovered_interfaces: crate::discovery::DiscoveredInterfaceStorage,
946 pub(crate) discovery_required_value: rns_core::stamp::StampCost,
948 pub(crate) discovery_stamp_cache: crate::discovery::DiscoveryStampCache,
950 pub(crate) discovery_name_hash: [u8; 10],
952 pub(crate) probe_responder_hash: Option<[u8; 16]>,
954 pub(crate) discover_interfaces: bool,
956 pub(crate) autoconnect_interface_mode: Option<u8>,
958 pub(crate) autoconnect_interface_gravity: i64,
960 pub(crate) autoconnect_announces_to_internal: Option<bool>,
962 pub(crate) autoconnect_unverified_implementations: bool,
964 pub(crate) interface_announcer: Option<crate::discovery::InterfaceAnnouncer>,
966 pub(crate) announce_verify_queue: Arc<Mutex<AnnounceVerifyQueue>>,
968 pub(crate) announce_verify_signal: Arc<WorkSignal>,
970 pub(crate) async_announce_verification: bool,
972 pub(crate) discovery_cleanup_counter: u32,
974 pub(crate) discovery_cleanup_interval_ticks: u32,
976 pub(crate) memory_stats_counter: u32,
978 pub(crate) state_snapshot_schedule: crate::state_snapshot::PublishSchedule,
980 pub(crate) cache_cleanup_counter: u32,
982 pub(crate) announce_cache_cleanup_counter: u32,
984 pub(crate) known_destinations_cleanup_interval_ticks: u32,
986 known_destination_cleanup: Option<KnownDestinationCleanup>,
988 ratchet_cleanup_handle: Option<std::thread::JoinHandle<()>>,
990 pub(crate) folded: FoldedTimers,
993 pub(crate) rpc_service: Option<rpc_service::RpcService>,
996 pub(crate) probe_server: Option<crate::holepunch::probe::FoldedProbeServer>,
999 pub(crate) known_destinations_cap_evict_count: usize,
1001 pub(crate) announce_cache_cleanup_interval_ticks: u32,
1003 pub(crate) announce_cache_cleanup_batch_size: usize,
1008 pub(crate) management_announce_interval_secs: f64,
1010 pub(crate) runtime_config_defaults: RuntimeConfigDefaults,
1012 #[cfg(feature = "hooks")]
1014 pub(crate) hook_slots: [HookSlot; HookPoint::COUNT],
1015 #[cfg(feature = "hooks")]
1017 pub(crate) hook_manager: Option<HookManager>,
1018 #[cfg(feature = "hooks")]
1019 pub(crate) provider_bridge: Option<ProviderBridge>,
1020 #[cfg(feature = "hooks")]
1023 pub(crate) hook_rejected_modifications: [u64; HookPoint::COUNT],
1024}
1025
1026impl Driver {
1027 pub fn new(
1029 config: TransportConfig,
1030 rx: EventReceiver,
1031 tx: crate::event::EventSender,
1032 callbacks: Box<dyn Callbacks>,
1033 ) -> Self {
1034 let announce_queue_max_entries = config.announce_queue_max_entries;
1035 let tunnel_synth_dest = rns_core::destination::destination_hash(
1036 "rnstransport",
1037 &["tunnel", "synthesize"],
1038 None,
1039 );
1040 let path_request_dest =
1041 rns_core::destination::destination_hash("rnstransport", &["path", "request"], None);
1042 let discovery_name_hash = crate::discovery::discovery_name_hash();
1043 let mut engine = TransportEngine::new(config);
1044 engine.seed_table_hashing(&mut OsRng);
1045 engine.register_destination(tunnel_synth_dest, rns_core::constants::DESTINATION_PLAIN);
1046 engine.register_destination(path_request_dest, rns_core::constants::DESTINATION_PLAIN);
1048 let mut local_destinations = HashMap::new();
1051 local_destinations.insert(tunnel_synth_dest, rns_core::constants::DESTINATION_PLAIN);
1052 local_destinations.insert(path_request_dest, rns_core::constants::DESTINATION_PLAIN);
1053 let runtime_config_defaults = RuntimeConfigDefaults {
1054 tick_interval_ms: DEFAULT_TICK_INTERVAL_MS,
1055 known_destinations_ttl: DEFAULT_KNOWN_DESTINATIONS_TTL,
1056 rate_limiter_ttl_secs: DEFAULT_RATE_LIMITER_TTL_SECS,
1057 known_destinations_cleanup_interval_ticks:
1058 DEFAULT_KNOWN_DESTINATIONS_CLEANUP_INTERVAL_TICKS,
1059 announce_cache_cleanup_interval_ticks: DEFAULT_ANNOUNCE_CACHE_CLEANUP_INTERVAL_TICKS,
1060 announce_cache_cleanup_batch_size: DEFAULT_ANNOUNCE_CACHE_CLEANUP_BATCH_SIZE,
1061 discovery_cleanup_interval_ticks: DEFAULT_DISCOVERY_CLEANUP_INTERVAL_TICKS,
1062 management_announce_interval_secs: DEFAULT_MANAGEMENT_ANNOUNCE_INTERVAL_SECS,
1063 direct_connect_policy: crate::event::HolePunchPolicy::default(),
1064 stamp_destinations: rns_core::constants::STAMP_DESTINATIONS,
1065 stamp_path_requests: rns_core::constants::STAMP_PRS,
1066 stamps_enforced: rns_core::constants::STAMPS_ENFORCED,
1067 lr_stamps_enforced: rns_core::constants::LR_STAMPS_ENFORCED,
1068 stamp_link_requests: rns_core::constants::STAMP_LRS,
1069 always_stamp_link_requests: rns_core::constants::ALWAYS_STAMP_LRS,
1070 #[cfg(feature = "hooks")]
1071 provider_queue_max_events: crate::provider_bridge::ProviderBridgeConfig::default()
1072 .queue_max_events,
1073 #[cfg(feature = "hooks")]
1074 provider_queue_max_bytes: crate::provider_bridge::ProviderBridgeConfig::default()
1075 .queue_max_bytes,
1076 };
1077 Driver {
1078 tracked_link_send: None,
1079 pending_link_frames: std::collections::VecDeque::new(),
1080 engine,
1081 interfaces: Default::default(),
1082 dynamic_interface_parents: HashMap::new(),
1083 traffic_samples: HashMap::new(),
1084 rng: OsRng,
1085 rx,
1086 callbacks,
1087 started: time::now(),
1088 lifecycle_state: LifecycleState::Active,
1089 accepting_work: Arc::new(AtomicBool::new(true)),
1090 connected_to_shared_instance: false,
1091 drain_started_at: None,
1092 drain_deadline: None,
1093 listener_controls: Vec::new(),
1094 interface_management: None,
1095 managed_interfaces: HashMap::new(),
1096 retired_interface_parents: HashSet::new(),
1097 published_ingress_bursts: Default::default(),
1098 writers_to_wake: Vec::new(),
1099 announce_cache: None,
1100 tunnel_synth_dest,
1101 transport_identity: None,
1102 link_manager: {
1103 let mut link_manager = LinkManager::new();
1104 link_manager.set_link_request_costs(tx.link_request_costs().clone());
1105 link_manager
1106 },
1107 management_config: Default::default(),
1108 last_management_announce: 0.0,
1109 initial_announce_sent: false,
1110 known_destinations: HashMap::new(),
1111 ratchet_store: None,
1112 ratchet_expiry_secs: rns_core::constants::RATCHET_EXPIRY as f64,
1113 known_destinations_ttl: DEFAULT_KNOWN_DESTINATIONS_TTL,
1114 known_destinations_max_entries: DEFAULT_KNOWN_DESTINATIONS_MAX_ENTRIES,
1115 rate_limiter_ttl_secs: DEFAULT_RATE_LIMITER_TTL_SECS,
1116 path_request_dest,
1117 proof_strategies: HashMap::new(),
1118 sent_packets: HashMap::new(),
1119 packet_proofs: Vec::new(),
1120 decrypted_destinations: HashMap::new(),
1121 transport_actions: crate::action_pool::ActionPool::new(),
1122 link_actions: crate::action_pool::ActionPool::new(),
1123 completed_proofs: HashMap::new(),
1124 pending_probes: std::collections::HashSet::new(),
1125 proof_keys: HashMap::new(),
1126 local_destinations,
1127 shared_announces: HashMap::new(),
1128 shared_reconnect_pending: HashMap::new(),
1129 local_path_responses: HashMap::new(),
1130 holepunch_manager: {
1131 let mut manager =
1132 HolePunchManager::new(vec![], rns_core::holepunch::ProbeProtocol::Rnsp, None);
1133 manager.set_event_sender(tx.clone());
1134 manager
1135 },
1136 stamper: Arc::new(crate::stamper::Stamper::new(tx.clone(), None)),
1137 stamp_destinations: Arc::new(AtomicBool::new(rns_core::constants::STAMP_DESTINATIONS)),
1138 stamp_settings: crate::config::StampsSection::default(),
1139 hop_limiter: rns_core::constants::HOP_LIMITER,
1140 event_tx: tx,
1141 interface_writer_queue_capacity: crate::interface::DEFAULT_ASYNC_WRITER_QUEUE_CAPACITY,
1142 underlay_mark: None,
1143 announce_rate_defaults: AnnounceRateDefaults::default(),
1144 ingress_control_defaults: rns_core::transport::types::IngressControlConfig::enabled(),
1145 tick_interval_ms: Arc::new(AtomicU64::new(DEFAULT_TICK_INTERVAL_MS)),
1146 #[cfg(feature = "iface-backbone")]
1147 backbone_runtime: HashMap::new(),
1148 #[cfg(feature = "iface-backbone")]
1149 backbone_peer_state: HashMap::new(),
1150 #[cfg(feature = "iface-backbone")]
1151 backbone_client_runtime: HashMap::new(),
1152 #[cfg(feature = "iface-backbone")]
1153 backbone_discovery_runtime: HashMap::new(),
1154 #[cfg(feature = "iface-backbone")]
1155 backbone_peer_pool: None,
1156 next_dynamic_interface_id: Arc::new(AtomicU64::new(10000)),
1157 #[cfg(feature = "iface-tcp")]
1158 tcp_server_runtime: HashMap::new(),
1159 #[cfg(feature = "iface-tcp")]
1160 tcp_client_runtime: HashMap::new(),
1161 #[cfg(feature = "iface-tcp")]
1162 tcp_server_discovery_runtime: HashMap::new(),
1163 #[cfg(feature = "iface-udp")]
1164 udp_runtime: HashMap::new(),
1165 #[cfg(feature = "iface-auto")]
1166 auto_runtime: HashMap::new(),
1167 #[cfg(feature = "iface-i2p")]
1168 i2p_runtime: HashMap::new(),
1169 #[cfg(feature = "iface-pipe")]
1170 pipe_runtime: HashMap::new(),
1171 #[cfg(feature = "iface-rnode")]
1172 rnode_runtime: HashMap::new(),
1173 interface_runtime_defaults: HashMap::new(),
1174 interface_ifac_runtime: HashMap::new(),
1175 interface_ifac_runtime_defaults: HashMap::new(),
1176 discovered_interfaces: crate::discovery::DiscoveredInterfaceStorage::new(
1177 std::env::temp_dir().join("rns-discovered-interfaces"),
1178 ),
1179 discovery_required_value: crate::discovery::DEFAULT_STAMP_VALUE,
1180 discovery_stamp_cache: crate::discovery::DiscoveryStampCache::default(),
1181 discovery_name_hash,
1182 probe_responder_hash: None,
1183 discover_interfaces: false,
1184 autoconnect_interface_mode: None,
1185 autoconnect_interface_gravity: 0,
1186 autoconnect_announces_to_internal: None,
1187 autoconnect_unverified_implementations: false,
1188 interface_announcer: None,
1189 announce_verify_queue: Arc::new(Mutex::new(AnnounceVerifyQueue::new(
1190 announce_queue_max_entries,
1191 ))),
1192 announce_verify_signal: Arc::default(),
1193 async_announce_verification: false,
1194 discovery_cleanup_counter: 0,
1195 discovery_cleanup_interval_ticks: runtime_config_defaults
1196 .discovery_cleanup_interval_ticks,
1197 memory_stats_counter: 0,
1198 state_snapshot_schedule: Default::default(),
1199 cache_cleanup_counter: 0,
1200 announce_cache_cleanup_counter: 0,
1201 known_destinations_cleanup_interval_ticks: runtime_config_defaults
1202 .known_destinations_cleanup_interval_ticks,
1203 known_destination_cleanup: None,
1204 ratchet_cleanup_handle: None,
1205 folded: FoldedTimers::new(),
1206 rpc_service: None,
1207 probe_server: None,
1208 resource_preparation: None,
1209 known_destinations_cap_evict_count: 0,
1210 announce_cache_cleanup_interval_ticks: runtime_config_defaults
1211 .announce_cache_cleanup_interval_ticks,
1212 announce_cache_cleanup_batch_size: runtime_config_defaults
1213 .announce_cache_cleanup_batch_size,
1214 management_announce_interval_secs: runtime_config_defaults
1215 .management_announce_interval_secs,
1216 runtime_config_defaults,
1217 #[cfg(feature = "hooks")]
1218 hook_slots: create_hook_slots(),
1219 #[cfg(feature = "hooks")]
1220 hook_manager: HookManager::new().ok(),
1221 #[cfg(feature = "hooks")]
1222 provider_bridge: None,
1223 #[cfg(feature = "hooks")]
1224 hook_rejected_modifications: [0; HookPoint::COUNT],
1225 }
1226 }
1227
1228 pub fn set_announce_verify_queue_config(
1229 &mut self,
1230 max_entries: usize,
1231 max_bytes: usize,
1232 max_stale_secs: f64,
1233 overflow_policy: OverflowPolicy,
1234 ) {
1235 self.announce_verify_queue = Arc::new(Mutex::new(AnnounceVerifyQueue::with_limits(
1236 max_entries,
1237 max_bytes,
1238 max_stale_secs,
1239 overflow_policy,
1240 )));
1241 }
1242
1243 pub fn set_announce_rate_defaults(&mut self, defaults: AnnounceRateDefaults) {
1244 self.announce_rate_defaults = defaults;
1245 }
1246
1247 pub fn set_ingress_control_defaults(
1248 &mut self,
1249 defaults: rns_core::transport::types::IngressControlConfig,
1250 ) {
1251 self.ingress_control_defaults = defaults;
1252 }
1253
1254 pub(crate) fn apply_announce_rate_defaults(
1255 &self,
1256 info: &mut rns_core::transport::types::InterfaceInfo,
1257 ) {
1258 if !self.engine.transport_enabled() || info.announce_rate_target.is_some() {
1259 return;
1260 }
1261
1262 let Some(target) = self.announce_rate_defaults.target else {
1263 return;
1264 };
1265
1266 info.announce_rate_target = Some(target);
1267 if info.announce_rate_grace == 0 {
1268 info.announce_rate_grace = self.announce_rate_defaults.grace;
1269 }
1270 if info.announce_rate_penalty == 0.0 {
1271 info.announce_rate_penalty = self.announce_rate_defaults.penalty;
1272 }
1273 }
1274
1275 pub(crate) fn apply_ingress_control_defaults(
1276 &self,
1277 info: &mut rns_core::transport::types::InterfaceInfo,
1278 ) {
1279 if !self.engine.transport_enabled() {
1280 return;
1281 }
1282
1283 let baseline = if info.ingress_control.enabled {
1284 rns_core::transport::types::IngressControlConfig::enabled()
1285 } else {
1286 rns_core::transport::types::IngressControlConfig::disabled()
1287 };
1288 let defaults = self.ingress_control_defaults;
1289 let ic = &mut info.ingress_control;
1290
1291 if ic.max_held_announces == baseline.max_held_announces {
1292 ic.max_held_announces = defaults.max_held_announces;
1293 }
1294 if ic.burst_hold == baseline.burst_hold {
1295 ic.burst_hold = defaults.burst_hold;
1296 }
1297 if ic.burst_freq_new == baseline.burst_freq_new {
1298 ic.burst_freq_new = defaults.burst_freq_new;
1299 }
1300 if ic.burst_freq == baseline.burst_freq {
1301 ic.burst_freq = defaults.burst_freq;
1302 }
1303 if ic.pr_burst_freq_new == baseline.pr_burst_freq_new {
1304 ic.pr_burst_freq_new = defaults.pr_burst_freq_new;
1305 }
1306 if ic.pr_burst_freq == baseline.pr_burst_freq {
1307 ic.pr_burst_freq = defaults.pr_burst_freq;
1308 }
1309 if ic.new_time == baseline.new_time {
1310 ic.new_time = defaults.new_time;
1311 }
1312 if ic.burst_penalty == baseline.burst_penalty {
1313 ic.burst_penalty = defaults.burst_penalty;
1314 }
1315 if ic.held_release_interval == baseline.held_release_interval {
1316 ic.held_release_interval = defaults.held_release_interval;
1317 }
1318 if ic.egress_enabled == baseline.egress_enabled {
1319 ic.egress_enabled = defaults.egress_enabled;
1320 }
1321 if ic.egress_pr_freq == baseline.egress_pr_freq {
1322 ic.egress_pr_freq = defaults.egress_pr_freq;
1323 }
1324 }
1325
1326 fn wrap_interface_writer(
1327 &self,
1328 interface_id: InterfaceId,
1329 interface_name: &str,
1330 writer: Box<dyn crate::interface::Writer>,
1331 ) -> (
1332 Box<dyn crate::interface::Writer>,
1333 crate::interface::AsyncWriterMetrics,
1334 ) {
1335 crate::interface::wrap_async_writer(
1336 writer,
1337 interface_id,
1338 interface_name,
1339 self.event_tx.clone(),
1340 self.interface_writer_queue_capacity,
1341 )
1342 }
1343
1344 #[cfg(feature = "hooks")]
1345 fn provider_events_enabled(&self) -> bool {
1346 self.provider_bridge.is_some()
1347 }
1348
1349 #[cfg(feature = "hooks")]
1352 pub(crate) fn hooks_attached(&self, point: HookPoint) -> bool {
1353 !self.hook_slots[point as usize].programs.is_empty()
1354 }
1355
1356 #[cfg(feature = "hooks")]
1357 fn run_backbone_peer_hook(
1358 &mut self,
1359 attach_point: &str,
1360 point: HookPoint,
1361 event: &BackbonePeerHookEvent,
1362 ) {
1363 let ctx = backbone_peer_hook_context(event);
1364 let now = time::now();
1365 let engine_ref = EngineRef {
1366 engine: &self.engine,
1367 interfaces: &self.interfaces,
1368 link_manager: &self.link_manager,
1369 now,
1370 };
1371 let provider_events_enabled = self.provider_events_enabled();
1372 if let Some(ref e) = run_hook_inner(
1373 &mut self.hook_slots[point as usize].programs,
1374 &self.hook_manager,
1375 &engine_ref,
1376 &ctx,
1377 now,
1378 provider_events_enabled,
1379 ) {
1380 self.forward_hook_side_effects(attach_point, e);
1381 }
1382 }
1383
1384 #[cfg(feature = "iface-backbone")]
1385 fn make_discoverable_interface(
1386 runtime: &BackboneDiscoveryRuntimeHandle,
1387 ) -> crate::discovery::DiscoverableInterface {
1388 crate::discovery::DiscoverableInterface {
1389 interface_name: runtime.interface_name.clone(),
1390 config: runtime.current.config.clone(),
1391 transport_enabled: runtime.current.transport_enabled,
1392 ifac_netname: runtime.current.ifac_netname.clone(),
1393 ifac_netkey: runtime.current.ifac_netkey.clone(),
1394 }
1395 }
1396
1397 #[cfg(feature = "iface-backbone")]
1398 fn sync_backbone_discovery_runtime(
1399 &mut self,
1400 interface_name: &str,
1401 ) -> Result<(), RuntimeConfigError> {
1402 let handle = self
1403 .backbone_discovery_runtime
1404 .get(interface_name)
1405 .ok_or(RuntimeConfigError {
1406 code: RuntimeConfigErrorCode::NotFound,
1407 message: format!("backbone interface '{}' not found", interface_name),
1408 })?
1409 .clone();
1410
1411 if handle.current.discoverable {
1412 let iface = Self::make_discoverable_interface(&handle);
1413 if let Some(announcer) = self.interface_announcer.as_mut() {
1414 announcer.upsert_interface(iface);
1415 } else if let Some(identity) = self.transport_identity.as_ref() {
1416 self.interface_announcer = Some(crate::discovery::InterfaceAnnouncer::new(
1417 *identity.hash(),
1418 vec![iface],
1419 ));
1420 }
1421 } else if let Some(announcer) = self.interface_announcer.as_mut() {
1422 announcer.remove_interface(interface_name);
1423 if announcer.is_empty() {
1424 self.interface_announcer = None;
1425 }
1426 }
1427
1428 Ok(())
1429 }
1430
1431 #[cfg(feature = "iface-tcp")]
1432 fn make_tcp_server_discoverable_interface(
1433 runtime: &TcpServerDiscoveryRuntimeHandle,
1434 ) -> crate::discovery::DiscoverableInterface {
1435 crate::discovery::DiscoverableInterface {
1436 interface_name: runtime.interface_name.clone(),
1437 config: runtime.current.config.clone(),
1438 transport_enabled: runtime.current.transport_enabled,
1439 ifac_netname: runtime.current.ifac_netname.clone(),
1440 ifac_netkey: runtime.current.ifac_netkey.clone(),
1441 }
1442 }
1443
1444 #[cfg(feature = "iface-tcp")]
1445 fn sync_tcp_server_discovery_runtime(
1446 &mut self,
1447 interface_name: &str,
1448 ) -> Result<(), RuntimeConfigError> {
1449 let handle = self
1450 .tcp_server_discovery_runtime
1451 .get(interface_name)
1452 .ok_or(RuntimeConfigError {
1453 code: RuntimeConfigErrorCode::NotFound,
1454 message: format!("tcp server interface '{}' not found", interface_name),
1455 })?
1456 .clone();
1457
1458 if handle.current.discoverable {
1459 let iface = Self::make_tcp_server_discoverable_interface(&handle);
1460 if let Some(announcer) = self.interface_announcer.as_mut() {
1461 announcer.upsert_interface(iface);
1462 } else if let Some(identity) = self.transport_identity.as_ref() {
1463 self.interface_announcer = Some(crate::discovery::InterfaceAnnouncer::new(
1464 *identity.hash(),
1465 vec![iface],
1466 ));
1467 }
1468 } else if let Some(announcer) = self.interface_announcer.as_mut() {
1469 announcer.remove_interface(interface_name);
1470 if announcer.is_empty() {
1471 self.interface_announcer = None;
1472 }
1473 }
1474
1475 Ok(())
1476 }
1477
1478 #[cfg(feature = "hooks")]
1479 fn update_hook_program<F>(
1480 &mut self,
1481 name: &str,
1482 attach_point: &str,
1483 mut update: F,
1484 ) -> Result<(), String>
1485 where
1486 F: FnMut(&mut rns_hooks::LoadedProgram),
1487 {
1488 let point_idx = crate::config::parse_hook_point(attach_point)
1489 .ok_or_else(|| format!("unknown hook point '{}'", attach_point))?;
1490 let program = self.hook_slots[point_idx]
1491 .programs
1492 .iter_mut()
1493 .find(|program| program.name == name)
1494 .ok_or_else(|| format!("hook '{}' not found at point '{}'", name, attach_point))?;
1495 update(program);
1496 Ok(())
1497 }
1498
1499 pub(crate) fn set_tick_interval_handle(&mut self, tick_interval_ms: Arc<AtomicU64>) {
1500 self.tick_interval_ms = tick_interval_ms;
1501 }
1502
1503 pub(crate) fn set_stamper(&mut self, stamper: Arc<crate::stamper::Stamper>) {
1506 self.stamper = stamper;
1507 }
1508
1509 pub(crate) fn apply_stamp_config(
1517 &mut self,
1518 stamps: &crate::config::StampsSection,
1519 hop_limiter: u8,
1520 ) {
1521 self.engine.set_stamp_requirements(stamps.requirements());
1522 self.engine.set_stamp_prs(stamps.stamp_prs);
1523 self.stamp_destinations
1524 .store(stamps.stamp_destinations, Ordering::Relaxed);
1525 self.stamper
1526 .set_targets(crate::stamper::StampTargets::from(stamps));
1527 self.stamper
1528 .set_path_request_timeout(stamps.path_request_stamp_timeout());
1529 self.runtime_config_defaults.stamp_destinations = stamps.stamp_destinations;
1530 self.runtime_config_defaults.stamp_path_requests = stamps.stamp_prs;
1531 self.runtime_config_defaults.stamp_link_requests = stamps.stamp_lrs;
1532 self.runtime_config_defaults.always_stamp_link_requests = stamps.always_stamp_lrs;
1533 self.runtime_config_defaults.stamps_enforced = stamps.stamps_enforced;
1534 self.runtime_config_defaults.lr_stamps_enforced = stamps.lr_stamps_enforced;
1535 let link_request_costs = self.link_manager.link_request_costs();
1539 link_request_costs.set_default_cost(stamps.lr_cost);
1540 link_request_costs.set_enforced(stamps.lr_stamps_enforced);
1541 self.stamp_settings = stamps.clone();
1542 self.hop_limiter = hop_limiter;
1543 if hop_limiter != rns_core::constants::PATHFINDER_M {
1545 log::debug!("Transport hop limit set to {hop_limiter}");
1546 }
1547 }
1548
1549 pub(crate) fn set_stamps_enforced(&mut self, enforced: bool) {
1552 let mut requirements = self.engine.stamp_requirements();
1553 requirements.enforced = enforced;
1554 self.engine.set_stamp_requirements(requirements);
1555 }
1556
1557 pub(crate) fn set_stamp_destinations_flag(&mut self, flag: Arc<AtomicBool>) {
1560 self.stamp_destinations = flag;
1561 }
1562
1563 pub(crate) fn accepting_work_handle(&self) -> Arc<AtomicBool> {
1565 Arc::clone(&self.accepting_work)
1566 }
1567
1568 #[allow(dead_code)]
1569 pub(crate) fn set_packet_hashlist_max_entries(&mut self, max_entries: usize) {
1570 self.engine.set_packet_hashlist_max_entries(max_entries);
1571 }
1572
1573 #[cfg(feature = "hooks")]
1581 pub(crate) fn packet_hook_outcome(
1582 &mut self,
1583 point: HookPoint,
1584 exec: &rns_hooks::ExecuteResult,
1585 max_len: usize,
1586 ) -> PacketHookOutcome {
1587 let Some(result) = exec.hook_result.as_ref() else {
1588 return PacketHookOutcome::Keep;
1589 };
1590 if result.is_drop() {
1591 return PacketHookOutcome::Drop;
1592 }
1593 if rns_hooks::Verdict::from_u32(result.verdict) != Some(rns_hooks::Verdict::Modify) {
1594 return PacketHookOutcome::Keep;
1595 }
1596 let Some(data) = exec.modified_data.as_deref() else {
1597 return PacketHookOutcome::Keep;
1598 };
1599 match validate_hook_replacement(data, max_len) {
1600 Ok(packet) => PacketHookOutcome::Replace(packet),
1601 Err(reason) => {
1602 let rejected = &mut self.hook_rejected_modifications[point as usize];
1603 *rejected = rejected.saturating_add(1);
1604 log::debug!("{:?} hook: {}; dropping packet", point, reason);
1605 PacketHookOutcome::Drop
1606 }
1607 }
1608 }
1609
1610 #[cfg(feature = "hooks")]
1612 pub(crate) fn hook_packet_limit(&self, interface: InterfaceId) -> usize {
1613 self.interfaces
1614 .get(&interface)
1615 .map(|entry| entry.info.mtu as usize)
1616 .filter(|mtu| *mtu > 0)
1617 .unwrap_or(rns_core::constants::MTU)
1618 }
1619
1620 #[cfg(feature = "hooks")]
1623 pub(crate) fn retarget_tracked_link_send(&mut self, original: &[u8], replacement: &RawPacket) {
1624 let Some((hash, _)) = self.tracked_link_send.as_mut() else {
1625 return;
1626 };
1627 if RawPacket::unpack(original).is_ok_and(|packet| packet.packet_hash == *hash) {
1628 *hash = replacement.packet_hash;
1629 }
1630 }
1631
1632 #[cfg(feature = "hooks")]
1633 fn forward_hook_side_effects(&mut self, attach_point: &str, exec: &rns_hooks::ExecuteResult) {
1634 if !exec.injected_actions.is_empty() {
1635 self.dispatch_all(convert_injected_actions(exec.injected_actions.clone()));
1636 }
1637 if let Some(ref bridge) = self.provider_bridge {
1638 for event in &exec.provider_events {
1639 bridge.emit_event(
1640 attach_point,
1641 event.hook_name.clone(),
1642 event.payload_type.clone(),
1643 event.payload.clone(),
1644 );
1645 }
1646 }
1647 }
1648
1649 #[cfg(feature = "hooks")]
1650 fn collect_hook_side_effects(
1651 &mut self,
1652 attach_point: &str,
1653 exec: &rns_hooks::ExecuteResult,
1654 out: &mut Vec<TransportAction>,
1655 ) {
1656 if !exec.injected_actions.is_empty() {
1657 out.extend(convert_injected_actions(exec.injected_actions.clone()));
1658 }
1659 if let Some(ref bridge) = self.provider_bridge {
1660 for event in &exec.provider_events {
1661 bridge.emit_event(
1662 attach_point,
1663 event.hook_name.clone(),
1664 event.payload_type.clone(),
1665 event.payload.clone(),
1666 );
1667 }
1668 }
1669 }
1670
1671 pub fn set_probe_config(
1673 &mut self,
1674 addrs: Vec<std::net::SocketAddr>,
1675 protocol: rns_core::holepunch::ProbeProtocol,
1676 device: Option<String>,
1677 ) {
1678 let policy = self.holepunch_manager.policy();
1679 let allow_private = self.holepunch_manager.allow_private_endpoints();
1680 self.holepunch_manager = HolePunchManager::new(addrs, protocol, device);
1681 self.holepunch_manager
1682 .set_event_sender(self.event_tx.clone());
1683 self.holepunch_manager.set_underlay_mark(self.underlay_mark);
1684 self.holepunch_manager.set_policy(policy);
1685 self.holepunch_manager
1686 .set_allow_private_endpoints(allow_private);
1687 }
1688}
1689
1690pub(crate) struct PendingLinkFrame {
1691 interface: InterfaceId,
1692 data: Vec<u8>,
1693 is_announce: bool,
1694 completion: Option<crate::link_send::Completion>,
1695}
1696
1697#[derive(Default)]
1700pub(crate) struct WorkSignal {
1701 state: Mutex<(bool, bool)>,
1703 condvar: std::sync::Condvar,
1704}
1705
1706impl WorkSignal {
1707 fn lock(&self) -> std::sync::MutexGuard<'_, (bool, bool)> {
1708 self.state
1709 .lock()
1710 .unwrap_or_else(|poisoned| poisoned.into_inner())
1711 }
1712
1713 pub(crate) fn notify(&self) {
1715 self.lock().0 = true;
1716 self.condvar.notify_one();
1717 }
1718
1719 pub(crate) fn stop(&self) {
1721 self.lock().1 = true;
1722 self.condvar.notify_all();
1723 }
1724
1725 pub(crate) fn stopped(&self) -> bool {
1726 self.lock().1
1727 }
1728
1729 pub(crate) fn wait(&self) -> bool {
1732 let mut state = self.lock();
1733 while !state.0 && !state.1 {
1734 state = self
1735 .condvar
1736 .wait(state)
1737 .unwrap_or_else(|poisoned| poisoned.into_inner());
1738 }
1739 state.0 = false;
1740 !state.1
1741 }
1742}