@@ -275,10 +275,41 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> { |
| 275 | let peers: Arc<RwLock<HashMap<Direction, network::FramedConnection>>> = | 275 | let peers: Arc<RwLock<HashMap<Direction, network::FramedConnection>>> = |
| 276 | Arc::new(RwLock::new(HashMap::new())); | 276 | Arc::new(RwLock::new(HashMap::new())); |
| 277 | | 277 | |
| | 278 | + // TLS setup (if enabled) |
| | 279 | + let tls_enabled = config.network.tls.enabled; |
| | 280 | + if tls_enabled { |
| | 281 | + info!("TLS is enabled, ensuring certificates exist..."); |
| | 282 | + let cert_path = std::path::Path::new(&config.network.tls.cert_path); |
| | 283 | + let key_path = std::path::Path::new(&config.network.tls.key_path); |
| | 284 | + |
| | 285 | + if let Err(e) = network::ensure_certificate(cert_path, key_path, &config.machines.self_name) { |
| | 286 | + anyhow::bail!("Failed to setup TLS certificates: {}", e); |
| | 287 | + } |
| | 288 | + |
| | 289 | + // Print certificate fingerprint for users to share |
| | 290 | + match network::get_cert_fingerprint(cert_path) { |
| | 291 | + Ok(fp) => { |
| | 292 | + info!("Certificate fingerprint: {}", fp); |
| | 293 | + info!("Share this fingerprint with peers for secure verification"); |
| | 294 | + } |
| | 295 | + Err(e) => { |
| | 296 | + tracing::warn!("Could not read certificate fingerprint: {}", e); |
| | 297 | + } |
| | 298 | + } |
| | 299 | + } else { |
| | 300 | + info!("TLS is disabled (plain TCP mode for backwards compatibility)"); |
| | 301 | + } |
| | 302 | + |
| 278 | // Start network server | 303 | // Start network server |
| 279 | let listen_addr: SocketAddr = format!("0.0.0.0:{}", config.network.listen_port).parse()?; | 304 | let listen_addr: SocketAddr = format!("0.0.0.0:{}", config.network.listen_port).parse()?; |
| 280 | - let server = network::Server::bind(listen_addr).await?; | 305 | + let server = if tls_enabled { |
| 281 | - info!("Listening for connections on {}", server.local_addr()); | 306 | + let cert_path = std::path::Path::new(&config.network.tls.cert_path); |
| | 307 | + let key_path = std::path::Path::new(&config.network.tls.key_path); |
| | 308 | + network::Server::bind_tls(listen_addr, cert_path, key_path).await? |
| | 309 | + } else { |
| | 310 | + network::Server::bind(listen_addr).await? |
| | 311 | + }; |
| | 312 | + info!("Listening for connections on {} (TLS: {})", server.local_addr(), tls_enabled); |
| 282 | | 313 | |
| 283 | // Spawn task to accept incoming connections | 314 | // Spawn task to accept incoming connections |
| 284 | let machine_name = config.machines.self_name.clone(); | 315 | let machine_name = config.machines.self_name.clone(); |
@@ -355,6 +386,13 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> { |
| 355 | let direction = neighbor.direction; | 386 | let direction = neighbor.direction; |
| 356 | let peers_clone = peers.clone(); | 387 | let peers_clone = peers.clone(); |
| 357 | let machine_name = config.machines.self_name.clone(); | 388 | let machine_name = config.machines.self_name.clone(); |
| | 389 | + let neighbor_name = neighbor.name.clone(); |
| | 390 | + |
| | 391 | + // Determine if TLS should be used for this neighbor |
| | 392 | + // Per-neighbor override takes precedence over global setting |
| | 393 | + let use_tls = neighbor.tls.unwrap_or(tls_enabled); |
| | 394 | + let fingerprint = neighbor.fingerprint.clone(); |
| | 395 | + let tofu_enabled = config.network.tls.tofu; |
| 358 | | 396 | |
| 359 | tokio::spawn(async move { | 397 | tokio::spawn(async move { |
| 360 | loop { | 398 | loop { |
@@ -369,8 +407,21 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> { |
| 369 | } | 407 | } |
| 370 | } | 408 | } |
| 371 | | 409 | |
| 372 | - tracing::debug!("Connecting to {} at {}...", direction, addr); | 410 | + tracing::debug!("Connecting to {} at {} (TLS: {})...", direction, addr, use_tls); |
| 373 | - match network::connect(addr).await { | 411 | + |
| | 412 | + // Connect with or without TLS |
| | 413 | + let conn_result = if use_tls { |
| | 414 | + network::connect_tls( |
| | 415 | + addr, |
| | 416 | + &neighbor_name, |
| | 417 | + fingerprint.as_deref(), |
| | 418 | + tofu_enabled, |
| | 419 | + ).await |
| | 420 | + } else { |
| | 421 | + network::connect(addr).await |
| | 422 | + }; |
| | 423 | + |
| | 424 | + match conn_result { |
| 374 | Ok(mut conn) => { | 425 | Ok(mut conn) => { |
| 375 | // Send Hello | 426 | // Send Hello |
| 376 | let hello = Message::Hello(HelloPayload { | 427 | let hello = Message::Hello(HelloPayload { |
@@ -1695,8 +1746,21 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> { |
| 1695 | let peers_clone = peers.clone(); | 1746 | let peers_clone = peers.clone(); |
| 1696 | let machine_name = config.machines.self_name.clone(); | 1747 | let machine_name = config.machines.self_name.clone(); |
| 1697 | let neighbor_name = n.name.clone(); | 1748 | let neighbor_name = n.name.clone(); |
| | 1749 | + |
| | 1750 | + // Determine TLS settings for this neighbor |
| | 1751 | + let use_tls = n.tls.unwrap_or(tls_enabled); |
| | 1752 | + let fingerprint = n.fingerprint.clone(); |
| | 1753 | + let tofu = config.network.tls.tofu; |
| | 1754 | + |
| 1698 | tokio::spawn(async move { | 1755 | tokio::spawn(async move { |
| 1699 | - match network::connect(addr).await { | 1756 | + // Connect with or without TLS |
| | 1757 | + let conn_result = if use_tls { |
| | 1758 | + network::connect_tls(addr, &neighbor_name, fingerprint.as_deref(), tofu).await |
| | 1759 | + } else { |
| | 1760 | + network::connect(addr).await |
| | 1761 | + }; |
| | 1762 | + |
| | 1763 | + match conn_result { |
| 1700 | Ok(mut conn) => { | 1764 | Ok(mut conn) => { |
| 1701 | // Send Hello | 1765 | // Send Hello |
| 1702 | let hello = Message::Hello(HelloPayload { | 1766 | let hello = Message::Hello(HelloPayload { |