1use std::collections::HashMap;
4use std::io;
5use std::sync::atomic::{AtomicU64, Ordering};
6use std::sync::{Arc, Mutex};
7use std::time::{Duration, Instant};
8
9use rns_core::packet::RawPacket;
10use rns_core::transport::announce_verify_queue::{AnnounceVerifyQueue, OverflowPolicy};
11use rns_core::transport::tables::PathEntry;
12use rns_core::transport::types::{InterfaceId, TransportAction, TransportConfig};
13use rns_core::transport::TransportEngine;
14use rns_crypto::{OsRng, Rng};
15
16#[cfg(feature = "hooks")]
17use crate::provider_bridge::ProviderBridge;
18#[cfg(feature = "hooks")]
19use rns_hooks::{create_hook_slots, EngineAccess, HookContext, HookManager, HookPoint, HookSlot};
20
21#[cfg(feature = "hooks")]
22use crate::event::BackbonePeerHookEvent;
23use crate::event::{
24 BackbonePeerPoolMemberStatus, BackbonePeerPoolStatus, BackbonePeerStateEntry, BlackholeInfo,
25 DrainStatus, Event, EventReceiver, InterfaceStatsResponse, KnownDestinationEntry,
26 LifecycleState, LocalDestinationEntry, NextHopResponse, PathTableEntry, QueryRequest,
27 QueryResponse, RateTableEntry, RuntimeConfigApplyMode, RuntimeConfigEntry, RuntimeConfigError,
28 RuntimeConfigErrorCode, RuntimeConfigSource, RuntimeConfigValue, SingleInterfaceStat,
29};
30use crate::holepunch::orchestrator::{HolePunchManager, HolePunchManagerAction};
31use crate::ifac;
32#[cfg(all(feature = "iface-auto", test))]
33use crate::interface::auto::AutoRuntime;
34#[cfg(feature = "iface-auto")]
35use crate::interface::auto::AutoRuntimeConfigHandle;
36#[cfg(feature = "iface-backbone")]
37use crate::interface::backbone::{
38 start_client_with_ifac, BackboneClientConfig, BackboneClientRuntime,
39 BackboneClientRuntimeConfigHandle, BackbonePeerStateHandle, BackboneRuntimeConfigHandle,
40};
41#[cfg(all(feature = "iface-backbone", target_os = "linux", test))]
42use crate::interface::backbone::{BackboneAbuseConfig, BackboneServerRuntime};
43#[cfg(all(feature = "iface-i2p", test))]
44use crate::interface::i2p::I2pRuntime;
45#[cfg(feature = "iface-i2p")]
46use crate::interface::i2p::I2pRuntimeConfigHandle;
47#[cfg(all(feature = "iface-pipe", test))]
48use crate::interface::pipe::PipeRuntime;
49#[cfg(feature = "iface-pipe")]
50use crate::interface::pipe::PipeRuntimeConfigHandle;
51#[cfg(feature = "iface-rnode")]
52use crate::interface::rnode::{
53 validate_sub_config, RNodeRuntime, RNodeRuntimeConfigHandle, RNodeSubConfig,
54};
55#[cfg(feature = "iface-tcp")]
56use crate::interface::tcp::TcpClientRuntimeConfigHandle;
57#[cfg(all(feature = "iface-tcp", test))]
58use crate::interface::tcp_server::TcpServerRuntime;
59#[cfg(feature = "iface-tcp")]
60use crate::interface::tcp_server::TcpServerRuntimeConfigHandle;
61#[cfg(all(feature = "iface-udp", test))]
62use crate::interface::udp::UdpRuntime;
63#[cfg(feature = "iface-udp")]
64use crate::interface::udp::UdpRuntimeConfigHandle;
65use crate::interface::{InterfaceEntry, InterfaceStats};
66use crate::link_manager::{LinkManager, LinkManagerAction};
67use crate::time;
68
69const DEFAULT_KNOWN_DESTINATIONS_TTL: f64 = 48.0 * 60.0 * 60.0;
70const DEFAULT_KNOWN_DESTINATIONS_MAX_ENTRIES: usize = 8192;
71const DEFAULT_RATE_LIMITER_TTL_SECS: f64 = 48.0 * 60.0 * 60.0;
72const DEFAULT_TICK_INTERVAL_MS: u64 = 1000;
73const DEFAULT_KNOWN_DESTINATIONS_CLEANUP_INTERVAL_TICKS: u32 = 3600;
74const KNOWN_DESTINATION_CLEANUP_BATCH_SIZE: usize = 64;
75const DEFAULT_ANNOUNCE_CACHE_CLEANUP_INTERVAL_TICKS: u32 = 3600;
76const DEFAULT_ANNOUNCE_CACHE_CLEANUP_BATCH_SIZE: usize = 10_000;
77const DEFAULT_DISCOVERY_CLEANUP_INTERVAL_TICKS: u32 = 3600;
78const DEFAULT_MANAGEMENT_ANNOUNCE_INTERVAL_SECS: f64 = 300.0;
79const DEFAULT_LINK_TEARDOWN_FLUSH: Duration = Duration::from_millis(150);
80const SEND_RETRY_BACKOFF_MIN: Duration = Duration::from_millis(25);
81const SEND_RETRY_BACKOFF_MAX: Duration = Duration::from_millis(1000);
82
83#[derive(Debug, Clone, Copy, PartialEq)]
85pub struct AnnounceRateDefaults {
86 pub target: Option<f64>,
87 pub penalty: f64,
88 pub grace: u32,
89}
90
91impl Default for AnnounceRateDefaults {
92 fn default() -> Self {
93 Self {
94 target: Some(3600.0),
95 penalty: 0.0,
96 grace: 5,
97 }
98 }
99}
100
101mod dispatch;
102mod events;
103mod lifecycle;
104mod queries;
105mod runtime_config;
106
107#[cfg(test)]
108mod tests;
109
110fn inject_transport_header(raw: &[u8], next_hop: &[u8; 16]) -> Vec<u8> {
111 if raw.len() < 18 {
112 return raw.to_vec();
113 }
114
115 let new_flags = (rns_core::constants::HEADER_2 << 6)
116 | (rns_core::constants::TRANSPORT_TRANSPORT << 4)
117 | (raw[0] & 0x0F);
118
119 let mut new_raw = Vec::with_capacity(raw.len() + 16);
120 new_raw.push(new_flags);
121 new_raw.push(raw[1]);
122 new_raw.extend_from_slice(next_hop);
123 new_raw.extend_from_slice(&raw[2..]);
124 new_raw
125}
126
127fn recover_mutex_guard<'a, T>(mutex: &'a Mutex<T>, label: &str) -> std::sync::MutexGuard<'a, T> {
128 match mutex.lock() {
129 Ok(guard) => guard,
130 Err(poisoned) => {
131 log::error!("recovering from poisoned mutex: {}", label);
132 poisoned.into_inner()
133 }
134 }
135}
136
137#[derive(Debug, Clone, Copy)]
138pub(crate) struct RuntimeConfigDefaults {
139 pub(crate) tick_interval_ms: u64,
140 pub(crate) known_destinations_ttl: f64,
141 pub(crate) rate_limiter_ttl_secs: f64,
142 pub(crate) known_destinations_cleanup_interval_ticks: u32,
143 pub(crate) announce_cache_cleanup_interval_ticks: u32,
144 pub(crate) announce_cache_cleanup_batch_size: usize,
145 pub(crate) discovery_cleanup_interval_ticks: u32,
146 pub(crate) management_announce_interval_secs: f64,
147 pub(crate) direct_connect_policy: crate::event::HolePunchPolicy,
148 #[cfg(feature = "hooks")]
149 pub(crate) provider_queue_max_events: usize,
150 #[cfg(feature = "hooks")]
151 pub(crate) provider_queue_max_bytes: usize,
152}
153
154#[cfg(feature = "iface-backbone")]
155#[derive(Debug, Clone)]
156pub(crate) struct BackboneDiscoveryRuntime {
157 pub(crate) discoverable: bool,
158 pub(crate) config: crate::discovery::DiscoveryConfig,
159 pub(crate) transport_enabled: bool,
160 pub(crate) ifac_netname: Option<String>,
161 pub(crate) ifac_netkey: Option<String>,
162}
163
164#[cfg(feature = "iface-backbone")]
165#[derive(Debug, Clone)]
166pub(crate) struct BackboneDiscoveryRuntimeHandle {
167 pub(crate) interface_name: String,
168 pub(crate) current: BackboneDiscoveryRuntime,
169 pub(crate) startup: BackboneDiscoveryRuntime,
170}
171
172#[cfg(feature = "iface-tcp")]
173#[derive(Debug, Clone)]
174pub(crate) struct TcpServerDiscoveryRuntime {
175 pub(crate) discoverable: bool,
176 pub(crate) config: crate::discovery::DiscoveryConfig,
177 pub(crate) transport_enabled: bool,
178 pub(crate) ifac_netname: Option<String>,
179 pub(crate) ifac_netkey: Option<String>,
180}
181
182#[cfg(feature = "iface-tcp")]
183#[derive(Debug, Clone)]
184pub(crate) struct TcpServerDiscoveryRuntimeHandle {
185 pub(crate) interface_name: String,
186 pub(crate) current: TcpServerDiscoveryRuntime,
187 pub(crate) startup: TcpServerDiscoveryRuntime,
188}
189
190#[derive(Debug, Clone, PartialEq, Eq)]
191pub(crate) struct IfacRuntimeConfig {
192 pub(crate) netname: Option<String>,
193 pub(crate) netkey: Option<String>,
194 pub(crate) size: usize,
195}
196
197#[cfg(feature = "iface-backbone")]
198impl BackboneDiscoveryRuntimeHandle {
199 pub(crate) fn from_parts(
200 interface_name: String,
201 startup_config: crate::discovery::DiscoveryConfig,
202 transport_enabled: bool,
203 ifac_netname: Option<String>,
204 ifac_netkey: Option<String>,
205 discoverable: bool,
206 ) -> Self {
207 let startup = BackboneDiscoveryRuntime {
208 discoverable,
209 config: startup_config,
210 transport_enabled,
211 ifac_netname,
212 ifac_netkey,
213 };
214 Self {
215 interface_name,
216 current: startup.clone(),
217 startup,
218 }
219 }
220}
221
222#[cfg(feature = "iface-tcp")]
223impl TcpServerDiscoveryRuntimeHandle {
224 pub(crate) fn from_parts(
225 interface_name: String,
226 startup_config: crate::discovery::DiscoveryConfig,
227 transport_enabled: bool,
228 ifac_netname: Option<String>,
229 ifac_netkey: Option<String>,
230 discoverable: bool,
231 ) -> Self {
232 let startup = TcpServerDiscoveryRuntime {
233 discoverable,
234 config: startup_config,
235 transport_enabled,
236 ifac_netname,
237 ifac_netkey,
238 };
239 Self {
240 interface_name,
241 current: startup.clone(),
242 startup,
243 }
244 }
245}
246
247impl IfacRuntimeConfig {
248 pub(crate) fn from_parts(netname: Option<String>, netkey: Option<String>, size: usize) -> Self {
249 Self {
250 netname,
251 netkey,
252 size,
253 }
254 }
255}
256
257#[cfg(feature = "iface-backbone")]
258#[derive(Debug, Clone)]
259pub struct BackbonePeerPoolSettings {
260 pub max_connected: usize,
261 pub failure_threshold: usize,
262 pub failure_window: Duration,
263 pub cooldown: Duration,
264}
265
266#[cfg(feature = "iface-backbone")]
267pub(crate) const BACKBONE_PEER_POOL_CONFIGURED_DEFAULT_PRIORITY: u8 = 60;
268#[cfg(feature = "iface-backbone")]
269pub(crate) const BACKBONE_PEER_POOL_DISCOVERED_PRIORITY: u8 = 40;
270
271#[cfg(feature = "iface-backbone")]
272pub(crate) struct BackbonePeerPoolCandidateConfig {
273 pub(crate) client: BackboneClientConfig,
274 pub(crate) mode: u8,
275 pub(crate) gravity: i64,
276 pub(crate) recursive_prs: bool,
277 pub(crate) announces_from_internal: bool,
278 pub(crate) announces_to_internal: Option<bool>,
279 pub(crate) ingress_control: rns_core::transport::types::IngressControlConfig,
280 pub(crate) ifac_runtime: IfacRuntimeConfig,
281 pub(crate) ifac_enabled: bool,
282 pub(crate) interface_type_name: String,
283 pub(crate) source: BackbonePeerPoolCandidateSource,
284 pub(crate) priority: u8,
285 pub(crate) discovery: Option<BackbonePeerPoolDiscoveryCandidate>,
286}
287
288#[cfg(feature = "iface-backbone")]
289#[derive(Debug, Clone, Copy, PartialEq, Eq)]
290pub(crate) enum BackbonePeerPoolCandidateSource {
291 Configured,
292 Discovered,
293}
294
295#[cfg(feature = "iface-backbone")]
296impl BackbonePeerPoolCandidateSource {
297 fn as_str(self) -> &'static str {
298 match self {
299 Self::Configured => "configured",
300 Self::Discovered => "discovered",
301 }
302 }
303}
304
305#[cfg(feature = "iface-backbone")]
306#[derive(Debug, Clone)]
307pub(crate) struct BackbonePeerPoolDiscoveryCandidate {
308 pub(crate) discovery_hash: [u8; 32],
309 pub(crate) status: crate::discovery::DiscoveredStatus,
310 pub(crate) hops: u8,
311 pub(crate) stamp_value: u32,
312 pub(crate) last_heard: f64,
313}
314
315#[cfg(feature = "iface-backbone")]
316struct BackbonePeerPool {
317 settings: BackbonePeerPoolSettings,
318 candidates: Vec<BackbonePeerPoolCandidate>,
319}
320
321#[cfg(feature = "iface-backbone")]
322struct BackbonePeerPoolCandidate {
323 config: BackbonePeerPoolCandidateConfig,
324 active_id: Option<InterfaceId>,
325 failures: Vec<f64>,
326 retry_after: Option<f64>,
327 cooldown_until: Option<f64>,
328 last_error: Option<String>,
329}
330
331#[cfg(feature = "hooks")]
333struct EngineRef<'a> {
334 engine: &'a TransportEngine,
335 interfaces: &'a HashMap<InterfaceId, InterfaceEntry>,
336 link_manager: &'a LinkManager,
337 now: f64,
338}
339
340#[cfg(feature = "hooks")]
341impl<'a> EngineAccess for EngineRef<'a> {
342 fn has_path(&self, dest: &[u8; 16]) -> bool {
343 self.engine.has_path(dest)
344 }
345 fn hops_to(&self, dest: &[u8; 16]) -> Option<u8> {
346 self.engine.hops_to(dest)
347 }
348 fn next_hop(&self, dest: &[u8; 16]) -> Option<[u8; 16]> {
349 self.engine.next_hop(dest)
350 }
351 fn is_blackholed(&self, identity: &[u8; 16]) -> bool {
352 self.engine.is_blackholed(identity, self.now)
353 }
354 fn interface_name(&self, id: u64) -> Option<String> {
355 self.interfaces
356 .get(&InterfaceId(id))
357 .map(|e| e.info.name.clone())
358 }
359 fn interface_mode(&self, id: u64) -> Option<u8> {
360 self.interfaces.get(&InterfaceId(id)).map(|e| e.info.mode)
361 }
362 fn identity_hash(&self) -> Option<[u8; 16]> {
363 self.engine.identity_hash().copied()
364 }
365 fn announce_rate(&self, id: u64) -> Option<i32> {
366 self.interfaces
367 .get(&InterfaceId(id))
368 .map(|e| (e.stats.outgoing_announce_freq() * 1000.0) as i32)
369 }
370 fn link_state(&self, link_hash: &[u8; 16]) -> Option<u8> {
371 use rns_core::link::types::LinkState;
372 self.link_manager.link_state(link_hash).map(|s| match s {
373 LinkState::Pending => 0,
374 LinkState::Handshake => 1,
375 LinkState::Active => 2,
376 LinkState::Stale => 3,
377 LinkState::Closed => 4,
378 })
379 }
380}
381
382#[cfg(any(test, feature = "hooks"))]
387fn extract_dest_hash(raw: &[u8]) -> [u8; 16] {
388 let mut dest = [0u8; 16];
389 if raw.is_empty() {
390 return dest;
391 }
392 let is_header2 = raw[0] & 0x40 != 0;
393 let start = if is_header2 { 18 } else { 2 };
394 let end = start + 16;
395 if raw.len() >= end {
396 dest.copy_from_slice(&raw[start..end]);
397 }
398 dest
399}
400
401#[cfg(feature = "hooks")]
403fn run_hook_inner(
404 programs: &mut [rns_hooks::LoadedProgram],
405 hook_manager: &Option<HookManager>,
406 engine_access: &dyn EngineAccess,
407 ctx: &HookContext,
408 now: f64,
409 provider_events_enabled: bool,
410) -> Option<rns_hooks::ExecuteResult> {
411 if programs.is_empty() {
412 return None;
413 }
414 let mgr = hook_manager.as_ref()?;
415 mgr.run_chain_with_provider_events(programs, ctx, engine_access, now, provider_events_enabled)
416}
417
418#[cfg(feature = "hooks")]
419fn backbone_peer_hook_context(event: &BackbonePeerHookEvent) -> HookContext<'_> {
420 HookContext::BackbonePeer {
421 server_interface_id: event.server_interface_id.0,
422 peer_interface_id: event.peer_interface_id.map(|id| id.0),
423 peer_ip: event.peer_ip,
424 peer_port: event.peer_port,
425 connected_for: event.connected_for,
426 had_received_data: event.had_received_data,
427 penalty_level: event.penalty_level,
428 blacklist_for: event.blacklist_for,
429 }
430}
431
432#[cfg(feature = "hooks")]
434fn convert_injected_actions(actions: Vec<rns_hooks::ActionWire>) -> Vec<TransportAction> {
435 actions
436 .into_iter()
437 .map(|a| {
438 use rns_hooks::ActionWire;
439 match a {
440 ActionWire::SendOnInterface { interface, raw } => {
441 TransportAction::SendOnInterface {
442 interface: InterfaceId(interface),
443 raw: raw.into(),
444 }
445 }
446 ActionWire::BroadcastOnAllInterfaces {
447 raw,
448 exclude,
449 has_exclude,
450 } => TransportAction::BroadcastOnAllInterfaces {
451 raw: raw.into(),
452 exclude: if has_exclude != 0 {
453 Some(InterfaceId(exclude))
454 } else {
455 None
456 },
457 },
458 ActionWire::DeliverLocal {
459 destination_hash,
460 raw,
461 packet_hash,
462 receiving_interface,
463 } => TransportAction::DeliverLocal {
464 destination_hash,
465 raw: raw.into(),
466 packet_hash,
467 receiving_interface: InterfaceId(receiving_interface),
468 },
469 ActionWire::PathUpdated {
470 destination_hash,
471 hops,
472 next_hop,
473 interface,
474 } => TransportAction::PathUpdated {
475 destination_hash,
476 hops,
477 next_hop,
478 interface: InterfaceId(interface),
479 },
480 ActionWire::CacheAnnounce { packet_hash, raw } => TransportAction::CacheAnnounce {
481 packet_hash,
482 raw: raw.into(),
483 },
484 ActionWire::TunnelEstablished {
485 tunnel_id,
486 interface,
487 } => TransportAction::TunnelEstablished {
488 tunnel_id,
489 interface: InterfaceId(interface),
490 },
491 ActionWire::TunnelSynthesize {
492 interface,
493 data,
494 dest_hash,
495 } => TransportAction::TunnelSynthesize {
496 interface: InterfaceId(interface),
497 data,
498 dest_hash,
499 },
500 ActionWire::ForwardToLocalClients {
501 raw,
502 exclude,
503 has_exclude,
504 } => TransportAction::ForwardToLocalClients {
505 raw: raw.into(),
506 exclude: if has_exclude != 0 {
507 Some(InterfaceId(exclude))
508 } else {
509 None
510 },
511 },
512 ActionWire::ForwardPlainBroadcast {
513 raw,
514 to_local,
515 exclude,
516 has_exclude,
517 } => TransportAction::ForwardPlainBroadcast {
518 raw: raw.into(),
519 to_local: to_local != 0,
520 exclude: if has_exclude != 0 {
521 Some(InterfaceId(exclude))
522 } else {
523 None
524 },
525 },
526 ActionWire::AnnounceReceived {
527 destination_hash,
528 identity_hash,
529 public_key,
530 name_hash,
531 random_hash,
532 app_data,
533 hops,
534 receiving_interface,
535 } => TransportAction::AnnounceReceived {
536 destination_hash,
537 identity_hash,
538 public_key,
539 name_hash,
540 random_hash,
541 ratchet: None,
542 app_data,
543 hops,
544 receiving_interface: InterfaceId(receiving_interface),
545 rx: rns_core::transport::RxMetadata::default(),
546 },
547 }
548 })
549 .collect()
550}
551
552fn infer_interface_type(name: &str) -> String {
556 if name.starts_with("TCPServerInterface") {
557 "TCPServerClientInterface".to_string()
558 } else if name.starts_with("BackboneInterface") {
559 "BackboneInterface".to_string()
560 } else if name.starts_with("LocalInterface") {
561 "LocalServerClientInterface".to_string()
562 } else if name.starts_with("WeaveInterfacePeer[") {
563 "WeaveInterfacePeer".to_string()
564 } else {
565 "AutoInterface".to_string()
568 }
569}
570
571pub use crate::common::callbacks::Callbacks;
572
573#[derive(Clone)]
574struct SharedAnnounceRecord {
575 name_hash: [u8; 10],
576 identity_prv_key: [u8; 64],
577 app_data: Option<Vec<u8>>,
578}
579
580#[derive(Debug, Clone)]
581pub(crate) struct KnownDestinationState {
582 announced: crate::destination::AnnouncedIdentity,
583 was_used: bool,
584 last_used_at: Option<f64>,
585 retained: bool,
586}
587
588struct KnownDestinationCleanup {
589 candidates: Vec<[u8; 16]>,
590 cursor: usize,
591 started_at: Instant,
592 removed: usize,
593}
594
595pub struct Driver {
597 pub(crate) engine: TransportEngine,
598 pub(crate) interfaces: HashMap<InterfaceId, InterfaceEntry>,
599 pub(crate) rng: OsRng,
600 pub(crate) rx: EventReceiver,
601 pub(crate) callbacks: Box<dyn Callbacks>,
602 pub(crate) started: f64,
603 pub(crate) lifecycle_state: LifecycleState,
604 pub(crate) drain_started_at: Option<Instant>,
605 pub(crate) drain_deadline: Option<Instant>,
606 pub(crate) listener_controls: Vec<crate::interface::ListenerControl>,
607 pub(crate) announce_cache: Option<crate::announce_cache::AnnounceCache>,
608 pub(crate) tunnel_synth_dest: [u8; 16],
610 pub(crate) transport_identity: Option<rns_crypto::identity::Identity>,
612 pub(crate) link_manager: LinkManager,
614 pub(crate) management_config: crate::management::ManagementConfig,
616 pub(crate) last_management_announce: f64,
618 pub(crate) initial_announce_sent: bool,
620 pub(crate) known_destinations: HashMap<[u8; 16], KnownDestinationState>,
622 pub(crate) ratchet_store: Option<Arc<dyn crate::storage::RatchetStore>>,
624 pub(crate) ratchet_expiry_secs: f64,
626 pub(crate) known_destinations_ttl: f64,
628 pub(crate) known_destinations_max_entries: usize,
630 pub(crate) rate_limiter_ttl_secs: f64,
632 pub(crate) path_request_dest: [u8; 16],
634 pub(crate) proof_strategies: HashMap<
637 [u8; 16],
638 (
639 rns_core::types::ProofStrategy,
640 Option<rns_crypto::identity::Identity>,
641 ),
642 >,
643 pub(crate) sent_packets: HashMap<[u8; 32], ([u8; 16], f64)>,
645 pub(crate) completed_proofs: HashMap<[u8; 32], (f64, f64)>,
647 pub(crate) local_destinations: HashMap<[u8; 16], u8>,
649 shared_announces: HashMap<[u8; 16], SharedAnnounceRecord>,
651 shared_reconnect_pending: HashMap<InterfaceId, bool>,
653 pub(crate) holepunch_manager: HolePunchManager,
655 pub(crate) event_tx: crate::event::EventSender,
657 pub(crate) interface_writer_queue_capacity: usize,
659 pub(crate) announce_rate_defaults: AnnounceRateDefaults,
661 pub(crate) ingress_control_defaults: rns_core::transport::types::IngressControlConfig,
663 pub(crate) tick_interval_ms: Arc<AtomicU64>,
665 #[cfg(feature = "iface-backbone")]
667 pub(crate) backbone_runtime: HashMap<String, BackboneRuntimeConfigHandle>,
668 #[cfg(feature = "iface-backbone")]
670 pub(crate) backbone_peer_state: HashMap<String, BackbonePeerStateHandle>,
671 #[cfg(feature = "iface-backbone")]
673 pub(crate) backbone_client_runtime: HashMap<String, BackboneClientRuntimeConfigHandle>,
674 #[cfg(feature = "iface-backbone")]
676 pub(crate) backbone_discovery_runtime: HashMap<String, BackboneDiscoveryRuntimeHandle>,
677 #[cfg(feature = "iface-backbone")]
679 backbone_peer_pool: Option<BackbonePeerPool>,
680 #[cfg(feature = "iface-backbone")]
682 pub(crate) next_dynamic_interface_id: Arc<AtomicU64>,
683 #[cfg(feature = "iface-tcp")]
685 pub(crate) tcp_server_runtime: HashMap<String, TcpServerRuntimeConfigHandle>,
686 #[cfg(feature = "iface-tcp")]
688 pub(crate) tcp_client_runtime: HashMap<String, TcpClientRuntimeConfigHandle>,
689 #[cfg(feature = "iface-tcp")]
691 pub(crate) tcp_server_discovery_runtime: HashMap<String, TcpServerDiscoveryRuntimeHandle>,
692 #[cfg(feature = "iface-udp")]
694 pub(crate) udp_runtime: HashMap<String, UdpRuntimeConfigHandle>,
695 #[cfg(feature = "iface-auto")]
697 pub(crate) auto_runtime: HashMap<String, AutoRuntimeConfigHandle>,
698 #[cfg(feature = "iface-i2p")]
700 pub(crate) i2p_runtime: HashMap<String, I2pRuntimeConfigHandle>,
701 #[cfg(feature = "iface-pipe")]
703 pub(crate) pipe_runtime: HashMap<String, PipeRuntimeConfigHandle>,
704 #[cfg(feature = "iface-rnode")]
706 pub(crate) rnode_runtime: HashMap<String, RNodeRuntimeConfigHandle>,
707 pub(crate) interface_runtime_defaults:
709 HashMap<String, rns_core::transport::types::InterfaceInfo>,
710 pub(crate) interface_ifac_runtime: HashMap<String, IfacRuntimeConfig>,
712 pub(crate) interface_ifac_runtime_defaults: HashMap<String, IfacRuntimeConfig>,
714 pub(crate) discovered_interfaces: crate::discovery::DiscoveredInterfaceStorage,
716 pub(crate) discovery_required_value: u8,
718 pub(crate) discovery_stamp_cache: crate::discovery::DiscoveryStampCache,
720 pub(crate) discovery_name_hash: [u8; 10],
722 pub(crate) probe_responder_hash: Option<[u8; 16]>,
724 pub(crate) discover_interfaces: bool,
726 pub(crate) autoconnect_interface_mode: Option<u8>,
728 pub(crate) autoconnect_interface_gravity: i64,
730 pub(crate) autoconnect_announces_to_internal: Option<bool>,
732 pub(crate) interface_announcer: Option<crate::discovery::InterfaceAnnouncer>,
734 pub(crate) announce_verify_queue: Arc<Mutex<AnnounceVerifyQueue>>,
736 pub(crate) async_announce_verification: bool,
738 pub(crate) discovery_cleanup_counter: u32,
740 pub(crate) discovery_cleanup_interval_ticks: u32,
742 pub(crate) memory_stats_counter: u32,
744 pub(crate) cache_cleanup_counter: u32,
746 pub(crate) announce_cache_cleanup_counter: u32,
748 pub(crate) known_destinations_cleanup_interval_ticks: u32,
750 known_destination_cleanup: Option<KnownDestinationCleanup>,
752 ratchet_cleanup_handle: Option<std::thread::JoinHandle<()>>,
754 pub(crate) known_destinations_cap_evict_count: usize,
756 pub(crate) announce_cache_cleanup_interval_ticks: u32,
758 pub(crate) cache_cleanup_active_hashes: Option<Vec<[u8; 32]>>,
760 pub(crate) cache_cleanup_entries: Option<std::fs::ReadDir>,
762 pub(crate) cache_cleanup_removed: usize,
764 pub(crate) announce_cache_cleanup_batch_size: usize,
766 pub(crate) management_announce_interval_secs: f64,
768 pub(crate) runtime_config_defaults: RuntimeConfigDefaults,
770 #[cfg(feature = "hooks")]
772 pub(crate) hook_slots: [HookSlot; HookPoint::COUNT],
773 #[cfg(feature = "hooks")]
775 pub(crate) hook_manager: Option<HookManager>,
776 #[cfg(feature = "hooks")]
777 pub(crate) provider_bridge: Option<ProviderBridge>,
778}
779
780impl Driver {
781 pub fn new(
783 config: TransportConfig,
784 rx: EventReceiver,
785 tx: crate::event::EventSender,
786 callbacks: Box<dyn Callbacks>,
787 ) -> Self {
788 let announce_queue_max_entries = config.announce_queue_max_entries;
789 let tunnel_synth_dest = rns_core::destination::destination_hash(
790 "rnstransport",
791 &["tunnel", "synthesize"],
792 None,
793 );
794 let path_request_dest =
795 rns_core::destination::destination_hash("rnstransport", &["path", "request"], None);
796 let discovery_name_hash = crate::discovery::discovery_name_hash();
797 let mut engine = TransportEngine::new(config);
798 engine.register_destination(tunnel_synth_dest, rns_core::constants::DESTINATION_PLAIN);
799 engine.register_destination(path_request_dest, rns_core::constants::DESTINATION_PLAIN);
801 let mut local_destinations = HashMap::new();
804 local_destinations.insert(tunnel_synth_dest, rns_core::constants::DESTINATION_PLAIN);
805 local_destinations.insert(path_request_dest, rns_core::constants::DESTINATION_PLAIN);
806 let runtime_config_defaults = RuntimeConfigDefaults {
807 tick_interval_ms: DEFAULT_TICK_INTERVAL_MS,
808 known_destinations_ttl: DEFAULT_KNOWN_DESTINATIONS_TTL,
809 rate_limiter_ttl_secs: DEFAULT_RATE_LIMITER_TTL_SECS,
810 known_destinations_cleanup_interval_ticks:
811 DEFAULT_KNOWN_DESTINATIONS_CLEANUP_INTERVAL_TICKS,
812 announce_cache_cleanup_interval_ticks: DEFAULT_ANNOUNCE_CACHE_CLEANUP_INTERVAL_TICKS,
813 announce_cache_cleanup_batch_size: DEFAULT_ANNOUNCE_CACHE_CLEANUP_BATCH_SIZE,
814 discovery_cleanup_interval_ticks: DEFAULT_DISCOVERY_CLEANUP_INTERVAL_TICKS,
815 management_announce_interval_secs: DEFAULT_MANAGEMENT_ANNOUNCE_INTERVAL_SECS,
816 direct_connect_policy: crate::event::HolePunchPolicy::default(),
817 #[cfg(feature = "hooks")]
818 provider_queue_max_events: crate::provider_bridge::ProviderBridgeConfig::default()
819 .queue_max_events,
820 #[cfg(feature = "hooks")]
821 provider_queue_max_bytes: crate::provider_bridge::ProviderBridgeConfig::default()
822 .queue_max_bytes,
823 };
824 Driver {
825 engine,
826 interfaces: HashMap::new(),
827 rng: OsRng,
828 rx,
829 callbacks,
830 started: time::now(),
831 lifecycle_state: LifecycleState::Active,
832 drain_started_at: None,
833 drain_deadline: None,
834 listener_controls: Vec::new(),
835 announce_cache: None,
836 tunnel_synth_dest,
837 transport_identity: None,
838 link_manager: LinkManager::new(),
839 management_config: Default::default(),
840 last_management_announce: 0.0,
841 initial_announce_sent: false,
842 known_destinations: HashMap::new(),
843 ratchet_store: None,
844 ratchet_expiry_secs: rns_core::constants::RATCHET_EXPIRY as f64,
845 known_destinations_ttl: DEFAULT_KNOWN_DESTINATIONS_TTL,
846 known_destinations_max_entries: DEFAULT_KNOWN_DESTINATIONS_MAX_ENTRIES,
847 rate_limiter_ttl_secs: DEFAULT_RATE_LIMITER_TTL_SECS,
848 path_request_dest,
849 proof_strategies: HashMap::new(),
850 sent_packets: HashMap::new(),
851 completed_proofs: HashMap::new(),
852 local_destinations,
853 shared_announces: HashMap::new(),
854 shared_reconnect_pending: HashMap::new(),
855 holepunch_manager: HolePunchManager::new(
856 vec![],
857 rns_core::holepunch::ProbeProtocol::Rnsp,
858 None,
859 ),
860 event_tx: tx,
861 interface_writer_queue_capacity: crate::interface::DEFAULT_ASYNC_WRITER_QUEUE_CAPACITY,
862 announce_rate_defaults: AnnounceRateDefaults::default(),
863 ingress_control_defaults: rns_core::transport::types::IngressControlConfig::enabled(),
864 tick_interval_ms: Arc::new(AtomicU64::new(DEFAULT_TICK_INTERVAL_MS)),
865 #[cfg(feature = "iface-backbone")]
866 backbone_runtime: HashMap::new(),
867 #[cfg(feature = "iface-backbone")]
868 backbone_peer_state: HashMap::new(),
869 #[cfg(feature = "iface-backbone")]
870 backbone_client_runtime: HashMap::new(),
871 #[cfg(feature = "iface-backbone")]
872 backbone_discovery_runtime: HashMap::new(),
873 #[cfg(feature = "iface-backbone")]
874 backbone_peer_pool: None,
875 #[cfg(feature = "iface-backbone")]
876 next_dynamic_interface_id: Arc::new(AtomicU64::new(10000)),
877 #[cfg(feature = "iface-tcp")]
878 tcp_server_runtime: HashMap::new(),
879 #[cfg(feature = "iface-tcp")]
880 tcp_client_runtime: HashMap::new(),
881 #[cfg(feature = "iface-tcp")]
882 tcp_server_discovery_runtime: HashMap::new(),
883 #[cfg(feature = "iface-udp")]
884 udp_runtime: HashMap::new(),
885 #[cfg(feature = "iface-auto")]
886 auto_runtime: HashMap::new(),
887 #[cfg(feature = "iface-i2p")]
888 i2p_runtime: HashMap::new(),
889 #[cfg(feature = "iface-pipe")]
890 pipe_runtime: HashMap::new(),
891 #[cfg(feature = "iface-rnode")]
892 rnode_runtime: HashMap::new(),
893 interface_runtime_defaults: HashMap::new(),
894 interface_ifac_runtime: HashMap::new(),
895 interface_ifac_runtime_defaults: HashMap::new(),
896 discovered_interfaces: crate::discovery::DiscoveredInterfaceStorage::new(
897 std::env::temp_dir().join("rns-discovered-interfaces"),
898 ),
899 discovery_required_value: crate::discovery::DEFAULT_STAMP_VALUE,
900 discovery_stamp_cache: crate::discovery::DiscoveryStampCache::default(),
901 discovery_name_hash,
902 probe_responder_hash: None,
903 discover_interfaces: false,
904 autoconnect_interface_mode: None,
905 autoconnect_interface_gravity: 0,
906 autoconnect_announces_to_internal: None,
907 interface_announcer: None,
908 announce_verify_queue: Arc::new(Mutex::new(AnnounceVerifyQueue::new(
909 announce_queue_max_entries,
910 ))),
911 async_announce_verification: false,
912 discovery_cleanup_counter: 0,
913 discovery_cleanup_interval_ticks: runtime_config_defaults
914 .discovery_cleanup_interval_ticks,
915 memory_stats_counter: 0,
916 cache_cleanup_counter: 0,
917 announce_cache_cleanup_counter: 0,
918 known_destinations_cleanup_interval_ticks: runtime_config_defaults
919 .known_destinations_cleanup_interval_ticks,
920 known_destination_cleanup: None,
921 ratchet_cleanup_handle: None,
922 known_destinations_cap_evict_count: 0,
923 announce_cache_cleanup_interval_ticks: runtime_config_defaults
924 .announce_cache_cleanup_interval_ticks,
925 cache_cleanup_active_hashes: None,
926 cache_cleanup_entries: None,
927 cache_cleanup_removed: 0,
928 announce_cache_cleanup_batch_size: runtime_config_defaults
929 .announce_cache_cleanup_batch_size,
930 management_announce_interval_secs: runtime_config_defaults
931 .management_announce_interval_secs,
932 runtime_config_defaults,
933 #[cfg(feature = "hooks")]
934 hook_slots: create_hook_slots(),
935 #[cfg(feature = "hooks")]
936 hook_manager: HookManager::new().ok(),
937 #[cfg(feature = "hooks")]
938 provider_bridge: None,
939 }
940 }
941
942 pub fn set_announce_verify_queue_config(
943 &mut self,
944 max_entries: usize,
945 max_bytes: usize,
946 max_stale_secs: f64,
947 overflow_policy: OverflowPolicy,
948 ) {
949 self.announce_verify_queue = Arc::new(Mutex::new(AnnounceVerifyQueue::with_limits(
950 max_entries,
951 max_bytes,
952 max_stale_secs,
953 overflow_policy,
954 )));
955 }
956
957 pub fn set_announce_rate_defaults(&mut self, defaults: AnnounceRateDefaults) {
958 self.announce_rate_defaults = defaults;
959 }
960
961 pub fn set_ingress_control_defaults(
962 &mut self,
963 defaults: rns_core::transport::types::IngressControlConfig,
964 ) {
965 self.ingress_control_defaults = defaults;
966 }
967
968 pub(crate) fn apply_announce_rate_defaults(
969 &self,
970 info: &mut rns_core::transport::types::InterfaceInfo,
971 ) {
972 if !self.engine.transport_enabled() || info.announce_rate_target.is_some() {
973 return;
974 }
975
976 let Some(target) = self.announce_rate_defaults.target else {
977 return;
978 };
979
980 info.announce_rate_target = Some(target);
981 if info.announce_rate_grace == 0 {
982 info.announce_rate_grace = self.announce_rate_defaults.grace;
983 }
984 if info.announce_rate_penalty == 0.0 {
985 info.announce_rate_penalty = self.announce_rate_defaults.penalty;
986 }
987 }
988
989 pub(crate) fn apply_ingress_control_defaults(
990 &self,
991 info: &mut rns_core::transport::types::InterfaceInfo,
992 ) {
993 if !self.engine.transport_enabled() {
994 return;
995 }
996
997 let baseline = if info.ingress_control.enabled {
998 rns_core::transport::types::IngressControlConfig::enabled()
999 } else {
1000 rns_core::transport::types::IngressControlConfig::disabled()
1001 };
1002 let defaults = self.ingress_control_defaults;
1003 let ic = &mut info.ingress_control;
1004
1005 if ic.max_held_announces == baseline.max_held_announces {
1006 ic.max_held_announces = defaults.max_held_announces;
1007 }
1008 if ic.burst_hold == baseline.burst_hold {
1009 ic.burst_hold = defaults.burst_hold;
1010 }
1011 if ic.burst_freq_new == baseline.burst_freq_new {
1012 ic.burst_freq_new = defaults.burst_freq_new;
1013 }
1014 if ic.burst_freq == baseline.burst_freq {
1015 ic.burst_freq = defaults.burst_freq;
1016 }
1017 if ic.pr_burst_freq_new == baseline.pr_burst_freq_new {
1018 ic.pr_burst_freq_new = defaults.pr_burst_freq_new;
1019 }
1020 if ic.pr_burst_freq == baseline.pr_burst_freq {
1021 ic.pr_burst_freq = defaults.pr_burst_freq;
1022 }
1023 if ic.new_time == baseline.new_time {
1024 ic.new_time = defaults.new_time;
1025 }
1026 if ic.burst_penalty == baseline.burst_penalty {
1027 ic.burst_penalty = defaults.burst_penalty;
1028 }
1029 if ic.held_release_interval == baseline.held_release_interval {
1030 ic.held_release_interval = defaults.held_release_interval;
1031 }
1032 if ic.egress_enabled == baseline.egress_enabled {
1033 ic.egress_enabled = defaults.egress_enabled;
1034 }
1035 if ic.egress_pr_freq == baseline.egress_pr_freq {
1036 ic.egress_pr_freq = defaults.egress_pr_freq;
1037 }
1038 }
1039
1040 fn wrap_interface_writer(
1041 &self,
1042 interface_id: InterfaceId,
1043 interface_name: &str,
1044 writer: Box<dyn crate::interface::Writer>,
1045 ) -> (
1046 Box<dyn crate::interface::Writer>,
1047 crate::interface::AsyncWriterMetrics,
1048 ) {
1049 crate::interface::wrap_async_writer(
1050 writer,
1051 interface_id,
1052 interface_name,
1053 self.event_tx.clone(),
1054 self.interface_writer_queue_capacity,
1055 )
1056 }
1057
1058 #[cfg(feature = "hooks")]
1059 fn provider_events_enabled(&self) -> bool {
1060 self.provider_bridge.is_some()
1061 }
1062
1063 #[cfg(feature = "hooks")]
1064 fn run_backbone_peer_hook(
1065 &mut self,
1066 attach_point: &str,
1067 point: HookPoint,
1068 event: &BackbonePeerHookEvent,
1069 ) {
1070 let ctx = backbone_peer_hook_context(event);
1071 let now = time::now();
1072 let engine_ref = EngineRef {
1073 engine: &self.engine,
1074 interfaces: &self.interfaces,
1075 link_manager: &self.link_manager,
1076 now,
1077 };
1078 let provider_events_enabled = self.provider_events_enabled();
1079 if let Some(ref e) = run_hook_inner(
1080 &mut self.hook_slots[point as usize].programs,
1081 &self.hook_manager,
1082 &engine_ref,
1083 &ctx,
1084 now,
1085 provider_events_enabled,
1086 ) {
1087 self.forward_hook_side_effects(attach_point, e);
1088 }
1089 }
1090
1091 #[cfg(feature = "iface-backbone")]
1092 fn make_discoverable_interface(
1093 runtime: &BackboneDiscoveryRuntimeHandle,
1094 ) -> crate::discovery::DiscoverableInterface {
1095 crate::discovery::DiscoverableInterface {
1096 interface_name: runtime.interface_name.clone(),
1097 config: runtime.current.config.clone(),
1098 transport_enabled: runtime.current.transport_enabled,
1099 ifac_netname: runtime.current.ifac_netname.clone(),
1100 ifac_netkey: runtime.current.ifac_netkey.clone(),
1101 }
1102 }
1103
1104 #[cfg(feature = "iface-backbone")]
1105 fn sync_backbone_discovery_runtime(
1106 &mut self,
1107 interface_name: &str,
1108 ) -> Result<(), RuntimeConfigError> {
1109 let handle = self
1110 .backbone_discovery_runtime
1111 .get(interface_name)
1112 .ok_or(RuntimeConfigError {
1113 code: RuntimeConfigErrorCode::NotFound,
1114 message: format!("backbone interface '{}' not found", interface_name),
1115 })?
1116 .clone();
1117
1118 if handle.current.discoverable {
1119 let iface = Self::make_discoverable_interface(&handle);
1120 if let Some(announcer) = self.interface_announcer.as_mut() {
1121 announcer.upsert_interface(iface);
1122 } else if let Some(identity) = self.transport_identity.as_ref() {
1123 self.interface_announcer = Some(crate::discovery::InterfaceAnnouncer::new(
1124 *identity.hash(),
1125 vec![iface],
1126 ));
1127 }
1128 } else if let Some(announcer) = self.interface_announcer.as_mut() {
1129 announcer.remove_interface(interface_name);
1130 if announcer.is_empty() {
1131 self.interface_announcer = None;
1132 }
1133 }
1134
1135 Ok(())
1136 }
1137
1138 #[cfg(feature = "iface-tcp")]
1139 fn make_tcp_server_discoverable_interface(
1140 runtime: &TcpServerDiscoveryRuntimeHandle,
1141 ) -> crate::discovery::DiscoverableInterface {
1142 crate::discovery::DiscoverableInterface {
1143 interface_name: runtime.interface_name.clone(),
1144 config: runtime.current.config.clone(),
1145 transport_enabled: runtime.current.transport_enabled,
1146 ifac_netname: runtime.current.ifac_netname.clone(),
1147 ifac_netkey: runtime.current.ifac_netkey.clone(),
1148 }
1149 }
1150
1151 #[cfg(feature = "iface-tcp")]
1152 fn sync_tcp_server_discovery_runtime(
1153 &mut self,
1154 interface_name: &str,
1155 ) -> Result<(), RuntimeConfigError> {
1156 let handle = self
1157 .tcp_server_discovery_runtime
1158 .get(interface_name)
1159 .ok_or(RuntimeConfigError {
1160 code: RuntimeConfigErrorCode::NotFound,
1161 message: format!("tcp server interface '{}' not found", interface_name),
1162 })?
1163 .clone();
1164
1165 if handle.current.discoverable {
1166 let iface = Self::make_tcp_server_discoverable_interface(&handle);
1167 if let Some(announcer) = self.interface_announcer.as_mut() {
1168 announcer.upsert_interface(iface);
1169 } else if let Some(identity) = self.transport_identity.as_ref() {
1170 self.interface_announcer = Some(crate::discovery::InterfaceAnnouncer::new(
1171 *identity.hash(),
1172 vec![iface],
1173 ));
1174 }
1175 } else if let Some(announcer) = self.interface_announcer.as_mut() {
1176 announcer.remove_interface(interface_name);
1177 if announcer.is_empty() {
1178 self.interface_announcer = None;
1179 }
1180 }
1181
1182 Ok(())
1183 }
1184
1185 #[cfg(feature = "hooks")]
1186 fn update_hook_program<F>(
1187 &mut self,
1188 name: &str,
1189 attach_point: &str,
1190 mut update: F,
1191 ) -> Result<(), String>
1192 where
1193 F: FnMut(&mut rns_hooks::LoadedProgram),
1194 {
1195 let point_idx = crate::config::parse_hook_point(attach_point)
1196 .ok_or_else(|| format!("unknown hook point '{}'", attach_point))?;
1197 let program = self.hook_slots[point_idx]
1198 .programs
1199 .iter_mut()
1200 .find(|program| program.name == name)
1201 .ok_or_else(|| format!("hook '{}' not found at point '{}'", name, attach_point))?;
1202 update(program);
1203 Ok(())
1204 }
1205
1206 pub(crate) fn set_tick_interval_handle(&mut self, tick_interval_ms: Arc<AtomicU64>) {
1207 self.tick_interval_ms = tick_interval_ms;
1208 }
1209
1210 #[allow(dead_code)]
1211 pub(crate) fn set_packet_hashlist_max_entries(&mut self, max_entries: usize) {
1212 self.engine.set_packet_hashlist_max_entries(max_entries);
1213 }
1214
1215 #[cfg(feature = "hooks")]
1216 fn forward_hook_side_effects(&mut self, attach_point: &str, exec: &rns_hooks::ExecuteResult) {
1217 if !exec.injected_actions.is_empty() {
1218 self.dispatch_all(convert_injected_actions(exec.injected_actions.clone()));
1219 }
1220 if let Some(ref bridge) = self.provider_bridge {
1221 for event in &exec.provider_events {
1222 bridge.emit_event(
1223 attach_point,
1224 event.hook_name.clone(),
1225 event.payload_type.clone(),
1226 event.payload.clone(),
1227 );
1228 }
1229 }
1230 }
1231
1232 #[cfg(feature = "hooks")]
1233 fn collect_hook_side_effects(
1234 &mut self,
1235 attach_point: &str,
1236 exec: &rns_hooks::ExecuteResult,
1237 out: &mut Vec<TransportAction>,
1238 ) {
1239 if !exec.injected_actions.is_empty() {
1240 out.extend(convert_injected_actions(exec.injected_actions.clone()));
1241 }
1242 if let Some(ref bridge) = self.provider_bridge {
1243 for event in &exec.provider_events {
1244 bridge.emit_event(
1245 attach_point,
1246 event.hook_name.clone(),
1247 event.payload_type.clone(),
1248 event.payload.clone(),
1249 );
1250 }
1251 }
1252 }
1253
1254 pub fn set_probe_config(
1256 &mut self,
1257 addrs: Vec<std::net::SocketAddr>,
1258 protocol: rns_core::holepunch::ProbeProtocol,
1259 device: Option<String>,
1260 ) {
1261 self.holepunch_manager = HolePunchManager::new(addrs, protocol, device);
1262 }
1263}