1use std::io;
6use std::path::Path;
7use std::sync::atomic::{AtomicU64, Ordering};
8use std::sync::Arc;
9use std::thread::{self, JoinHandle};
10use std::time::Duration;
11
12use rns_core::transport::types::{InterfaceInfo, TransportConfig};
13use rns_crypto::identity::Identity;
14use rns_crypto::{OsRng, Rng};
15
16use crate::config;
17use crate::driver::{Callbacks, Driver};
18use crate::event::{self, Event, EventSender};
19use crate::ifac;
20use crate::interface::tcp::TcpClientConfig;
21use crate::interface::tcp_server::TcpServerConfig;
22use crate::interface::udp::UdpConfig;
23use crate::interface::local::{LocalServerConfig, LocalClientConfig};
24use crate::interface::serial_iface::SerialIfaceConfig;
25use crate::interface::kiss_iface::KissIfaceConfig;
26use crate::interface::pipe::PipeConfig;
27use crate::interface::rnode::{RNodeConfig, RNodeSubConfig};
28use crate::interface::backbone::{BackboneConfig, BackboneClientConfig};
29use crate::interface::auto::AutoConfig;
30use crate::interface::i2p::I2pConfig;
31use crate::interface::{InterfaceEntry, InterfaceStats};
32use crate::time;
33use crate::serial::Parity;
34use crate::storage;
35
36fn parse_interface_mode(mode: &str) -> u8 {
39 match mode.to_lowercase().as_str() {
40 "full" => rns_core::constants::MODE_FULL,
41 "access_point" | "accesspoint" | "ap" => rns_core::constants::MODE_ACCESS_POINT,
42 "pointtopoint" | "ptp" => rns_core::constants::MODE_POINT_TO_POINT,
43 "roaming" => rns_core::constants::MODE_ROAMING,
44 "boundary" => rns_core::constants::MODE_BOUNDARY,
45 "gateway" | "gw" => rns_core::constants::MODE_GATEWAY,
46 _ => rns_core::constants::MODE_FULL,
47 }
48}
49
50fn parse_parity(s: &str) -> Parity {
52 match s.to_lowercase().as_str() {
53 "e" | "even" => Parity::Even,
54 "o" | "odd" => Parity::Odd,
55 _ => Parity::None,
56 }
57}
58
59fn extract_ifac_config(params: &std::collections::HashMap<String, String>, default_size: usize) -> Option<IfacConfig> {
62 let netname = params.get("networkname")
63 .or_else(|| params.get("network_name"))
64 .cloned();
65 let netkey = params.get("passphrase")
66 .or_else(|| params.get("pass_phrase"))
67 .cloned();
68
69 if netname.is_none() && netkey.is_none() {
70 return None;
71 }
72
73 let size = params.get("ifac_size")
75 .and_then(|v| v.parse::<usize>().ok())
76 .map(|bits| (bits / 8).max(1))
77 .unwrap_or(default_size);
78
79 Some(IfacConfig { netname, netkey, size })
80}
81
82pub struct NodeConfig {
84 pub transport_enabled: bool,
85 pub identity: Option<Identity>,
86 pub interfaces: Vec<InterfaceConfig>,
87 pub share_instance: bool,
89 pub rpc_port: u16,
91 pub cache_dir: Option<std::path::PathBuf>,
93 pub management: crate::management::ManagementConfig,
95 pub probe_port: Option<u16>,
97 pub probe_addr: Option<std::net::SocketAddr>,
99 pub device: Option<String>,
101}
102
103pub struct InterfaceConfig {
105 pub variant: InterfaceVariant,
106 pub mode: u8,
108 pub ifac: Option<IfacConfig>,
110}
111
112pub struct IfacConfig {
114 pub netname: Option<String>,
115 pub netkey: Option<String>,
116 pub size: usize,
117}
118
119pub enum InterfaceVariant {
121 TcpClient(TcpClientConfig),
122 TcpServer(TcpServerConfig),
123 Udp(UdpConfig),
124 LocalServer(LocalServerConfig),
125 LocalClient(LocalClientConfig),
126 Serial(SerialIfaceConfig),
127 Kiss(KissIfaceConfig),
128 Pipe(PipeConfig),
129 RNode(RNodeConfig),
130 Backbone(BackboneConfig),
131 BackboneClient(BackboneClientConfig),
132 Auto(AutoConfig),
133 I2p(I2pConfig),
134}
135
136use crate::event::{QueryRequest, QueryResponse};
137
138#[derive(Debug)]
140pub struct SendError;
141
142impl std::fmt::Display for SendError {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 write!(f, "driver shut down")
145 }
146}
147
148impl std::error::Error for SendError {}
149
150pub struct RnsNode {
152 tx: EventSender,
153 driver_handle: Option<JoinHandle<()>>,
154 rpc_server: Option<crate::rpc::RpcServer>,
155 tick_interval_ms: Arc<AtomicU64>,
156 #[allow(dead_code)]
157 probe_server: Option<crate::holepunch::probe::ProbeServerHandle>,
158}
159
160impl RnsNode {
161 pub fn from_config(
164 config_path: Option<&Path>,
165 callbacks: Box<dyn Callbacks>,
166 ) -> io::Result<Self> {
167 let config_dir = storage::resolve_config_dir(config_path);
168 let paths = storage::ensure_storage_dirs(&config_dir)?;
169
170 let config_file = config_dir.join("config");
172 let rns_config = if config_file.exists() {
173 config::parse_file(&config_file).map_err(|e| {
174 io::Error::new(io::ErrorKind::InvalidData, format!("{}", e))
175 })?
176 } else {
177 config::parse("").map_err(|e| {
179 io::Error::new(io::ErrorKind::InvalidData, format!("{}", e))
180 })?
181 };
182
183 let identity = if let Some(ref id_path_str) = rns_config.reticulum.network_identity {
185 let id_path = std::path::PathBuf::from(id_path_str);
186 if id_path.exists() {
187 storage::load_identity(&id_path)?
188 } else {
189 let id = Identity::new(&mut OsRng);
190 storage::save_identity(&id, &id_path)?;
191 id
192 }
193 } else {
194 storage::load_or_create_identity(&paths.identities)?
195 };
196
197 let mut interface_configs = Vec::new();
199 let mut next_id_val = 1u64;
200
201 for iface in &rns_config.interfaces {
202 if !iface.enabled {
203 continue;
204 }
205
206 let iface_id = rns_core::transport::types::InterfaceId(next_id_val);
207 next_id_val += 1;
208
209 let mut iface_mode = parse_interface_mode(&iface.mode);
210
211 let has_discovery = match iface.interface_type.as_str() {
214 "AutoInterface" => true,
215 "RNodeInterface" => iface.params.get("discoverable")
216 .and_then(|v| config::parse_bool_pub(v))
217 .unwrap_or(false),
218 _ => false,
219 };
220 if has_discovery
221 && iface_mode != rns_core::constants::MODE_ACCESS_POINT
222 && iface_mode != rns_core::constants::MODE_GATEWAY
223 {
224 let new_mode = if iface.interface_type == "RNodeInterface" {
225 rns_core::constants::MODE_ACCESS_POINT
226 } else {
227 rns_core::constants::MODE_GATEWAY
228 };
229 log::info!(
230 "Interface '{}' has discovery enabled, auto-configuring mode to {}",
231 iface.name,
232 if new_mode == rns_core::constants::MODE_ACCESS_POINT {
233 "ACCESS_POINT"
234 } else {
235 "GATEWAY"
236 }
237 );
238 iface_mode = new_mode;
239 }
240
241 let default_ifac_size = match iface.interface_type.as_str() {
244 "SerialInterface" | "KISSInterface" | "RNodeInterface" => 8,
245 _ => 16,
246 };
247 let ifac_config = extract_ifac_config(&iface.params, default_ifac_size);
248
249 match iface.interface_type.as_str() {
250 "TCPClientInterface" => {
251 let target_host = iface
252 .params
253 .get("target_host")
254 .cloned()
255 .unwrap_or_else(|| "127.0.0.1".into());
256 let target_port = iface
257 .params
258 .get("target_port")
259 .and_then(|v| v.parse().ok())
260 .unwrap_or(4242);
261
262 interface_configs.push(InterfaceConfig {
263 variant: InterfaceVariant::TcpClient(TcpClientConfig {
264 name: iface.name.clone(),
265 target_host,
266 target_port,
267 interface_id: iface_id,
268 device: rns_config.reticulum.device.clone(),
269 ..TcpClientConfig::default()
270 }),
271 mode: iface_mode,
272 ifac: ifac_config,
273 });
274 }
275 "TCPServerInterface" => {
276 let listen_ip = iface
277 .params
278 .get("listen_ip")
279 .cloned()
280 .unwrap_or_else(|| "0.0.0.0".into());
281 let listen_port = iface
282 .params
283 .get("listen_port")
284 .and_then(|v| v.parse().ok())
285 .unwrap_or(4242);
286
287 interface_configs.push(InterfaceConfig {
288 variant: InterfaceVariant::TcpServer(TcpServerConfig {
289 name: iface.name.clone(),
290 listen_ip,
291 listen_port,
292 interface_id: iface_id,
293 }),
294 mode: iface_mode,
295 ifac: ifac_config,
296 });
297 }
298 "UDPInterface" => {
299 let listen_ip = iface.params.get("listen_ip").cloned();
300 let listen_port = iface
301 .params
302 .get("listen_port")
303 .and_then(|v| v.parse().ok());
304 let forward_ip = iface.params.get("forward_ip").cloned();
305 let forward_port = iface
306 .params
307 .get("forward_port")
308 .and_then(|v| v.parse().ok());
309
310 let port = iface.params.get("port").and_then(|v| v.parse::<u16>().ok());
312 let listen_port = listen_port.or(port);
313 let forward_port = forward_port.or(port);
314
315 interface_configs.push(InterfaceConfig {
316 variant: InterfaceVariant::Udp(UdpConfig {
317 name: iface.name.clone(),
318 listen_ip,
319 listen_port,
320 forward_ip,
321 forward_port,
322 interface_id: iface_id,
323 }),
324 mode: iface_mode,
325 ifac: ifac_config,
326 });
327 }
328 "SerialInterface" => {
329 let port = match iface.params.get("port") {
330 Some(p) => p.clone(),
331 None => {
332 log::warn!("No port specified for SerialInterface '{}'", iface.name);
333 continue;
334 }
335 };
336 let speed = iface.params.get("speed")
337 .and_then(|v| v.parse().ok())
338 .unwrap_or(9600);
339 let databits = iface.params.get("databits")
340 .and_then(|v| v.parse().ok())
341 .unwrap_or(8);
342 let parity = iface.params.get("parity")
343 .map(|v| parse_parity(v))
344 .unwrap_or(Parity::None);
345 let stopbits = iface.params.get("stopbits")
346 .and_then(|v| v.parse().ok())
347 .unwrap_or(1);
348
349 interface_configs.push(InterfaceConfig {
350 variant: InterfaceVariant::Serial(SerialIfaceConfig {
351 name: iface.name.clone(),
352 port,
353 speed,
354 data_bits: databits,
355 parity,
356 stop_bits: stopbits,
357 interface_id: iface_id,
358 }),
359 mode: iface_mode,
360 ifac: ifac_config,
361 });
362 }
363 "KISSInterface" => {
364 let port = match iface.params.get("port") {
365 Some(p) => p.clone(),
366 None => {
367 log::warn!("No port specified for KISSInterface '{}'", iface.name);
368 continue;
369 }
370 };
371 let speed = iface.params.get("speed")
372 .and_then(|v| v.parse().ok())
373 .unwrap_or(9600);
374 let databits = iface.params.get("databits")
375 .and_then(|v| v.parse().ok())
376 .unwrap_or(8);
377 let parity = iface.params.get("parity")
378 .map(|v| parse_parity(v))
379 .unwrap_or(Parity::None);
380 let stopbits = iface.params.get("stopbits")
381 .and_then(|v| v.parse().ok())
382 .unwrap_or(1);
383 let preamble = iface.params.get("preamble")
384 .and_then(|v| v.parse().ok())
385 .unwrap_or(350);
386 let txtail = iface.params.get("txtail")
387 .and_then(|v| v.parse().ok())
388 .unwrap_or(20);
389 let persistence = iface.params.get("persistence")
390 .and_then(|v| v.parse().ok())
391 .unwrap_or(64);
392 let slottime = iface.params.get("slottime")
393 .and_then(|v| v.parse().ok())
394 .unwrap_or(20);
395 let flow_control = iface.params.get("flow_control")
396 .and_then(|v| config::parse_bool_pub(v))
397 .unwrap_or(false);
398 let beacon_interval = iface.params.get("id_interval")
399 .and_then(|v| v.parse().ok());
400 let beacon_data = iface.params.get("id_callsign")
401 .map(|v| v.as_bytes().to_vec());
402
403 interface_configs.push(InterfaceConfig {
404 variant: InterfaceVariant::Kiss(KissIfaceConfig {
405 name: iface.name.clone(),
406 port,
407 speed,
408 data_bits: databits,
409 parity,
410 stop_bits: stopbits,
411 preamble,
412 txtail,
413 persistence,
414 slottime,
415 flow_control,
416 beacon_interval,
417 beacon_data,
418 interface_id: iface_id,
419 }),
420 mode: iface_mode,
421 ifac: ifac_config,
422 });
423 }
424 "RNodeInterface" => {
425 let port = match iface.params.get("port") {
426 Some(p) => p.clone(),
427 None => {
428 log::warn!("No port specified for RNodeInterface '{}'", iface.name);
429 continue;
430 }
431 };
432 let speed = iface.params.get("speed")
433 .and_then(|v| v.parse().ok())
434 .unwrap_or(115200);
435 let frequency = iface.params.get("frequency")
436 .and_then(|v| v.parse().ok())
437 .unwrap_or(868_000_000);
438 let bandwidth = iface.params.get("bandwidth")
439 .and_then(|v| v.parse().ok())
440 .unwrap_or(125_000);
441 let txpower = iface.params.get("txpower")
442 .and_then(|v| v.parse().ok())
443 .unwrap_or(7);
444 let spreading_factor = iface.params.get("spreadingfactor")
445 .or_else(|| iface.params.get("spreading_factor"))
446 .and_then(|v| v.parse().ok())
447 .unwrap_or(8);
448 let coding_rate = iface.params.get("codingrate")
449 .or_else(|| iface.params.get("coding_rate"))
450 .and_then(|v| v.parse().ok())
451 .unwrap_or(5);
452 let flow_control = iface.params.get("flow_control")
453 .and_then(|v| config::parse_bool_pub(v))
454 .unwrap_or(false);
455 let st_alock = iface.params.get("st_alock")
456 .and_then(|v| v.parse().ok());
457 let lt_alock = iface.params.get("lt_alock")
458 .and_then(|v| v.parse().ok());
459 let id_interval = iface.params.get("id_interval")
460 .and_then(|v| v.parse().ok());
461 let id_callsign = iface.params.get("id_callsign")
462 .map(|v| v.as_bytes().to_vec());
463
464 let sub = RNodeSubConfig {
465 name: iface.name.clone(),
466 frequency,
467 bandwidth,
468 txpower,
469 spreading_factor,
470 coding_rate,
471 flow_control,
472 st_alock,
473 lt_alock,
474 };
475
476 interface_configs.push(InterfaceConfig {
477 variant: InterfaceVariant::RNode(RNodeConfig {
478 name: iface.name.clone(),
479 port,
480 speed,
481 subinterfaces: vec![sub],
482 id_interval,
483 id_callsign,
484 base_interface_id: iface_id,
485 }),
486 mode: iface_mode,
487 ifac: ifac_config,
488 });
489 }
490 "PipeInterface" => {
491 let command = match iface.params.get("command") {
492 Some(c) => c.clone(),
493 None => {
494 log::warn!("No command specified for PipeInterface '{}'", iface.name);
495 continue;
496 }
497 };
498 let respawn_delay = iface.params.get("respawn_delay")
499 .and_then(|v| v.parse::<u64>().ok())
500 .map(Duration::from_millis)
501 .unwrap_or(Duration::from_secs(5));
502
503 interface_configs.push(InterfaceConfig {
504 variant: InterfaceVariant::Pipe(PipeConfig {
505 name: iface.name.clone(),
506 command,
507 respawn_delay,
508 interface_id: iface_id,
509 }),
510 mode: iface_mode,
511 ifac: ifac_config,
512 });
513 }
514 "BackboneInterface" => {
515 if let Some(target_host) = iface.params.get("remote")
516 .or_else(|| iface.params.get("target_host"))
517 {
518 let target_host = target_host.clone();
520 let target_port = iface.params.get("target_port")
521 .or_else(|| iface.params.get("port"))
522 .and_then(|v| v.parse().ok())
523 .unwrap_or(4242);
524 let transport_identity = iface.params.get("transport_identity").cloned();
525
526 interface_configs.push(InterfaceConfig {
527 variant: InterfaceVariant::BackboneClient(BackboneClientConfig {
528 name: iface.name.clone(),
529 target_host,
530 target_port,
531 interface_id: iface_id,
532 transport_identity,
533 ..BackboneClientConfig::default()
534 }),
535 mode: iface_mode,
536 ifac: ifac_config,
537 });
538 } else {
539 let listen_ip = iface.params.get("listen_ip")
541 .or_else(|| iface.params.get("device"))
542 .cloned()
543 .unwrap_or_else(|| "0.0.0.0".into());
544 let listen_port = iface.params.get("listen_port")
545 .or_else(|| iface.params.get("port"))
546 .and_then(|v| v.parse().ok())
547 .unwrap_or(4242);
548
549 interface_configs.push(InterfaceConfig {
550 variant: InterfaceVariant::Backbone(BackboneConfig {
551 name: iface.name.clone(),
552 listen_ip,
553 listen_port,
554 interface_id: iface_id,
555 }),
556 mode: iface_mode,
557 ifac: ifac_config,
558 });
559 }
560 }
561 "AutoInterface" => {
562 let group_id = iface
563 .params
564 .get("group_id")
565 .map(|s| s.as_bytes().to_vec())
566 .unwrap_or_else(|| crate::interface::auto::DEFAULT_GROUP_ID.to_vec());
567
568 let discovery_scope = iface
569 .params
570 .get("discovery_scope")
571 .map(|s| match s.to_lowercase().as_str() {
572 "link" => crate::interface::auto::SCOPE_LINK.to_string(),
573 "admin" => crate::interface::auto::SCOPE_ADMIN.to_string(),
574 "site" => crate::interface::auto::SCOPE_SITE.to_string(),
575 "organisation" | "organization" => crate::interface::auto::SCOPE_ORGANISATION.to_string(),
576 "global" => crate::interface::auto::SCOPE_GLOBAL.to_string(),
577 other => other.to_string(),
578 })
579 .unwrap_or_else(|| crate::interface::auto::SCOPE_LINK.to_string());
580
581 let discovery_port = iface
582 .params
583 .get("discovery_port")
584 .and_then(|v| v.parse().ok())
585 .unwrap_or(crate::interface::auto::DEFAULT_DISCOVERY_PORT);
586
587 let data_port = iface
588 .params
589 .get("data_port")
590 .and_then(|v| v.parse().ok())
591 .unwrap_or(crate::interface::auto::DEFAULT_DATA_PORT);
592
593 let multicast_address_type = iface
594 .params
595 .get("multicast_address_type")
596 .map(|s| match s.to_lowercase().as_str() {
597 "permanent" => crate::interface::auto::MULTICAST_PERMANENT_ADDRESS_TYPE.to_string(),
598 "temporary" => crate::interface::auto::MULTICAST_TEMPORARY_ADDRESS_TYPE.to_string(),
599 other => other.to_string(),
600 })
601 .unwrap_or_else(|| crate::interface::auto::MULTICAST_TEMPORARY_ADDRESS_TYPE.to_string());
602
603 let configured_bitrate = iface
604 .params
605 .get("configured_bitrate")
606 .or_else(|| iface.params.get("bitrate"))
607 .and_then(|v| v.parse().ok())
608 .unwrap_or(crate::interface::auto::BITRATE_GUESS);
609
610 let allowed_interfaces = iface
612 .params
613 .get("devices")
614 .or_else(|| iface.params.get("allowed_interfaces"))
615 .map(|s| s.split(',').map(|d| d.trim().to_string()).filter(|d| !d.is_empty()).collect())
616 .unwrap_or_default();
617
618 let ignored_interfaces = iface
619 .params
620 .get("ignored_devices")
621 .or_else(|| iface.params.get("ignored_interfaces"))
622 .map(|s| s.split(',').map(|d| d.trim().to_string()).filter(|d| !d.is_empty()).collect())
623 .unwrap_or_default();
624
625 interface_configs.push(InterfaceConfig {
626 variant: InterfaceVariant::Auto(AutoConfig {
627 name: iface.name.clone(),
628 group_id,
629 discovery_scope,
630 discovery_port,
631 data_port,
632 multicast_address_type,
633 allowed_interfaces,
634 ignored_interfaces,
635 configured_bitrate,
636 interface_id: iface_id,
637 }),
638 mode: iface_mode,
639 ifac: ifac_config,
640 });
641 }
642 "I2PInterface" => {
643 let sam_host = iface
644 .params
645 .get("sam_host")
646 .cloned()
647 .unwrap_or_else(|| "127.0.0.1".into());
648 let sam_port = iface
649 .params
650 .get("sam_port")
651 .and_then(|v| v.parse().ok())
652 .unwrap_or(7656);
653 let connectable = iface
654 .params
655 .get("connectable")
656 .and_then(|v| config::parse_bool_pub(v))
657 .unwrap_or(false);
658 let peers: Vec<String> = iface
659 .params
660 .get("peers")
661 .map(|s| {
662 s.split(',')
663 .map(|p| p.trim().to_string())
664 .filter(|p| !p.is_empty())
665 .collect()
666 })
667 .unwrap_or_default();
668
669 interface_configs.push(InterfaceConfig {
670 variant: InterfaceVariant::I2p(I2pConfig {
671 name: iface.name.clone(),
672 interface_id: iface_id,
673 sam_host,
674 sam_port,
675 peers,
676 connectable,
677 storage_dir: paths.storage.clone(),
678 }),
679 mode: iface_mode,
680 ifac: ifac_config,
681 });
682 }
683 _ => {
684 log::warn!(
685 "Unsupported interface type '{}' for '{}'",
686 iface.interface_type,
687 iface.name
688 );
689 }
690 }
691 }
692
693 let mut mgmt_allowed = Vec::new();
695 for hex_hash in &rns_config.reticulum.remote_management_allowed {
696 if hex_hash.len() == 32 {
697 if let Ok(bytes) = (0..hex_hash.len())
698 .step_by(2)
699 .map(|i| u8::from_str_radix(&hex_hash[i..i+2], 16))
700 .collect::<Result<Vec<u8>, _>>()
701 {
702 if bytes.len() == 16 {
703 let mut h = [0u8; 16];
704 h.copy_from_slice(&bytes);
705 mgmt_allowed.push(h);
706 }
707 } else {
708 log::warn!("Invalid hex in remote_management_allowed: {}", hex_hash);
709 }
710 } else {
711 log::warn!(
712 "Invalid entry in remote_management_allowed (expected 32 hex chars, got {}): {}",
713 hex_hash.len(), hex_hash,
714 );
715 }
716 }
717
718 let probe_addr = rns_config.reticulum.probe_addr.as_ref().and_then(|s| {
720 s.parse::<std::net::SocketAddr>().map_err(|e| {
721 log::warn!("Invalid probe_addr '{}': {}", s, e);
722 e
723 }).ok()
724 });
725
726 let node_config = NodeConfig {
727 transport_enabled: rns_config.reticulum.enable_transport,
728 identity: Some(identity),
729 interfaces: interface_configs,
730 share_instance: rns_config.reticulum.share_instance,
731 rpc_port: rns_config.reticulum.instance_control_port,
732 cache_dir: Some(paths.cache),
733 management: crate::management::ManagementConfig {
734 enable_remote_management: rns_config.reticulum.enable_remote_management,
735 remote_management_allowed: mgmt_allowed,
736 publish_blackhole: rns_config.reticulum.publish_blackhole,
737 },
738 probe_port: rns_config.reticulum.probe_port,
739 probe_addr,
740 device: rns_config.reticulum.device.clone(),
741 };
742
743 Self::start(node_config, callbacks)
744 }
745
746 pub fn start(config: NodeConfig, callbacks: Box<dyn Callbacks>) -> io::Result<Self> {
748 let identity = config
749 .identity
750 .unwrap_or_else(|| Identity::new(&mut OsRng));
751
752 let transport_config = TransportConfig {
753 transport_enabled: config.transport_enabled,
754 identity_hash: Some(*identity.hash()),
755 };
756
757 let (tx, rx) = event::channel();
758 let mut driver = Driver::new(transport_config, rx, tx.clone(), callbacks);
759
760 if let Some(ref cache_dir) = config.cache_dir {
762 let announces_dir = cache_dir.join("announces");
763 let _ = std::fs::create_dir_all(&announces_dir);
764 driver.announce_cache = Some(crate::announce_cache::AnnounceCache::new(announces_dir));
765 }
766
767 if config.probe_addr.is_some() || config.device.is_some() {
769 driver.set_probe_config(config.probe_addr, config.device.clone());
770 }
771
772 let probe_server = if let Some(port) = config.probe_port {
774 let listen_addr: std::net::SocketAddr = ([0, 0, 0, 0], port).into();
775 match crate::holepunch::probe::start_probe_server(listen_addr) {
776 Ok(handle) => {
777 log::info!("Probe server started on 0.0.0.0:{}", port);
778 Some(handle)
779 }
780 Err(e) => {
781 log::error!("Failed to start probe server on port {}: {}", port, e);
782 None
783 }
784 }
785 } else {
786 None
787 };
788
789 driver.management_config = config.management.clone();
791
792 if let Some(prv_key) = identity.get_private_key() {
794 driver.transport_identity = Some(Identity::from_private_key(&prv_key));
795 }
796
797 let next_dynamic_id = Arc::new(AtomicU64::new(10000));
799
800 for iface_config in config.interfaces {
802 let iface_mode = iface_config.mode;
803 let ifac_cfg = iface_config.ifac;
804
805 let mut ifac_state = ifac_cfg.as_ref().and_then(|ic| {
807 if ic.netname.is_some() || ic.netkey.is_some() {
808 Some(ifac::derive_ifac(
809 ic.netname.as_deref(),
810 ic.netkey.as_deref(),
811 ic.size,
812 ))
813 } else {
814 None
815 }
816 });
817
818 match iface_config.variant {
819 InterfaceVariant::TcpClient(tcp_config) => {
820 let id = tcp_config.interface_id;
821 let name = tcp_config.name.clone();
822 let info = InterfaceInfo {
823 id,
824 name,
825 mode: iface_mode,
826 out_capable: true,
827 in_capable: true,
828 bitrate: None,
829 announce_rate_target: None,
830 announce_rate_grace: 0,
831 announce_rate_penalty: 0.0,
832 announce_cap: rns_core::constants::ANNOUNCE_CAP,
833 is_local_client: false,
834 wants_tunnel: false,
835 tunnel_id: None,
836 mtu: 65535,
837 ingress_control: true,
838 ia_freq: 0.0,
839 started: time::now(),
840 };
841
842 let writer =
843 crate::interface::tcp::start(tcp_config, tx.clone())?;
844
845 driver.engine.register_interface(info.clone());
846 driver.interfaces.insert(
847 id,
848 InterfaceEntry {
849 id,
850 info,
851 writer,
852 online: false,
853 dynamic: false,
854 ifac: ifac_state,
855 stats: InterfaceStats {
856 started: time::now(),
857 ..Default::default()
858 },
859 interface_type: "TCPClientInterface".to_string(),
860 },
861 );
862 }
863 InterfaceVariant::TcpServer(server_config) => {
864 crate::interface::tcp_server::start(
865 server_config,
866 tx.clone(),
867 next_dynamic_id.clone(),
868 )?;
869 }
872 InterfaceVariant::Udp(udp_config) => {
873 let id = udp_config.interface_id;
874 let name = udp_config.name.clone();
875 let out_capable = udp_config.forward_ip.is_some();
876 let in_capable = udp_config.listen_ip.is_some();
877
878 let writer = crate::interface::udp::start(udp_config, tx.clone())?;
879
880 let info = InterfaceInfo {
881 id,
882 name,
883 mode: iface_mode,
884 out_capable,
885 in_capable,
886 bitrate: Some(10_000_000), announce_rate_target: None,
888 announce_rate_grace: 0,
889 announce_rate_penalty: 0.0,
890 announce_cap: rns_core::constants::ANNOUNCE_CAP,
891 is_local_client: false,
892 wants_tunnel: false,
893 tunnel_id: None,
894 mtu: 1400,
895 ingress_control: true,
896 ia_freq: 0.0,
897 started: time::now(),
898 };
899
900 driver.engine.register_interface(info.clone());
901
902 if let Some(w) = writer {
903 driver.interfaces.insert(
904 id,
905 InterfaceEntry {
906 id,
907 info,
908 writer: w,
909 online: in_capable || out_capable,
910 dynamic: false,
911 ifac: ifac_state,
912 stats: InterfaceStats {
913 started: time::now(),
914 ..Default::default()
915 },
916 interface_type: "UDPInterface".to_string(),
917 },
918 );
919 }
920 }
921 InterfaceVariant::LocalServer(local_config) => {
922 crate::interface::local::start_server(
923 local_config,
924 tx.clone(),
925 next_dynamic_id.clone(),
926 )?;
927 }
928 InterfaceVariant::LocalClient(local_config) => {
929 let id = local_config.interface_id;
930 let name = local_config.name.clone();
931 let info = InterfaceInfo {
932 id,
933 name,
934 mode: iface_mode,
935 out_capable: true,
936 in_capable: true,
937 bitrate: Some(1_000_000_000),
938 announce_rate_target: None,
939 announce_rate_grace: 0,
940 announce_rate_penalty: 0.0,
941 announce_cap: rns_core::constants::ANNOUNCE_CAP,
942 is_local_client: false,
943 wants_tunnel: false,
944 tunnel_id: None,
945 mtu: 65535,
946 ingress_control: false,
947 ia_freq: 0.0,
948 started: time::now(),
949 };
950
951 let writer =
952 crate::interface::local::start_client(local_config, tx.clone())?;
953
954 driver.engine.register_interface(info.clone());
955 driver.interfaces.insert(
956 id,
957 InterfaceEntry {
958 id,
959 info,
960 writer,
961 online: false,
962 dynamic: false,
963 ifac: ifac_state,
964 stats: InterfaceStats {
965 started: time::now(),
966 ..Default::default()
967 },
968 interface_type: "LocalInterface".to_string(),
969 },
970 );
971 }
972 InterfaceVariant::Serial(serial_config) => {
973 let id = serial_config.interface_id;
974 let name = serial_config.name.clone();
975 let bitrate = serial_config.speed;
976 let info = InterfaceInfo {
977 id,
978 name,
979 mode: iface_mode,
980 out_capable: true,
981 in_capable: true,
982 bitrate: Some(bitrate as u64),
983 announce_rate_target: None,
984 announce_rate_grace: 0,
985 announce_rate_penalty: 0.0,
986 announce_cap: rns_core::constants::ANNOUNCE_CAP,
987 is_local_client: false,
988 wants_tunnel: false,
989 tunnel_id: None,
990 mtu: rns_core::constants::MTU as u32,
991 ingress_control: false,
992 ia_freq: 0.0,
993 started: time::now(),
994 };
995
996 let writer =
997 crate::interface::serial_iface::start(serial_config, tx.clone())?;
998
999 driver.engine.register_interface(info.clone());
1000 driver.interfaces.insert(
1001 id,
1002 InterfaceEntry {
1003 id,
1004 info,
1005 writer,
1006 online: false,
1007 dynamic: false,
1008 ifac: ifac_state,
1009 stats: InterfaceStats {
1010 started: time::now(),
1011 ..Default::default()
1012 },
1013 interface_type: "SerialInterface".to_string(),
1014 },
1015 );
1016 }
1017 InterfaceVariant::Kiss(kiss_config) => {
1018 let id = kiss_config.interface_id;
1019 let name = kiss_config.name.clone();
1020 let info = InterfaceInfo {
1021 id,
1022 name,
1023 mode: iface_mode,
1024 out_capable: true,
1025 in_capable: true,
1026 bitrate: Some(1200), announce_rate_target: None,
1028 announce_rate_grace: 0,
1029 announce_rate_penalty: 0.0,
1030 announce_cap: rns_core::constants::ANNOUNCE_CAP,
1031 is_local_client: false,
1032 wants_tunnel: false,
1033 tunnel_id: None,
1034 mtu: rns_core::constants::MTU as u32,
1035 ingress_control: false,
1036 ia_freq: 0.0,
1037 started: time::now(),
1038 };
1039
1040 let writer =
1041 crate::interface::kiss_iface::start(kiss_config, tx.clone())?;
1042
1043 driver.engine.register_interface(info.clone());
1044 driver.interfaces.insert(
1045 id,
1046 InterfaceEntry {
1047 id,
1048 info,
1049 writer,
1050 online: false,
1051 dynamic: false,
1052 ifac: ifac_state,
1053 stats: InterfaceStats {
1054 started: time::now(),
1055 ..Default::default()
1056 },
1057 interface_type: "KISSInterface".to_string(),
1058 },
1059 );
1060 }
1061 InterfaceVariant::Pipe(pipe_config) => {
1062 let id = pipe_config.interface_id;
1063 let name = pipe_config.name.clone();
1064 let info = InterfaceInfo {
1065 id,
1066 name,
1067 mode: iface_mode,
1068 out_capable: true,
1069 in_capable: true,
1070 bitrate: Some(1_000_000), announce_rate_target: None,
1072 announce_rate_grace: 0,
1073 announce_rate_penalty: 0.0,
1074 announce_cap: rns_core::constants::ANNOUNCE_CAP,
1075 is_local_client: false,
1076 wants_tunnel: false,
1077 tunnel_id: None,
1078 mtu: rns_core::constants::MTU as u32,
1079 ingress_control: false,
1080 ia_freq: 0.0,
1081 started: time::now(),
1082 };
1083
1084 let writer =
1085 crate::interface::pipe::start(pipe_config, tx.clone())?;
1086
1087 driver.engine.register_interface(info.clone());
1088 driver.interfaces.insert(
1089 id,
1090 InterfaceEntry {
1091 id,
1092 info,
1093 writer,
1094 online: false,
1095 dynamic: false,
1096 ifac: ifac_state,
1097 stats: InterfaceStats {
1098 started: time::now(),
1099 ..Default::default()
1100 },
1101 interface_type: "PipeInterface".to_string(),
1102 },
1103 );
1104 }
1105 InterfaceVariant::RNode(rnode_config) => {
1106 let name = rnode_config.name.clone();
1107 let sub_writers =
1108 crate::interface::rnode::start(rnode_config, tx.clone())?;
1109
1110 let mut first = true;
1113 let mut sub_index = 0u32;
1114 for (sub_id, writer) in sub_writers {
1115 let sub_name = if sub_index == 0 {
1116 name.clone()
1117 } else {
1118 format!("{}/{}", name, sub_index)
1119 };
1120 sub_index += 1;
1121
1122 let info = InterfaceInfo {
1123 id: sub_id,
1124 name: sub_name,
1125 mode: iface_mode,
1126 out_capable: true,
1127 in_capable: true,
1128 bitrate: None, announce_rate_target: None,
1130 announce_rate_grace: 0,
1131 announce_rate_penalty: 0.0,
1132 announce_cap: rns_core::constants::ANNOUNCE_CAP,
1133 is_local_client: false,
1134 wants_tunnel: false,
1135 tunnel_id: None,
1136 mtu: rns_core::constants::MTU as u32,
1137 ingress_control: false,
1138 ia_freq: 0.0,
1139 started: time::now(),
1140 };
1141
1142 let sub_ifac = if first {
1143 first = false;
1144 ifac_state.take()
1145 } else if let Some(ref ic) = ifac_cfg {
1146 Some(ifac::derive_ifac(
1147 ic.netname.as_deref(),
1148 ic.netkey.as_deref(),
1149 ic.size,
1150 ))
1151 } else {
1152 None
1153 };
1154
1155 driver.engine.register_interface(info.clone());
1156 driver.interfaces.insert(
1157 sub_id,
1158 InterfaceEntry {
1159 id: sub_id,
1160 info,
1161 writer,
1162 online: false,
1163 dynamic: false,
1164 ifac: sub_ifac,
1165 stats: InterfaceStats {
1166 started: time::now(),
1167 ..Default::default()
1168 },
1169 interface_type: "RNodeInterface".to_string(),
1170 },
1171 );
1172 }
1173
1174 }
1175 InterfaceVariant::Backbone(backbone_config) => {
1176 crate::interface::backbone::start(
1177 backbone_config,
1178 tx.clone(),
1179 next_dynamic_id.clone(),
1180 )?;
1181 }
1184 InterfaceVariant::BackboneClient(config) => {
1185 let id = config.interface_id;
1186 let name = config.name.clone();
1187 let info = InterfaceInfo {
1188 id,
1189 name,
1190 mode: iface_mode,
1191 out_capable: true,
1192 in_capable: true,
1193 bitrate: Some(1_000_000_000),
1194 announce_rate_target: None,
1195 announce_rate_grace: 0,
1196 announce_rate_penalty: 0.0,
1197 announce_cap: rns_core::constants::ANNOUNCE_CAP,
1198 is_local_client: false,
1199 wants_tunnel: false,
1200 tunnel_id: None,
1201 mtu: 65535,
1202 ingress_control: true,
1203 ia_freq: 0.0,
1204 started: time::now(),
1205 };
1206
1207 let writer =
1208 crate::interface::backbone::start_client(config, tx.clone())?;
1209
1210 driver.engine.register_interface(info.clone());
1211 driver.interfaces.insert(
1212 id,
1213 InterfaceEntry {
1214 id,
1215 info,
1216 writer,
1217 online: false,
1218 dynamic: false,
1219 ifac: ifac_state,
1220 stats: InterfaceStats {
1221 started: time::now(),
1222 ..Default::default()
1223 },
1224 interface_type: "BackboneInterface".to_string(),
1225 },
1226 );
1227 }
1228 InterfaceVariant::Auto(auto_config) => {
1229 crate::interface::auto::start(
1230 auto_config,
1231 tx.clone(),
1232 next_dynamic_id.clone(),
1233 )?;
1234 }
1237 InterfaceVariant::I2p(i2p_config) => {
1238 crate::interface::i2p::start(
1239 i2p_config,
1240 tx.clone(),
1241 next_dynamic_id.clone(),
1242 )?;
1243 }
1246 }
1247 }
1248
1249 if config.management.enable_remote_management {
1251 if let Some(prv_key) = identity.get_private_key() {
1252 let identity_hash = *identity.hash();
1253 let mgmt_dest = crate::management::management_dest_hash(&identity_hash);
1254
1255 let sig_prv = rns_crypto::ed25519::Ed25519PrivateKey::from_bytes(
1257 &prv_key[32..64].try_into().unwrap(),
1258 );
1259 let sig_pub_bytes: [u8; 32] = identity
1260 .get_public_key()
1261 .unwrap()[32..64]
1262 .try_into()
1263 .unwrap();
1264
1265 driver.engine.register_destination(
1267 mgmt_dest,
1268 rns_core::constants::DESTINATION_SINGLE,
1269 );
1270 driver.local_destinations.insert(
1271 mgmt_dest,
1272 rns_core::constants::DESTINATION_SINGLE,
1273 );
1274
1275 driver.link_manager.register_link_destination(
1277 mgmt_dest,
1278 sig_prv,
1279 sig_pub_bytes,
1280 );
1281
1282 driver.link_manager.register_management_path(
1284 crate::management::status_path_hash(),
1285 );
1286 driver.link_manager.register_management_path(
1287 crate::management::path_path_hash(),
1288 );
1289
1290 log::info!(
1291 "Remote management enabled on {:02x?}",
1292 &mgmt_dest[..4],
1293 );
1294
1295 if !config.management.remote_management_allowed.is_empty() {
1297 log::info!(
1298 "Remote management allowed for {} identities",
1299 config.management.remote_management_allowed.len(),
1300 );
1301 }
1302 }
1303 }
1304
1305 if config.management.publish_blackhole {
1306 if let Some(prv_key) = identity.get_private_key() {
1307 let identity_hash = *identity.hash();
1308 let bh_dest = crate::management::blackhole_dest_hash(&identity_hash);
1309
1310 let sig_prv = rns_crypto::ed25519::Ed25519PrivateKey::from_bytes(
1311 &prv_key[32..64].try_into().unwrap(),
1312 );
1313 let sig_pub_bytes: [u8; 32] = identity
1314 .get_public_key()
1315 .unwrap()[32..64]
1316 .try_into()
1317 .unwrap();
1318
1319 driver.engine.register_destination(
1320 bh_dest,
1321 rns_core::constants::DESTINATION_SINGLE,
1322 );
1323 driver.link_manager.register_link_destination(
1324 bh_dest,
1325 sig_prv,
1326 sig_pub_bytes,
1327 );
1328 driver.link_manager.register_management_path(
1329 crate::management::list_path_hash(),
1330 );
1331
1332 log::info!(
1333 "Blackhole list publishing enabled on {:02x?}",
1334 &bh_dest[..4],
1335 );
1336 }
1337 }
1338
1339 let tick_interval_ms = Arc::new(AtomicU64::new(1000));
1341 let timer_tx = tx.clone();
1342 let timer_interval = Arc::clone(&tick_interval_ms);
1343 thread::Builder::new()
1344 .name("rns-timer".into())
1345 .spawn(move || {
1346 loop {
1347 let ms = timer_interval.load(Ordering::Relaxed);
1348 thread::sleep(Duration::from_millis(ms));
1349 if timer_tx.send(Event::Tick).is_err() {
1350 break; }
1352 }
1353 })?;
1354
1355 let rpc_server = if config.share_instance {
1357 let auth_key = crate::rpc::derive_auth_key(
1358 &identity.get_private_key().unwrap_or([0u8; 64]),
1359 );
1360 let rpc_addr = crate::rpc::RpcAddr::Tcp("127.0.0.1".into(), config.rpc_port);
1361 match crate::rpc::RpcServer::start(&rpc_addr, auth_key, tx.clone()) {
1362 Ok(server) => {
1363 log::info!("RPC server started on 127.0.0.1:{}", config.rpc_port);
1364 Some(server)
1365 }
1366 Err(e) => {
1367 log::error!("Failed to start RPC server: {}", e);
1368 None
1369 }
1370 }
1371 } else {
1372 None
1373 };
1374
1375 let driver_handle = thread::Builder::new()
1377 .name("rns-driver".into())
1378 .spawn(move || {
1379 driver.run();
1380 })?;
1381
1382 Ok(RnsNode {
1383 tx,
1384 driver_handle: Some(driver_handle),
1385 rpc_server,
1386 tick_interval_ms,
1387 probe_server,
1388 })
1389 }
1390
1391 pub fn query(&self, request: QueryRequest) -> Result<QueryResponse, SendError> {
1393 let (resp_tx, resp_rx) = std::sync::mpsc::channel();
1394 self.tx
1395 .send(Event::Query(request, resp_tx))
1396 .map_err(|_| SendError)?;
1397 resp_rx.recv().map_err(|_| SendError)
1398 }
1399
1400 pub fn send_raw(
1402 &self,
1403 raw: Vec<u8>,
1404 dest_type: u8,
1405 attached_interface: Option<rns_core::transport::types::InterfaceId>,
1406 ) -> Result<(), SendError> {
1407 self.tx
1408 .send(Event::SendOutbound {
1409 raw,
1410 dest_type,
1411 attached_interface,
1412 })
1413 .map_err(|_| SendError)
1414 }
1415
1416 pub fn register_destination(
1418 &self,
1419 dest_hash: [u8; 16],
1420 dest_type: u8,
1421 ) -> Result<(), SendError> {
1422 self.tx
1423 .send(Event::RegisterDestination { dest_hash, dest_type })
1424 .map_err(|_| SendError)
1425 }
1426
1427 pub fn deregister_destination(&self, dest_hash: [u8; 16]) -> Result<(), SendError> {
1429 self.tx
1430 .send(Event::DeregisterDestination { dest_hash })
1431 .map_err(|_| SendError)
1432 }
1433
1434 pub fn deregister_link_destination(&self, dest_hash: [u8; 16]) -> Result<(), SendError> {
1436 self.tx
1437 .send(Event::DeregisterLinkDestination { dest_hash })
1438 .map_err(|_| SendError)
1439 }
1440
1441 pub fn register_link_destination(
1447 &self,
1448 dest_hash: [u8; 16],
1449 sig_prv_bytes: [u8; 32],
1450 sig_pub_bytes: [u8; 32],
1451 ) -> Result<(), SendError> {
1452 self.tx
1453 .send(Event::RegisterLinkDestination {
1454 dest_hash,
1455 sig_prv_bytes,
1456 sig_pub_bytes,
1457 })
1458 .map_err(|_| SendError)
1459 }
1460
1461 pub fn register_request_handler<F>(
1463 &self,
1464 path: &str,
1465 allowed_list: Option<Vec<[u8; 16]>>,
1466 handler: F,
1467 ) -> Result<(), SendError>
1468 where
1469 F: Fn([u8; 16], &str, &[u8], Option<&([u8; 16], [u8; 64])>) -> Option<Vec<u8>> + Send + 'static,
1470 {
1471 self.tx
1472 .send(Event::RegisterRequestHandler {
1473 path: path.to_string(),
1474 allowed_list,
1475 handler: Box::new(handler),
1476 })
1477 .map_err(|_| SendError)
1478 }
1479
1480 pub fn create_link(
1484 &self,
1485 dest_hash: [u8; 16],
1486 dest_sig_pub_bytes: [u8; 32],
1487 ) -> Result<[u8; 16], SendError> {
1488 let (response_tx, response_rx) = std::sync::mpsc::channel();
1489 self.tx
1490 .send(Event::CreateLink {
1491 dest_hash,
1492 dest_sig_pub_bytes,
1493 response_tx,
1494 })
1495 .map_err(|_| SendError)?;
1496 response_rx.recv().map_err(|_| SendError)
1497 }
1498
1499 pub fn send_request(
1501 &self,
1502 link_id: [u8; 16],
1503 path: &str,
1504 data: &[u8],
1505 ) -> Result<(), SendError> {
1506 self.tx
1507 .send(Event::SendRequest {
1508 link_id,
1509 path: path.to_string(),
1510 data: data.to_vec(),
1511 })
1512 .map_err(|_| SendError)
1513 }
1514
1515 pub fn identify_on_link(
1517 &self,
1518 link_id: [u8; 16],
1519 identity_prv_key: [u8; 64],
1520 ) -> Result<(), SendError> {
1521 self.tx
1522 .send(Event::IdentifyOnLink {
1523 link_id,
1524 identity_prv_key,
1525 })
1526 .map_err(|_| SendError)
1527 }
1528
1529 pub fn teardown_link(&self, link_id: [u8; 16]) -> Result<(), SendError> {
1531 self.tx
1532 .send(Event::TeardownLink { link_id })
1533 .map_err(|_| SendError)
1534 }
1535
1536 pub fn send_resource(
1538 &self,
1539 link_id: [u8; 16],
1540 data: Vec<u8>,
1541 metadata: Option<Vec<u8>>,
1542 ) -> Result<(), SendError> {
1543 self.tx
1544 .send(Event::SendResource { link_id, data, metadata })
1545 .map_err(|_| SendError)
1546 }
1547
1548 pub fn set_resource_strategy(
1552 &self,
1553 link_id: [u8; 16],
1554 strategy: u8,
1555 ) -> Result<(), SendError> {
1556 self.tx
1557 .send(Event::SetResourceStrategy { link_id, strategy })
1558 .map_err(|_| SendError)
1559 }
1560
1561 pub fn accept_resource(
1563 &self,
1564 link_id: [u8; 16],
1565 resource_hash: Vec<u8>,
1566 accept: bool,
1567 ) -> Result<(), SendError> {
1568 self.tx
1569 .send(Event::AcceptResource { link_id, resource_hash, accept })
1570 .map_err(|_| SendError)
1571 }
1572
1573 pub fn send_channel_message(
1575 &self,
1576 link_id: [u8; 16],
1577 msgtype: u16,
1578 payload: Vec<u8>,
1579 ) -> Result<(), SendError> {
1580 self.tx
1581 .send(Event::SendChannelMessage { link_id, msgtype, payload })
1582 .map_err(|_| SendError)
1583 }
1584
1585 pub fn propose_direct_connect(&self, link_id: [u8; 16]) -> Result<(), SendError> {
1590 self.tx
1591 .send(Event::ProposeDirectConnect { link_id })
1592 .map_err(|_| SendError)
1593 }
1594
1595 pub fn set_direct_connect_policy(
1597 &self,
1598 policy: crate::holepunch::orchestrator::HolePunchPolicy,
1599 ) -> Result<(), SendError> {
1600 self.tx
1601 .send(Event::SetDirectConnectPolicy { policy })
1602 .map_err(|_| SendError)
1603 }
1604
1605 pub fn send_on_link(
1607 &self,
1608 link_id: [u8; 16],
1609 data: Vec<u8>,
1610 context: u8,
1611 ) -> Result<(), SendError> {
1612 self.tx
1613 .send(Event::SendOnLink { link_id, data, context })
1614 .map_err(|_| SendError)
1615 }
1616
1617 pub fn announce(
1622 &self,
1623 dest: &crate::destination::Destination,
1624 identity: &Identity,
1625 app_data: Option<&[u8]>,
1626 ) -> Result<(), SendError> {
1627 let name_hash = rns_core::destination::name_hash(
1628 &dest.app_name,
1629 &dest.aspects.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
1630 );
1631
1632 let mut random_hash = [0u8; 10];
1633 OsRng.fill_bytes(&mut random_hash);
1634
1635 let (announce_data, _has_ratchet) = rns_core::announce::AnnounceData::pack(
1636 identity,
1637 &dest.hash.0,
1638 &name_hash,
1639 &random_hash,
1640 None, app_data,
1642 ).map_err(|_| SendError)?;
1643
1644 let context_flag = rns_core::constants::FLAG_UNSET;
1645
1646 let flags = rns_core::packet::PacketFlags {
1647 header_type: rns_core::constants::HEADER_1,
1648 context_flag,
1649 transport_type: rns_core::constants::TRANSPORT_BROADCAST,
1650 destination_type: rns_core::constants::DESTINATION_SINGLE,
1651 packet_type: rns_core::constants::PACKET_TYPE_ANNOUNCE,
1652 };
1653
1654 let packet = rns_core::packet::RawPacket::pack(
1655 flags, 0, &dest.hash.0, None,
1656 rns_core::constants::CONTEXT_NONE, &announce_data,
1657 ).map_err(|_| SendError)?;
1658
1659 self.send_raw(
1660 packet.raw,
1661 dest.dest_type.to_wire_constant(),
1662 None,
1663 )
1664 }
1665
1666 pub fn send_packet(
1671 &self,
1672 dest: &crate::destination::Destination,
1673 data: &[u8],
1674 ) -> Result<rns_core::types::PacketHash, SendError> {
1675 use rns_core::types::DestinationType;
1676
1677 let payload = match dest.dest_type {
1678 DestinationType::Single => {
1679 let pub_key = dest.public_key.ok_or(SendError)?;
1680 let remote_id = rns_crypto::identity::Identity::from_public_key(&pub_key);
1681 remote_id.encrypt(data, &mut OsRng).map_err(|_| SendError)?
1682 }
1683 DestinationType::Plain => data.to_vec(),
1684 DestinationType::Group => {
1685 dest.encrypt(data).map_err(|_| SendError)?
1686 }
1687 };
1688
1689 let flags = rns_core::packet::PacketFlags {
1690 header_type: rns_core::constants::HEADER_1,
1691 context_flag: rns_core::constants::FLAG_UNSET,
1692 transport_type: rns_core::constants::TRANSPORT_BROADCAST,
1693 destination_type: dest.dest_type.to_wire_constant(),
1694 packet_type: rns_core::constants::PACKET_TYPE_DATA,
1695 };
1696
1697 let packet = rns_core::packet::RawPacket::pack(
1698 flags, 0, &dest.hash.0, None,
1699 rns_core::constants::CONTEXT_NONE, &payload,
1700 ).map_err(|_| SendError)?;
1701
1702 let packet_hash = rns_core::types::PacketHash(packet.packet_hash);
1703
1704 self.tx
1705 .send(Event::SendOutbound {
1706 raw: packet.raw,
1707 dest_type: dest.dest_type.to_wire_constant(),
1708 attached_interface: None,
1709 })
1710 .map_err(|_| SendError)?;
1711
1712 Ok(packet_hash)
1713 }
1714
1715 pub fn register_destination_with_proof(
1720 &self,
1721 dest: &crate::destination::Destination,
1722 signing_key: Option<[u8; 64]>,
1723 ) -> Result<(), SendError> {
1724 self.register_destination(dest.hash.0, dest.dest_type.to_wire_constant())?;
1726
1727 if dest.proof_strategy != rns_core::types::ProofStrategy::ProveNone {
1729 self.tx
1730 .send(Event::RegisterProofStrategy {
1731 dest_hash: dest.hash.0,
1732 strategy: dest.proof_strategy,
1733 signing_key,
1734 })
1735 .map_err(|_| SendError)?;
1736 }
1737
1738 Ok(())
1739 }
1740
1741 pub fn request_path(&self, dest_hash: &rns_core::types::DestHash) -> Result<(), SendError> {
1743 self.tx
1744 .send(Event::RequestPath { dest_hash: dest_hash.0 })
1745 .map_err(|_| SendError)
1746 }
1747
1748 pub fn has_path(&self, dest_hash: &rns_core::types::DestHash) -> Result<bool, SendError> {
1750 match self.query(QueryRequest::HasPath { dest_hash: dest_hash.0 })? {
1751 QueryResponse::HasPath(v) => Ok(v),
1752 _ => Ok(false),
1753 }
1754 }
1755
1756 pub fn hops_to(&self, dest_hash: &rns_core::types::DestHash) -> Result<Option<u8>, SendError> {
1758 match self.query(QueryRequest::HopsTo { dest_hash: dest_hash.0 })? {
1759 QueryResponse::HopsTo(v) => Ok(v),
1760 _ => Ok(None),
1761 }
1762 }
1763
1764 pub fn recall_identity(
1766 &self,
1767 dest_hash: &rns_core::types::DestHash,
1768 ) -> Result<Option<crate::destination::AnnouncedIdentity>, SendError> {
1769 match self.query(QueryRequest::RecallIdentity { dest_hash: dest_hash.0 })? {
1770 QueryResponse::RecallIdentity(v) => Ok(v),
1771 _ => Ok(None),
1772 }
1773 }
1774
1775 pub(crate) fn from_parts(
1778 tx: EventSender,
1779 driver_handle: thread::JoinHandle<()>,
1780 rpc_server: Option<crate::rpc::RpcServer>,
1781 tick_interval_ms: Arc<AtomicU64>,
1782 ) -> Self {
1783 RnsNode {
1784 tx,
1785 driver_handle: Some(driver_handle),
1786 rpc_server,
1787 tick_interval_ms,
1788 probe_server: None,
1789 }
1790 }
1791
1792 pub fn event_sender(&self) -> &EventSender {
1794 &self.tx
1795 }
1796
1797 pub fn set_tick_interval(&self, ms: u64) -> u64 {
1802 let clamped = ms.clamp(100, 10_000);
1803 if clamped != ms {
1804 log::warn!(
1805 "tick interval {}ms out of range, clamped to {}ms",
1806 ms,
1807 clamped
1808 );
1809 }
1810 self.tick_interval_ms.store(clamped, Ordering::Relaxed);
1811 clamped
1812 }
1813
1814 pub fn tick_interval(&self) -> u64 {
1816 self.tick_interval_ms.load(Ordering::Relaxed)
1817 }
1818
1819 pub fn shutdown(mut self) {
1821 if let Some(mut rpc) = self.rpc_server.take() {
1823 rpc.stop();
1824 }
1825 let _ = self.tx.send(Event::Shutdown);
1826 if let Some(handle) = self.driver_handle.take() {
1827 let _ = handle.join();
1828 }
1829 }
1830}
1831
1832#[cfg(test)]
1833mod tests {
1834 use super::*;
1835 use std::fs;
1836
1837 struct NoopCallbacks;
1838
1839 impl Callbacks for NoopCallbacks {
1840 fn on_announce(&mut self, _: crate::destination::AnnouncedIdentity) {}
1841 fn on_path_updated(&mut self, _: rns_core::types::DestHash, _: u8) {}
1842 fn on_local_delivery(&mut self, _: rns_core::types::DestHash, _: Vec<u8>, _: rns_core::types::PacketHash) {}
1843 }
1844
1845 #[test]
1846 fn start_and_shutdown() {
1847 let node = RnsNode::start(
1848 NodeConfig {
1849 transport_enabled: false,
1850 identity: None,
1851 interfaces: vec![],
1852 share_instance: false,
1853 rpc_port: 0,
1854 cache_dir: None,
1855 management: Default::default(),
1856 probe_port: None,
1857 probe_addr: None,
1858 device: None,
1859 },
1860 Box::new(NoopCallbacks),
1861 )
1862 .unwrap();
1863 node.shutdown();
1864 }
1865
1866 #[test]
1867 fn start_with_identity() {
1868 let identity = Identity::new(&mut OsRng);
1869 let hash = *identity.hash();
1870 let node = RnsNode::start(
1871 NodeConfig {
1872 transport_enabled: true,
1873 identity: Some(identity),
1874 interfaces: vec![],
1875 share_instance: false,
1876 rpc_port: 0,
1877 cache_dir: None,
1878 management: Default::default(),
1879 probe_port: None,
1880 probe_addr: None,
1881 device: None,
1882 },
1883 Box::new(NoopCallbacks),
1884 )
1885 .unwrap();
1886 let _ = hash;
1888 node.shutdown();
1889 }
1890
1891 #[test]
1892 fn start_generates_identity() {
1893 let node = RnsNode::start(
1894 NodeConfig {
1895 transport_enabled: false,
1896 identity: None,
1897 interfaces: vec![],
1898 share_instance: false,
1899 rpc_port: 0,
1900 cache_dir: None,
1901 management: Default::default(),
1902 probe_port: None,
1903 probe_addr: None,
1904 device: None,
1905 },
1906 Box::new(NoopCallbacks),
1907 )
1908 .unwrap();
1909 node.shutdown();
1911 }
1912
1913 #[test]
1914 fn from_config_creates_identity() {
1915 let dir = std::env::temp_dir().join(format!("rns-test-fc-{}", std::process::id()));
1916 let _ = fs::remove_dir_all(&dir);
1917 fs::create_dir_all(&dir).unwrap();
1918
1919 fs::write(
1921 dir.join("config"),
1922 "[reticulum]\nenable_transport = False\n",
1923 )
1924 .unwrap();
1925
1926 let node = RnsNode::from_config(Some(&dir), Box::new(NoopCallbacks)).unwrap();
1927
1928 assert!(dir.join("storage/identities/identity").exists());
1930
1931 node.shutdown();
1932 let _ = fs::remove_dir_all(&dir);
1933 }
1934
1935 #[test]
1936 fn from_config_loads_identity() {
1937 let dir = std::env::temp_dir().join(format!("rns-test-fl-{}", std::process::id()));
1938 let _ = fs::remove_dir_all(&dir);
1939 fs::create_dir_all(dir.join("storage/identities")).unwrap();
1940
1941 let identity = Identity::new(&mut OsRng);
1943 let hash = *identity.hash();
1944 storage::save_identity(&identity, &dir.join("storage/identities/identity")).unwrap();
1945
1946 fs::write(
1947 dir.join("config"),
1948 "[reticulum]\nenable_transport = False\n",
1949 )
1950 .unwrap();
1951
1952 let node = RnsNode::from_config(Some(&dir), Box::new(NoopCallbacks)).unwrap();
1953
1954 let loaded = storage::load_identity(&dir.join("storage/identities/identity")).unwrap();
1956 assert_eq!(*loaded.hash(), hash);
1957
1958 node.shutdown();
1959 let _ = fs::remove_dir_all(&dir);
1960 }
1961
1962 #[test]
1963 fn from_config_tcp_server() {
1964 let dir = std::env::temp_dir().join(format!("rns-test-fts-{}", std::process::id()));
1965 let _ = fs::remove_dir_all(&dir);
1966 fs::create_dir_all(&dir).unwrap();
1967
1968 let port = std::net::TcpListener::bind("127.0.0.1:0")
1970 .unwrap()
1971 .local_addr()
1972 .unwrap()
1973 .port();
1974
1975 let config = format!(
1976 r#"
1977[reticulum]
1978enable_transport = False
1979
1980[interfaces]
1981 [[Test TCP Server]]
1982 type = TCPServerInterface
1983 listen_ip = 127.0.0.1
1984 listen_port = {}
1985"#,
1986 port
1987 );
1988
1989 fs::write(dir.join("config"), config).unwrap();
1990
1991 let node = RnsNode::from_config(Some(&dir), Box::new(NoopCallbacks)).unwrap();
1992
1993 thread::sleep(Duration::from_millis(100));
1995
1996 let _client = std::net::TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
1998
1999 node.shutdown();
2000 let _ = fs::remove_dir_all(&dir);
2001 }
2002
2003 #[test]
2004 fn test_parse_interface_mode() {
2005 use rns_core::constants::*;
2006
2007 assert_eq!(parse_interface_mode("full"), MODE_FULL);
2008 assert_eq!(parse_interface_mode("Full"), MODE_FULL);
2009 assert_eq!(parse_interface_mode("access_point"), MODE_ACCESS_POINT);
2010 assert_eq!(parse_interface_mode("accesspoint"), MODE_ACCESS_POINT);
2011 assert_eq!(parse_interface_mode("ap"), MODE_ACCESS_POINT);
2012 assert_eq!(parse_interface_mode("AP"), MODE_ACCESS_POINT);
2013 assert_eq!(parse_interface_mode("pointtopoint"), MODE_POINT_TO_POINT);
2014 assert_eq!(parse_interface_mode("ptp"), MODE_POINT_TO_POINT);
2015 assert_eq!(parse_interface_mode("roaming"), MODE_ROAMING);
2016 assert_eq!(parse_interface_mode("boundary"), MODE_BOUNDARY);
2017 assert_eq!(parse_interface_mode("gateway"), MODE_GATEWAY);
2018 assert_eq!(parse_interface_mode("gw"), MODE_GATEWAY);
2019 assert_eq!(parse_interface_mode("invalid"), MODE_FULL);
2021 }
2022
2023 #[test]
2024 fn to_node_config_serial() {
2025 let dir = std::env::temp_dir().join(format!("rns-test-serial-{}", std::process::id()));
2029 let _ = fs::remove_dir_all(&dir);
2030 fs::create_dir_all(&dir).unwrap();
2031
2032 let config = r#"
2033[reticulum]
2034enable_transport = False
2035
2036[interfaces]
2037 [[Test Serial Port]]
2038 type = SerialInterface
2039 port = /dev/nonexistent_rns_test_serial
2040 speed = 115200
2041 databits = 8
2042 parity = E
2043 stopbits = 1
2044 interface_mode = ptp
2045 networkname = testnet
2046"#;
2047 fs::write(dir.join("config"), config).unwrap();
2048
2049 let result = RnsNode::from_config(Some(&dir), Box::new(NoopCallbacks));
2050 match result {
2052 Ok(node) => {
2053 node.shutdown();
2054 panic!("Expected error from non-existent serial port");
2055 }
2056 Err(err) => {
2057 let msg = format!("{}", err);
2058 assert!(
2059 !msg.contains("Unsupported") && !msg.contains("parse"),
2060 "Error should be from serial open, got: {}",
2061 msg
2062 );
2063 }
2064 }
2065
2066 let _ = fs::remove_dir_all(&dir);
2067 }
2068
2069 #[test]
2070 fn to_node_config_kiss() {
2071 let dir = std::env::temp_dir().join(format!("rns-test-kiss-{}", std::process::id()));
2073 let _ = fs::remove_dir_all(&dir);
2074 fs::create_dir_all(&dir).unwrap();
2075
2076 let config = r#"
2077[reticulum]
2078enable_transport = False
2079
2080[interfaces]
2081 [[Test KISS TNC]]
2082 type = KISSInterface
2083 port = /dev/nonexistent_rns_test_kiss
2084 speed = 9600
2085 preamble = 500
2086 txtail = 30
2087 persistence = 128
2088 slottime = 40
2089 flow_control = True
2090 id_interval = 600
2091 id_callsign = TEST0
2092 interface_mode = full
2093 passphrase = secretkey
2094"#;
2095 fs::write(dir.join("config"), config).unwrap();
2096
2097 let result = RnsNode::from_config(Some(&dir), Box::new(NoopCallbacks));
2098 match result {
2100 Ok(node) => {
2101 node.shutdown();
2102 panic!("Expected error from non-existent serial port");
2103 }
2104 Err(err) => {
2105 let msg = format!("{}", err);
2106 assert!(
2107 !msg.contains("Unsupported") && !msg.contains("parse"),
2108 "Error should be from serial open, got: {}",
2109 msg
2110 );
2111 }
2112 }
2113
2114 let _ = fs::remove_dir_all(&dir);
2115 }
2116
2117 #[test]
2118 fn test_extract_ifac_config() {
2119 use std::collections::HashMap;
2120
2121 let params: HashMap<String, String> = HashMap::new();
2123 assert!(extract_ifac_config(¶ms, 16).is_none());
2124
2125 let mut params = HashMap::new();
2127 params.insert("networkname".into(), "testnet".into());
2128 let ifac = extract_ifac_config(¶ms, 16).unwrap();
2129 assert_eq!(ifac.netname.as_deref(), Some("testnet"));
2130 assert!(ifac.netkey.is_none());
2131 assert_eq!(ifac.size, 16);
2132
2133 let mut params = HashMap::new();
2135 params.insert("passphrase".into(), "secret".into());
2136 params.insert("ifac_size".into(), "64".into()); let ifac = extract_ifac_config(¶ms, 16).unwrap();
2138 assert!(ifac.netname.is_none());
2139 assert_eq!(ifac.netkey.as_deref(), Some("secret"));
2140 assert_eq!(ifac.size, 8);
2141
2142 let mut params = HashMap::new();
2144 params.insert("network_name".into(), "mynet".into());
2145 params.insert("pass_phrase".into(), "mykey".into());
2146 let ifac = extract_ifac_config(¶ms, 8).unwrap();
2147 assert_eq!(ifac.netname.as_deref(), Some("mynet"));
2148 assert_eq!(ifac.netkey.as_deref(), Some("mykey"));
2149 assert_eq!(ifac.size, 8);
2150 }
2151
2152 #[test]
2153 fn test_parse_parity() {
2154 assert_eq!(parse_parity("E"), Parity::Even);
2155 assert_eq!(parse_parity("even"), Parity::Even);
2156 assert_eq!(parse_parity("O"), Parity::Odd);
2157 assert_eq!(parse_parity("odd"), Parity::Odd);
2158 assert_eq!(parse_parity("N"), Parity::None);
2159 assert_eq!(parse_parity("none"), Parity::None);
2160 assert_eq!(parse_parity("unknown"), Parity::None);
2161 }
2162
2163 #[test]
2164 fn to_node_config_rnode() {
2165 let dir = std::env::temp_dir().join(format!("rns-test-rnode-{}", std::process::id()));
2168 let _ = fs::remove_dir_all(&dir);
2169 fs::create_dir_all(&dir).unwrap();
2170
2171 let config = r#"
2172[reticulum]
2173enable_transport = False
2174
2175[interfaces]
2176 [[Test RNode]]
2177 type = RNodeInterface
2178 port = /dev/nonexistent_rns_test_rnode
2179 frequency = 867200000
2180 bandwidth = 125000
2181 txpower = 7
2182 spreadingfactor = 8
2183 codingrate = 5
2184 flow_control = True
2185 st_alock = 5.0
2186 lt_alock = 2.5
2187 interface_mode = full
2188 networkname = testnet
2189"#;
2190 fs::write(dir.join("config"), config).unwrap();
2191
2192 let result = RnsNode::from_config(Some(&dir), Box::new(NoopCallbacks));
2193 match result {
2195 Ok(node) => {
2196 node.shutdown();
2197 panic!("Expected error from non-existent serial port");
2198 }
2199 Err(err) => {
2200 let msg = format!("{}", err);
2201 assert!(
2202 !msg.contains("Unsupported") && !msg.contains("parse"),
2203 "Error should be from serial open, got: {}",
2204 msg
2205 );
2206 }
2207 }
2208
2209 let _ = fs::remove_dir_all(&dir);
2210 }
2211
2212 #[test]
2213 fn to_node_config_pipe() {
2214 let dir = std::env::temp_dir().join(format!("rns-test-pipe-{}", std::process::id()));
2217 let _ = fs::remove_dir_all(&dir);
2218 fs::create_dir_all(&dir).unwrap();
2219
2220 let config = r#"
2221[reticulum]
2222enable_transport = False
2223
2224[interfaces]
2225 [[Test Pipe]]
2226 type = PipeInterface
2227 command = cat
2228 respawn_delay = 5000
2229 interface_mode = full
2230"#;
2231 fs::write(dir.join("config"), config).unwrap();
2232
2233 let node = RnsNode::from_config(Some(&dir), Box::new(NoopCallbacks)).unwrap();
2234 node.shutdown();
2236
2237 let _ = fs::remove_dir_all(&dir);
2238 }
2239
2240 #[test]
2241 fn to_node_config_backbone() {
2242 let dir = std::env::temp_dir().join(format!("rns-test-backbone-{}", std::process::id()));
2244 let _ = fs::remove_dir_all(&dir);
2245 fs::create_dir_all(&dir).unwrap();
2246
2247 let port = std::net::TcpListener::bind("127.0.0.1:0")
2248 .unwrap()
2249 .local_addr()
2250 .unwrap()
2251 .port();
2252
2253 let config = format!(
2254 r#"
2255[reticulum]
2256enable_transport = False
2257
2258[interfaces]
2259 [[Test Backbone]]
2260 type = BackboneInterface
2261 listen_ip = 127.0.0.1
2262 listen_port = {}
2263 interface_mode = full
2264"#,
2265 port
2266 );
2267
2268 fs::write(dir.join("config"), config).unwrap();
2269
2270 let node = RnsNode::from_config(Some(&dir), Box::new(NoopCallbacks)).unwrap();
2271
2272 thread::sleep(Duration::from_millis(100));
2274
2275 {
2277 let _client = std::net::TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
2278 }
2280
2281 thread::sleep(Duration::from_millis(50));
2283
2284 node.shutdown();
2285 let _ = fs::remove_dir_all(&dir);
2286 }
2287
2288 #[test]
2289 fn rnode_config_defaults() {
2290 use crate::interface::rnode::{RNodeConfig, RNodeSubConfig};
2291
2292 let config = RNodeConfig::default();
2293 assert_eq!(config.speed, 115200);
2294 assert!(config.subinterfaces.is_empty());
2295 assert!(config.id_interval.is_none());
2296 assert!(config.id_callsign.is_none());
2297
2298 let sub = RNodeSubConfig {
2299 name: "test".into(),
2300 frequency: 868_000_000,
2301 bandwidth: 125_000,
2302 txpower: 7,
2303 spreading_factor: 8,
2304 coding_rate: 5,
2305 flow_control: false,
2306 st_alock: None,
2307 lt_alock: None,
2308 };
2309 assert_eq!(sub.frequency, 868_000_000);
2310 assert_eq!(sub.bandwidth, 125_000);
2311 assert!(!sub.flow_control);
2312 }
2313
2314 #[test]
2319 fn announce_builds_valid_packet() {
2320 let identity = Identity::new(&mut OsRng);
2321 let identity_hash = rns_core::types::IdentityHash(*identity.hash());
2322
2323 let node = RnsNode::start(
2324 NodeConfig {
2325 transport_enabled: false,
2326 identity: None,
2327 interfaces: vec![],
2328 share_instance: false,
2329 rpc_port: 0,
2330 cache_dir: None,
2331 management: Default::default(),
2332 probe_port: None,
2333 probe_addr: None,
2334 device: None,
2335 },
2336 Box::new(NoopCallbacks),
2337 ).unwrap();
2338
2339 let dest = crate::destination::Destination::single_in(
2340 "test", &["echo"], identity_hash,
2341 );
2342
2343 node.register_destination(dest.hash.0, dest.dest_type.to_wire_constant()).unwrap();
2345
2346 let result = node.announce(&dest, &identity, Some(b"hello"));
2348 assert!(result.is_ok());
2349
2350 node.shutdown();
2351 }
2352
2353 #[test]
2354 fn has_path_and_hops_to() {
2355 let node = RnsNode::start(
2356 NodeConfig {
2357 transport_enabled: false,
2358 identity: None,
2359 interfaces: vec![],
2360 share_instance: false,
2361 rpc_port: 0,
2362 cache_dir: None,
2363 management: Default::default(),
2364 probe_port: None,
2365 probe_addr: None,
2366 device: None,
2367 },
2368 Box::new(NoopCallbacks),
2369 ).unwrap();
2370
2371 let dh = rns_core::types::DestHash([0xAA; 16]);
2372
2373 assert_eq!(node.has_path(&dh).unwrap(), false);
2375 assert_eq!(node.hops_to(&dh).unwrap(), None);
2376
2377 node.shutdown();
2378 }
2379
2380 #[test]
2381 fn recall_identity_none_when_unknown() {
2382 let node = RnsNode::start(
2383 NodeConfig {
2384 transport_enabled: false,
2385 identity: None,
2386 interfaces: vec![],
2387 share_instance: false,
2388 rpc_port: 0,
2389 cache_dir: None,
2390 management: Default::default(),
2391 probe_port: None,
2392 probe_addr: None,
2393 device: None,
2394 },
2395 Box::new(NoopCallbacks),
2396 ).unwrap();
2397
2398 let dh = rns_core::types::DestHash([0xBB; 16]);
2399 assert!(node.recall_identity(&dh).unwrap().is_none());
2400
2401 node.shutdown();
2402 }
2403
2404 #[test]
2405 fn request_path_does_not_crash() {
2406 let node = RnsNode::start(
2407 NodeConfig {
2408 transport_enabled: false,
2409 identity: None,
2410 interfaces: vec![],
2411 share_instance: false,
2412 rpc_port: 0,
2413 cache_dir: None,
2414 management: Default::default(),
2415 probe_port: None,
2416 probe_addr: None,
2417 device: None,
2418 },
2419 Box::new(NoopCallbacks),
2420 ).unwrap();
2421
2422 let dh = rns_core::types::DestHash([0xCC; 16]);
2423 assert!(node.request_path(&dh).is_ok());
2424
2425 thread::sleep(Duration::from_millis(50));
2427
2428 node.shutdown();
2429 }
2430
2431 #[test]
2436 fn send_packet_plain() {
2437 let node = RnsNode::start(
2438 NodeConfig {
2439 transport_enabled: false,
2440 identity: None,
2441 interfaces: vec![],
2442 share_instance: false,
2443 rpc_port: 0,
2444 cache_dir: None,
2445 management: Default::default(),
2446 probe_port: None,
2447 probe_addr: None,
2448 device: None,
2449 },
2450 Box::new(NoopCallbacks),
2451 ).unwrap();
2452
2453 let dest = crate::destination::Destination::plain("test", &["echo"]);
2454 let result = node.send_packet(&dest, b"hello world");
2455 assert!(result.is_ok());
2456
2457 let packet_hash = result.unwrap();
2458 assert_ne!(packet_hash.0, [0u8; 32]);
2460
2461 thread::sleep(Duration::from_millis(50));
2463
2464 node.shutdown();
2465 }
2466
2467 #[test]
2468 fn send_packet_single_requires_public_key() {
2469 let node = RnsNode::start(
2470 NodeConfig {
2471 transport_enabled: false,
2472 identity: None,
2473 interfaces: vec![],
2474 share_instance: false,
2475 rpc_port: 0,
2476 cache_dir: None,
2477 management: Default::default(),
2478 probe_port: None,
2479 probe_addr: None,
2480 device: None,
2481 },
2482 Box::new(NoopCallbacks),
2483 ).unwrap();
2484
2485 let dest = crate::destination::Destination::single_in(
2487 "test", &["echo"],
2488 rns_core::types::IdentityHash([0x42; 16]),
2489 );
2490 let result = node.send_packet(&dest, b"hello");
2491 assert!(result.is_err(), "single_in has no public_key, should fail");
2492
2493 node.shutdown();
2494 }
2495
2496 #[test]
2497 fn send_packet_single_encrypts() {
2498 let node = RnsNode::start(
2499 NodeConfig {
2500 transport_enabled: false,
2501 identity: None,
2502 interfaces: vec![],
2503 share_instance: false,
2504 rpc_port: 0,
2505 cache_dir: None,
2506 management: Default::default(),
2507 probe_port: None,
2508 probe_addr: None,
2509 device: None,
2510 },
2511 Box::new(NoopCallbacks),
2512 ).unwrap();
2513
2514 let remote_identity = Identity::new(&mut OsRng);
2516 let recalled = crate::destination::AnnouncedIdentity {
2517 dest_hash: rns_core::types::DestHash([0xAA; 16]),
2518 identity_hash: rns_core::types::IdentityHash(*remote_identity.hash()),
2519 public_key: remote_identity.get_public_key().unwrap(),
2520 app_data: None,
2521 hops: 1,
2522 received_at: 0.0,
2523 };
2524 let dest = crate::destination::Destination::single_out("test", &["echo"], &recalled);
2525
2526 let result = node.send_packet(&dest, b"secret message");
2527 assert!(result.is_ok());
2528
2529 let packet_hash = result.unwrap();
2530 assert_ne!(packet_hash.0, [0u8; 32]);
2531
2532 thread::sleep(Duration::from_millis(50));
2533 node.shutdown();
2534 }
2535
2536 #[test]
2537 fn register_destination_with_proof_prove_all() {
2538 let node = RnsNode::start(
2539 NodeConfig {
2540 transport_enabled: false,
2541 identity: None,
2542 interfaces: vec![],
2543 share_instance: false,
2544 rpc_port: 0,
2545 cache_dir: None,
2546 management: Default::default(),
2547 probe_port: None,
2548 probe_addr: None,
2549 device: None,
2550 },
2551 Box::new(NoopCallbacks),
2552 ).unwrap();
2553
2554 let identity = Identity::new(&mut OsRng);
2555 let ih = rns_core::types::IdentityHash(*identity.hash());
2556 let dest = crate::destination::Destination::single_in("echo", &["request"], ih)
2557 .set_proof_strategy(rns_core::types::ProofStrategy::ProveAll);
2558 let prv_key = identity.get_private_key().unwrap();
2559
2560 let result = node.register_destination_with_proof(&dest, Some(prv_key));
2561 assert!(result.is_ok());
2562
2563 thread::sleep(Duration::from_millis(50));
2565
2566 node.shutdown();
2567 }
2568
2569 #[test]
2570 fn register_destination_with_proof_prove_none() {
2571 let node = RnsNode::start(
2572 NodeConfig {
2573 transport_enabled: false,
2574 identity: None,
2575 interfaces: vec![],
2576 share_instance: false,
2577 rpc_port: 0,
2578 cache_dir: None,
2579 management: Default::default(),
2580 probe_port: None,
2581 probe_addr: None,
2582 device: None,
2583 },
2584 Box::new(NoopCallbacks),
2585 ).unwrap();
2586
2587 let dest = crate::destination::Destination::plain("test", &["data"])
2589 .set_proof_strategy(rns_core::types::ProofStrategy::ProveNone);
2590
2591 let result = node.register_destination_with_proof(&dest, None);
2592 assert!(result.is_ok());
2593
2594 thread::sleep(Duration::from_millis(50));
2595 node.shutdown();
2596 }
2597}