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