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