diff --git a/core/src/service/network/core/mod.rs b/core/src/service/network/core/mod.rs index 5edae2bc2..7497ded37 100644 --- a/core/src/service/network/core/mod.rs +++ b/core/src/service/network/core/mod.rs @@ -213,40 +213,78 @@ impl NetworkingService { // - mDNS for local network discovery // - PkarrPublisher to publish our address to dns.iroh.link (enables remote discovery) // - DnsDiscovery to resolve other nodes from dns.iroh.link - let endpoint = Endpoint::builder() - .secret_key(secret_key) - .alpns(vec![ - PAIRING_ALPN.to_vec(), - FILE_TRANSFER_ALPN.to_vec(), - MESSAGING_ALPN.to_vec(), - SYNC_ALPN.to_vec(), - JOB_ACTIVITY_ALPN.to_vec(), - ]) - .relay_mode(iroh::RelayMode::Default) - .discovery(MdnsDiscovery::builder()) - .discovery(PkarrPublisher::n0_dns()) - .discovery(DnsDiscovery::n0_dns()) - .bind_addr_v4(std::net::SocketAddrV4::new( - std::net::Ipv4Addr::UNSPECIFIED, - 0, - )) - .bind_addr_v6(std::net::SocketAddrV6::new( - std::net::Ipv6Addr::UNSPECIFIED, - 0, - 0, - 0, - )) - .bind() - .await - .map_err(|e| NetworkingError::Transport(format!("Failed to create endpoint: {}", e)))?; + // + // mDNS is best-effort: on hosts where another service (e.g. avahi-daemon + // on most Linux boxes / TrueNAS) already owns UDP :5353, Iroh's own mDNS + // service can't bind and endpoint creation fails wholesale. Fall back to + // pkarr + DNS-only discovery in that case — remote pairing via node ID + // continues to work, we just lose local-network auto-discovery. + let build_endpoint = |with_mdns: bool| { + let mut builder = Endpoint::builder() + .secret_key(secret_key.clone()) + .alpns(vec![ + PAIRING_ALPN.to_vec(), + FILE_TRANSFER_ALPN.to_vec(), + MESSAGING_ALPN.to_vec(), + SYNC_ALPN.to_vec(), + JOB_ACTIVITY_ALPN.to_vec(), + ]) + .relay_mode(iroh::RelayMode::Default) + .discovery(PkarrPublisher::n0_dns()) + .discovery(DnsDiscovery::n0_dns()) + .bind_addr_v4(std::net::SocketAddrV4::new( + std::net::Ipv4Addr::UNSPECIFIED, + 0, + )) + .bind_addr_v6(std::net::SocketAddrV6::new( + std::net::Ipv6Addr::UNSPECIFIED, + 0, + 0, + 0, + )); + if with_mdns { + builder = builder.discovery(MdnsDiscovery::builder()); + } + builder.bind() + }; + + let endpoint = match build_endpoint(true).await { + Ok(ep) => { + self.logger + .info("Endpoint bound successfully with mDNS + pkarr discovery enabled") + .await; + ep + } + Err(e) => { + let err_str = e.to_string().to_lowercase(); + if err_str.contains("mdns") { + self.logger + .warn(&format!( + "mDNS discovery unavailable ({}); retrying with pkarr + DNS only. \ + Local-network auto-discovery is disabled on this host, but remote \ + pairing via node ID will still work.", + e + )) + .await; + let ep = build_endpoint(false).await.map_err(|e| { + NetworkingError::Transport(format!("Failed to create endpoint: {}", e)) + })?; + self.logger + .info("Endpoint bound successfully without mDNS (pkarr + DNS only)") + .await; + ep + } else { + return Err(NetworkingError::Transport(format!( + "Failed to create endpoint: {}", + e + ))); + } + } + }; // Store endpoint reference for other methods self.endpoint = Some(endpoint.clone()); - self.logger - .info("Endpoint bound successfully with mDNS + pkarr discovery enabled") - .await; - // Create and start event loop let event_loop = NetworkingEventLoop::new( endpoint,