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