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