1use super::*;
2
3impl Node {
4 fn new_packet_mover2_node() -> PacketMover2Node {
5 PacketMover2LiveNode::new(AdmissionConfig::new(1024, 4096))
6 }
7
8 pub fn new(config: Config) -> Result<Self, NodeError> {
10 config.validate()?;
11 let identity = config.create_identity()?;
12 let node_addr = *identity.node_addr();
13 let is_leaf_only = config.is_leaf_only();
14
15 let mut startup_epoch = [0u8; 8];
16 rand::rng().fill_bytes(&mut startup_epoch);
17
18 let mut bloom_state = if is_leaf_only {
19 BloomState::leaf_only(node_addr)
20 } else {
21 BloomState::new(node_addr)
22 };
23 bloom_state.set_update_debounce_ms(config.node.bloom.update_debounce_ms);
24
25 let tun_state = if config.tun.enabled {
26 TunState::Configured
27 } else {
28 TunState::Disabled
29 };
30
31 let mut tree_state = TreeState::new(node_addr);
33 tree_state.set_parent_hysteresis(config.node.tree.parent_hysteresis);
34 tree_state.set_hold_down(config.node.tree.hold_down_secs);
35 tree_state.set_flap_dampening(
36 config.node.tree.flap_threshold,
37 config.node.tree.flap_window_secs,
38 config.node.tree.flap_dampening_secs,
39 );
40 tree_state
41 .sign_declaration(&identity)
42 .expect("signing own declaration should never fail");
43
44 let coord_cache = CoordCache::new(
45 config.node.cache.coord_size,
46 config.node.cache.coord_ttl_secs * 1000,
47 );
48 let rl = &config.node.rate_limit;
49 let msg1_rate_limiter = HandshakeRateLimiter::with_params(
50 rate_limit::TokenBucket::with_params(rl.handshake_burst, rl.handshake_rate),
51 config.node.limits.max_pending_inbound,
52 );
53
54 let max_connections = config.node.limits.max_connections;
55 let max_peers = config.node.limits.max_peers;
56 let max_links = config.node.limits.max_links;
57 let coords_response_interval_ms = config.node.session.coords_response_interval_ms;
58 let backoff_base_secs = config.node.discovery.backoff_base_secs;
59 let backoff_max_secs = config.node.discovery.backoff_max_secs;
60 let forward_min_interval_secs = config.node.discovery.forward_min_interval_secs;
61
62 let (host_map, peer_acl) = Self::host_map_and_peer_acl(&config);
63 let configured_peer_send_weights = ConfiguredPeerSendWeights::from_config(&config);
64
65 Ok(Self {
66 identity,
67 startup_epoch,
68 started_at: std::time::Instant::now(),
69 config,
70 state: NodeState::Created,
71 is_leaf_only,
72 tree_state,
73 bloom_state,
74 coord_cache,
75 learned_routes: LearnedRouteTable::default(),
76 session_direct_degradation: SessionDirectDegradation::default(),
77 recent_requests: RecentDiscoveryRequests::default(),
78 transports: HashMap::new(),
79 udp_transport_resolution_cache: lifecycle::UdpTransportResolutionCache::default(),
80 transport_drops: TransportDropTracker::default(),
81 transport_socket_drops: TransportDropTracker::default(),
82 transport_namespace_drops: TransportDropTracker::default(),
83 links: LinkRegistry::default(),
84 packet_tx: None,
85 packet_rx: None,
86 packet_mover2: Self::new_packet_mover2_node(),
87 packet_mover2_fast_ingress_rx: None,
88 packet_mover2_transport_send_worker: Default::default(),
89 peers: PeerLifecycleRegistry::default(),
90 sessions: SessionRegistry::default(),
91 identity_cache: IdentityCache::default(),
92 pending_session_traffic: PendingSessionTrafficQueues::default(),
93 pending_lookups: handlers::discovery::PendingDiscoveryLookups::default(),
94 max_connections,
95 max_peers,
96 max_links,
97 next_link_id: 1,
98 next_transport_id: 1,
99 stats: stats::NodeStats::new(),
100 stats_history: stats_history::StatsHistory::new(),
101 tun_state,
102 tun_name: None,
103 tun_tx: None,
104 tun_outbound_rx: None,
105 external_packet_tx: None,
106 endpoint_control_rx: None,
107 endpoint_data_rx: None,
108 endpoint_events: EndpointEventRuntime::default(),
109 tun_reader_handle: None,
110 tun_writer_handle: None,
111 #[cfg(target_os = "macos")]
112 tun_shutdown_fd: None,
113 dns_identity_rx: None,
114 dns_task: None,
115 index_allocator: IndexAllocator::new(),
116 pending_outbound: PendingOutboundHandshakes::default(),
117 msg1_rate_limiter,
118 icmp_rate_limiter: IcmpRateLimiter::new(),
119 routing_error_rate_limiter: RoutingErrorRateLimiter::new(),
120 coords_response_rate_limiter: RoutingErrorRateLimiter::with_interval(
121 std::time::Duration::from_millis(coords_response_interval_ms),
122 ),
123 discovery_backoff: DiscoveryBackoff::with_params(backoff_base_secs, backoff_max_secs),
124 discovery_forward_limiter: DiscoveryForwardRateLimiter::with_interval(
125 std::time::Duration::from_secs(forward_min_interval_secs),
126 ),
127 pending_connects: Vec::new(),
128 retry_pending: retry::PendingRouteRetries::default(),
129 nostr_discovery: None,
130 nostr_discovery_started_at_ms: None,
131 lan_discovery: None,
132 local_instance_registry: None,
133 local_instance_started_at_ms: None,
134 last_local_instance_publish_ms: None,
135 last_local_instance_scan_ms: None,
136 startup_open_discovery_sweep_done: false,
137 bootstrap_transports: BootstrapTransports::default(),
138 discovery_fallback_transit: DiscoveryFallbackTransit::default(),
139 last_parent_reeval: None,
140 last_congestion_log: None,
141 estimated_mesh_size: None,
142 last_mesh_size_log: None,
143 last_self_warn: None,
144 local_send_failures: LocalSendFailures::default(),
145 last_rx_loop_maintenance_timeout_at: None,
146 peer_aliases: HashMap::new(),
147 configured_peer_send_weights,
148 peer_acl,
149 host_map,
150 path_mtu_lookup: Arc::new(std::sync::RwLock::new(HashMap::new())),
151 })
152 }
153
154 pub fn with_identity(identity: Identity, config: Config) -> Result<Self, NodeError> {
159 config.validate()?;
160 let node_addr = *identity.node_addr();
161
162 let mut startup_epoch = [0u8; 8];
163 rand::rng().fill_bytes(&mut startup_epoch);
164
165 let tun_state = if config.tun.enabled {
166 TunState::Configured
167 } else {
168 TunState::Disabled
169 };
170
171 let mut tree_state = TreeState::new(node_addr);
173 tree_state.set_parent_hysteresis(config.node.tree.parent_hysteresis);
174 tree_state.set_hold_down(config.node.tree.hold_down_secs);
175 tree_state.set_flap_dampening(
176 config.node.tree.flap_threshold,
177 config.node.tree.flap_window_secs,
178 config.node.tree.flap_dampening_secs,
179 );
180 tree_state
181 .sign_declaration(&identity)
182 .expect("signing own declaration should never fail");
183
184 let mut bloom_state = BloomState::new(node_addr);
185 bloom_state.set_update_debounce_ms(config.node.bloom.update_debounce_ms);
186
187 let coord_cache = CoordCache::new(
188 config.node.cache.coord_size,
189 config.node.cache.coord_ttl_secs * 1000,
190 );
191 let rl = &config.node.rate_limit;
192 let msg1_rate_limiter = HandshakeRateLimiter::with_params(
193 rate_limit::TokenBucket::with_params(rl.handshake_burst, rl.handshake_rate),
194 config.node.limits.max_pending_inbound,
195 );
196
197 let max_connections = config.node.limits.max_connections;
198 let max_peers = config.node.limits.max_peers;
199 let max_links = config.node.limits.max_links;
200 let coords_response_interval_ms = config.node.session.coords_response_interval_ms;
201
202 let (host_map, peer_acl) = Self::host_map_and_peer_acl(&config);
203 let configured_peer_send_weights = ConfiguredPeerSendWeights::from_config(&config);
204
205 Ok(Self {
206 identity,
207 startup_epoch,
208 started_at: std::time::Instant::now(),
209 config,
210 state: NodeState::Created,
211 is_leaf_only: false,
212 tree_state,
213 bloom_state,
214 coord_cache,
215 learned_routes: LearnedRouteTable::default(),
216 session_direct_degradation: SessionDirectDegradation::default(),
217 recent_requests: RecentDiscoveryRequests::default(),
218 transports: HashMap::new(),
219 udp_transport_resolution_cache: lifecycle::UdpTransportResolutionCache::default(),
220 transport_drops: TransportDropTracker::default(),
221 transport_socket_drops: TransportDropTracker::default(),
222 transport_namespace_drops: TransportDropTracker::default(),
223 links: LinkRegistry::default(),
224 packet_tx: None,
225 packet_rx: None,
226 packet_mover2: Self::new_packet_mover2_node(),
227 packet_mover2_fast_ingress_rx: None,
228 packet_mover2_transport_send_worker: Default::default(),
229 peers: PeerLifecycleRegistry::default(),
230 sessions: SessionRegistry::default(),
231 identity_cache: IdentityCache::default(),
232 pending_session_traffic: PendingSessionTrafficQueues::default(),
233 pending_lookups: handlers::discovery::PendingDiscoveryLookups::default(),
234 max_connections,
235 max_peers,
236 max_links,
237 next_link_id: 1,
238 next_transport_id: 1,
239 stats: stats::NodeStats::new(),
240 stats_history: stats_history::StatsHistory::new(),
241 tun_state,
242 tun_name: None,
243 tun_tx: None,
244 tun_outbound_rx: None,
245 external_packet_tx: None,
246 endpoint_control_rx: None,
247 endpoint_data_rx: None,
248 endpoint_events: EndpointEventRuntime::default(),
249 tun_reader_handle: None,
250 tun_writer_handle: None,
251 #[cfg(target_os = "macos")]
252 tun_shutdown_fd: None,
253 dns_identity_rx: None,
254 dns_task: None,
255 index_allocator: IndexAllocator::new(),
256 pending_outbound: PendingOutboundHandshakes::default(),
257 msg1_rate_limiter,
258 icmp_rate_limiter: IcmpRateLimiter::new(),
259 routing_error_rate_limiter: RoutingErrorRateLimiter::new(),
260 coords_response_rate_limiter: RoutingErrorRateLimiter::with_interval(
261 std::time::Duration::from_millis(coords_response_interval_ms),
262 ),
263 discovery_backoff: DiscoveryBackoff::new(),
264 discovery_forward_limiter: DiscoveryForwardRateLimiter::new(),
265 pending_connects: Vec::new(),
266 retry_pending: retry::PendingRouteRetries::default(),
267 nostr_discovery: None,
268 nostr_discovery_started_at_ms: None,
269 lan_discovery: None,
270 local_instance_registry: None,
271 local_instance_started_at_ms: None,
272 last_local_instance_publish_ms: None,
273 last_local_instance_scan_ms: None,
274 startup_open_discovery_sweep_done: false,
275 bootstrap_transports: BootstrapTransports::default(),
276 discovery_fallback_transit: DiscoveryFallbackTransit::default(),
277 last_parent_reeval: None,
278 last_congestion_log: None,
279 estimated_mesh_size: None,
280 last_mesh_size_log: None,
281 last_self_warn: None,
282 local_send_failures: LocalSendFailures::default(),
283 last_rx_loop_maintenance_timeout_at: None,
284 peer_aliases: HashMap::new(),
285 configured_peer_send_weights,
286 peer_acl,
287 host_map,
288 path_mtu_lookup: Arc::new(std::sync::RwLock::new(HashMap::new())),
289 })
290 }
291
292 pub fn leaf_only(config: Config) -> Result<Self, NodeError> {
294 let mut node = Self::new(config)?;
295 node.is_leaf_only = true;
296 node.bloom_state = BloomState::leaf_only(*node.identity.node_addr());
297 Ok(node)
298 }
299
300 pub(super) fn host_map_and_peer_acl(config: &Config) -> (Arc<HostMap>, acl::PeerAclReloader) {
301 let base_host_map = HostMap::from_peer_configs(config.peers());
302 if !config.node.system_files_enabled {
303 return (
304 Arc::new(base_host_map.clone()),
305 acl::PeerAclReloader::memory_only(base_host_map),
306 );
307 }
308
309 let mut host_map = base_host_map.clone();
310 let hosts_path = std::path::PathBuf::from(crate::upper::hosts::DEFAULT_HOSTS_PATH);
311 let hosts_file = HostMap::load_hosts_file(std::path::Path::new(
312 crate::upper::hosts::DEFAULT_HOSTS_PATH,
313 ));
314 host_map.merge(hosts_file);
315 let peer_acl = acl::PeerAclReloader::with_alias_sources(
316 std::path::PathBuf::from(acl::DEFAULT_PEERS_ALLOW_PATH),
317 std::path::PathBuf::from(acl::DEFAULT_PEERS_DENY_PATH),
318 base_host_map,
319 hosts_path,
320 );
321 (Arc::new(host_map), peer_acl)
322 }
323
324 pub(super) async fn create_transports(&mut self, packet_tx: &PacketTx) -> Vec<TransportHandle> {
328 let mut transports = Vec::new();
329
330 let udp_instances: Vec<_> = self
332 .config
333 .transports
334 .udp
335 .iter()
336 .map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
337 .collect();
338
339 for (name, udp_config) in udp_instances {
341 let transport_id = self.allocate_transport_id();
342 let udp = UdpTransport::new(transport_id, name, udp_config, packet_tx.clone());
343 transports.push(TransportHandle::Udp(udp));
344 }
345
346 #[cfg(feature = "sim-transport")]
347 {
348 let sim_instances: Vec<_> = self
349 .config
350 .transports
351 .sim
352 .iter()
353 .map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
354 .collect();
355
356 for (name, sim_config) in sim_instances {
357 let transport_id = self.allocate_transport_id();
358 let sim = crate::transport::sim::SimTransport::new(
359 transport_id,
360 name,
361 sim_config,
362 packet_tx.clone(),
363 );
364 transports.push(TransportHandle::Sim(sim));
365 }
366 }
367
368 #[cfg(any(target_os = "linux", target_os = "macos"))]
370 {
371 let eth_instances: Vec<_> = self
372 .config
373 .transports
374 .ethernet
375 .iter()
376 .map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
377 .collect();
378 let xonly = self.identity.pubkey();
379 for (name, eth_config) in eth_instances {
380 let mut eth_config = eth_config;
381 if eth_config.discovery_scope.is_none() {
382 eth_config.discovery_scope = self.lan_discovery_scope();
383 }
384 let transport_id = self.allocate_transport_id();
385 let mut eth =
386 EthernetTransport::new(transport_id, name, eth_config, packet_tx.clone());
387 eth.set_local_pubkey(xonly);
388 transports.push(TransportHandle::Ethernet(eth));
389 }
390 }
391
392 let tcp_instances: Vec<_> = self
394 .config
395 .transports
396 .tcp
397 .iter()
398 .map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
399 .collect();
400
401 for (name, tcp_config) in tcp_instances {
402 let transport_id = self.allocate_transport_id();
403 let tcp = TcpTransport::new(transport_id, name, tcp_config, packet_tx.clone());
404 transports.push(TransportHandle::Tcp(tcp));
405 }
406
407 let tor_instances: Vec<_> = self
409 .config
410 .transports
411 .tor
412 .iter()
413 .map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
414 .collect();
415
416 for (name, tor_config) in tor_instances {
417 let transport_id = self.allocate_transport_id();
418 let tor = TorTransport::new(transport_id, name, tor_config, packet_tx.clone());
419 transports.push(TransportHandle::Tor(tor));
420 }
421
422 let webrtc_instances: Vec<_> = self
423 .config
424 .transports
425 .webrtc
426 .iter()
427 .map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
428 .collect();
429
430 #[cfg(feature = "webrtc-transport")]
431 {
432 for (name, webrtc_config) in webrtc_instances {
433 let transport_id = self.allocate_transport_id();
434 match WebRtcTransport::new(
435 transport_id,
436 name,
437 webrtc_config,
438 packet_tx.clone(),
439 &self.identity,
440 &self.config.node.discovery.nostr,
441 ) {
442 Ok(webrtc) => transports.push(TransportHandle::WebRtc(Box::new(webrtc))),
443 Err(err) => {
444 warn!(
445 transport_id = %transport_id,
446 error = %err,
447 "failed to initialize WebRTC transport"
448 );
449 }
450 }
451 }
452 }
453 #[cfg(not(feature = "webrtc-transport"))]
454 if !webrtc_instances.is_empty() {
455 warn!("WebRTC transport configured but this build lacks WebRTC transport support");
456 }
457
458 #[cfg(bluer_available)]
460 {
461 let ble_instances: Vec<_> = self
462 .config
463 .transports
464 .ble
465 .iter()
466 .map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
467 .collect();
468
469 #[cfg(all(bluer_available, not(test)))]
470 for (name, ble_config) in ble_instances {
471 let transport_id = self.allocate_transport_id();
472 let adapter = ble_config.adapter().to_string();
473 let mtu = ble_config.mtu();
474 match crate::transport::ble::io::BluerIo::new(&adapter, mtu).await {
475 Ok(io) => {
476 let mut ble = crate::transport::ble::BleTransport::new(
477 transport_id,
478 name,
479 ble_config,
480 io,
481 packet_tx.clone(),
482 );
483 ble.set_local_pubkey(self.identity.pubkey().serialize());
484 transports.push(TransportHandle::Ble(ble));
485 }
486 Err(e) => {
487 tracing::warn!(adapter = %adapter, error = %e, "failed to initialize BLE adapter");
488 }
489 }
490 }
491
492 #[cfg(any(not(bluer_available), test))]
493 if !ble_instances.is_empty() {
494 #[cfg(not(test))]
495 tracing::warn!("BLE transport configured but this build lacks BlueZ support");
496 }
497 }
498
499 transports
500 }
501
502 pub(super) fn find_transport_for_type(&self, transport_type: &str) -> Option<TransportId> {
512 self.transports
513 .iter()
514 .filter(|(id, handle)| {
515 handle.transport_type().name == transport_type
516 && handle.is_operational()
517 && !self.bootstrap_transports.contains(id)
518 })
519 .min_by_key(|(id, _)| id.as_u32())
520 .map(|(id, _)| *id)
521 }
522
523 #[allow(unused_variables)]
529 pub(super) fn resolve_ethernet_addr(
530 &self,
531 addr_str: &str,
532 ) -> Result<(TransportId, TransportAddr), NodeError> {
533 #[cfg(any(target_os = "linux", target_os = "macos"))]
534 {
535 let (iface, mac_str) = addr_str.split_once('/').ok_or_else(|| {
536 NodeError::NoTransportForType(format!(
537 "invalid Ethernet address format '{}': expected 'interface/mac'",
538 addr_str
539 ))
540 })?;
541
542 let transport_id = self
544 .transports
545 .iter()
546 .find(|(_, handle)| {
547 handle.transport_type().name == "ethernet"
548 && handle.is_operational()
549 && handle.interface_name() == Some(iface)
550 })
551 .map(|(id, _)| *id)
552 .ok_or_else(|| {
553 NodeError::NoTransportForType(format!(
554 "no operational Ethernet transport for interface '{}'",
555 iface
556 ))
557 })?;
558
559 let mac = crate::transport::ethernet::parse_mac_string(mac_str).map_err(|e| {
560 NodeError::NoTransportForType(format!("invalid MAC in '{}': {}", addr_str, e))
561 })?;
562
563 Ok((transport_id, TransportAddr::from_bytes(&mac)))
564 }
565 #[cfg(not(any(target_os = "linux", target_os = "macos")))]
566 {
567 Err(NodeError::NoTransportForType(
568 "Ethernet transport is not supported on this platform".to_string(),
569 ))
570 }
571 }
572
573 #[cfg(bluer_available)]
577 pub(super) fn resolve_ble_addr(
578 &self,
579 addr_str: &str,
580 ) -> Result<(TransportId, TransportAddr), NodeError> {
581 let ta = TransportAddr::from_string(addr_str);
582 let adapter = crate::transport::ble::addr::adapter_from_addr(&ta).ok_or_else(|| {
583 NodeError::NoTransportForType(format!(
584 "invalid BLE address format '{}': expected 'adapter/mac'",
585 addr_str
586 ))
587 })?;
588
589 let transport_id = self
591 .transports
592 .iter()
593 .find(|(_, handle)| handle.transport_type().name == "ble" && handle.is_operational())
594 .map(|(id, _)| *id)
595 .ok_or_else(|| {
596 NodeError::NoTransportForType(format!(
597 "no operational BLE transport for adapter '{}'",
598 adapter
599 ))
600 })?;
601
602 crate::transport::ble::addr::BleAddr::parse(addr_str).map_err(|e| {
604 NodeError::NoTransportForType(format!("invalid BLE address '{}': {}", addr_str, e))
605 })?;
606
607 Ok((transport_id, TransportAddr::from_string(addr_str)))
608 }
609}