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