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