diff --git a/CHANGELOG.md b/CHANGELOG.md index 16daaa7..2daed37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -197,6 +197,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Nostr-mediated overlay discovery is now always-on. The + `nostr-discovery` cargo feature flag has been dropped along with the + `optional = true` markers on `nostr` / `nostr-sdk` dependencies and + every `#[cfg(feature = "nostr-discovery")]` source-level gate. Plain + `cargo build` produces a binary with overlay discovery available + whether or not the operator enables it via + `node.discovery.nostr.enabled`. Mirrors PR #79's collapse of the + `tui` / `ble` / `gateway` features in favor of platform cfg gates. + No runtime behavior change — the feature was in `default` already - MMP link-layer report intervals retuned for constrained transports: steady-state floor raised from 100ms to 1000ms, ceiling from 2000ms to 5000ms. Cold-start uses a 200ms floor for the first 5 SRTT samples diff --git a/Cargo.toml b/Cargo.toml index e1b718a..ca24947 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,6 @@ authors = ["Johnathan Corgan "] repository = "https://github.com/jmcorgan/fips" readme = "README.md" -[features] -default = ["nostr-discovery"] -nostr-discovery = ["dep:nostr", "dep:nostr-sdk"] - [dependencies] ratatui = "0.30" secp256k1 = { version = "0.30", features = ["rand", "global-context"] } @@ -36,8 +32,8 @@ socket2 = { version = "0.6.2", features = ["all"] } tokio-socks = "0.5" portable-atomic = { version = "1", features = ["std"] } -nostr = { version = "0.44", features = ["std", "nip59"], optional = true } -nostr-sdk = { version = "0.44", optional = true } +nostr = { version = "0.44", features = ["std", "nip59"] } +nostr-sdk = "0.44" [target.'cfg(unix)'.dependencies] tun = { version = "0.8.5", features = ["async"] } diff --git a/packaging/common/fips.yaml b/packaging/common/fips.yaml index a3b8b3c..0f730ef 100644 --- a/packaging/common/fips.yaml +++ b/packaging/common/fips.yaml @@ -12,7 +12,6 @@ node: # nsec: "nsec1..." discovery: # Optional Nostr-mediated overlay endpoint discovery. - # Requires a build of fips compiled with the 'nostr-discovery' feature. # nostr: # enabled: true # policy: configured_only # disabled | configured_only | open diff --git a/packaging/openwrt-ipk/Makefile b/packaging/openwrt-ipk/Makefile index 8dc74c7..d8f45da 100644 --- a/packaging/openwrt-ipk/Makefile +++ b/packaging/openwrt-ipk/Makefile @@ -82,7 +82,6 @@ define Build/Compile cargo build \ --release \ --target $(RUST_TARGET) \ - --features gateway \ --bin fips \ --bin fipsctl \ --bin fipstop \ diff --git a/src/bin/fips-gateway.rs b/src/bin/fips-gateway.rs index 1fa1132..7d8bc83 100644 --- a/src/bin/fips-gateway.rs +++ b/src/bin/fips-gateway.rs @@ -242,10 +242,7 @@ async fn main() { last_failure = Some(format!("recv_from failed: {}", e)); } Err(_) => { - last_failure = Some(format!( - "no response within {}s", - PROBE_TIMEOUT_SECS - )); + last_failure = Some(format!("no response within {}s", PROBE_TIMEOUT_SECS)); } } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 3adbda2..60925ea 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -71,10 +71,7 @@ fn is_loopback_addr_str(addr: &str) -> bool { Some((h, _)) => h, None => addr, }; - host == "localhost" - || host == "::1" - || host == "0:0:0:0:0:0:0:1" - || host.starts_with("127.") + host == "localhost" || host == "::1" || host == "0:0:0:0:0:0:0:1" || host.starts_with("127.") } /// Derive the key file path from a config file path. diff --git a/src/discovery.rs b/src/discovery.rs index 290d023..2d86d22 100644 --- a/src/discovery.rs +++ b/src/discovery.rs @@ -6,7 +6,6 @@ //! it hands the live socket and selected remote endpoint to FIPS so the //! existing Noise/FMP transport path can take over. -#[cfg(feature = "nostr-discovery")] pub mod nostr; use crate::config::UdpConfig; @@ -16,9 +15,9 @@ use std::net::{SocketAddr, UdpSocket}; /// Punch-probe magic ("NPTC", network byte order). First byte `0x4E` /// collides with FMP's prefix-version high-nibble check, so the UDP /// transport silently filters packets carrying this magic to keep -/// post-adoption handshake logs clean. Defined here (unconditionally -/// compiled) rather than inside the `nostr-discovery`-gated submodule so -/// the filter applies regardless of feature configuration. +/// post-adoption handshake logs clean. Defined at the top-level +/// `discovery` module so the UDP filter and the nostr submodule's +/// punch sender share the same constant. pub const PUNCH_MAGIC: u32 = 0x4E505443; /// Punch-probe-ack magic ("NPTA", network byte order). Same filter as diff --git a/src/discovery/nostr/mod.rs b/src/discovery/nostr/mod.rs index fcae598..c08f6f0 100644 --- a/src/discovery/nostr/mod.rs +++ b/src/discovery/nostr/mod.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "nostr-discovery")] - mod runtime; mod signal; mod stun; diff --git a/src/discovery/nostr/runtime.rs b/src/discovery/nostr/runtime.rs index b577181..7aa1245 100644 --- a/src/discovery/nostr/runtime.rs +++ b/src/discovery/nostr/runtime.rs @@ -829,12 +829,12 @@ impl NostrDiscovery { advert: Option<&OverlayAdvert>, ) -> Result, BootstrapError> { let mut merged = self.find_recipient_inbox_relays(target_pubkey).await?; - if let Some(advert) = advert { - if let Some(relays) = advert.signal_relays.as_ref() { - for relay in relays { - if !merged.contains(relay) { - merged.push(relay.clone()); - } + if let Some(advert) = advert + && let Some(relays) = advert.signal_relays.as_ref() + { + for relay in relays { + if !merged.contains(relay) { + merged.push(relay.clone()); } } } diff --git a/src/discovery/nostr/stun.rs b/src/discovery/nostr/stun.rs index 7225428..b4fcd89 100644 --- a/src/discovery/nostr/stun.rs +++ b/src/discovery/nostr/stun.rs @@ -268,8 +268,8 @@ fn private_interface_ips() -> Vec { // SAFETY: `cursor` points at a valid node from the `getifaddrs` list. let entry = unsafe { &*cursor }; let flags = entry.ifa_flags as i32; - let is_up = (flags & libc::IFF_UP as i32) != 0; - let is_loopback = (flags & libc::IFF_LOOPBACK as i32) != 0; + let is_up = (flags & libc::IFF_UP) != 0; + let is_loopback = (flags & libc::IFF_LOOPBACK) != 0; if is_up && !is_loopback && !entry.ifa_addr.is_null() { // SAFETY: `ifa_addr` is non-null and its concrete type matches diff --git a/src/discovery/nostr/types.rs b/src/discovery/nostr/types.rs index 4a5ece3..592444e 100644 --- a/src/discovery/nostr/types.rs +++ b/src/discovery/nostr/types.rs @@ -6,8 +6,8 @@ pub const ADVERT_KIND: u16 = 37195; pub const ADVERT_IDENTIFIER: &str = "fips-overlay-v1"; pub const ADVERT_VERSION: u32 = 1; pub const SIGNAL_KIND: u16 = 21059; -// Re-exported from `crate::discovery` so the UDP transport's stray-probe -// filter compiles regardless of the `nostr-discovery` cargo feature. +// Defined at the top-level `discovery` module; re-exported here so the +// existing punch sender / receiver imports remain unchanged. pub use crate::discovery::{PUNCH_ACK_MAGIC, PUNCH_MAGIC}; pub const PROTOCOL_VERSION: &str = "1"; diff --git a/src/node/handlers/rx_loop.rs b/src/node/handlers/rx_loop.rs index 334055a..082a234 100644 --- a/src/node/handlers/rx_loop.rs +++ b/src/node/handlers/rx_loop.rs @@ -115,7 +115,6 @@ impl Node { let now_ms = Self::now_ms(); self.reload_peer_acl(); self.poll_pending_connects().await; - #[cfg(feature = "nostr-discovery")] self.poll_nostr_discovery().await; self.resend_pending_handshakes(now_ms).await; self.resend_pending_rekeys(now_ms).await; diff --git a/src/node/lifecycle.rs b/src/node/lifecycle.rs index defc039..660988a 100644 --- a/src/node/lifecycle.rs +++ b/src/node/lifecycle.rs @@ -2,7 +2,6 @@ use super::{Node, NodeError, NodeState}; use crate::config::{ConnectPolicy, PeerAddress, PeerConfig}; -#[cfg(feature = "nostr-discovery")] use crate::discovery::nostr::{ ADVERT_IDENTIFIER, ADVERT_VERSION, BootstrapEvent, NostrDiscovery, OverlayAdvert, OverlayEndpointAdvert, OverlayTransportKind, @@ -15,13 +14,11 @@ use crate::protocol::{Disconnect, DisconnectReason}; use crate::transport::{Link, LinkDirection, LinkId, TransportAddr, TransportId, packet_channel}; use crate::upper::tun::{TunDevice, TunState, run_tun_reader, shutdown_tun_interface}; use crate::{NodeAddr, PeerIdentity}; -#[cfg(feature = "nostr-discovery")] use std::collections::HashSet; use std::thread; use std::time::Duration; use tracing::{debug, info, warn}; -#[cfg(feature = "nostr-discovery")] const OPEN_DISCOVERY_RETRY_LIFETIME_MULTIPLIER: u64 = 2; impl Node { @@ -381,7 +378,6 @@ impl Node { } } - #[cfg(feature = "nostr-discovery")] pub(super) async fn poll_nostr_discovery(&mut self) { let Some(bootstrap) = self.nostr_discovery.clone() else { return; @@ -569,7 +565,6 @@ impl Node { info!(count = self.transports.len(), "Transports initialized"); } - #[cfg(feature = "nostr-discovery")] if self.config.node.discovery.nostr.enabled { match NostrDiscovery::start(&self.identity, self.config.node.discovery.nostr.clone()) .await @@ -587,13 +582,6 @@ impl Node { } } - #[cfg(not(feature = "nostr-discovery"))] - if self.config.node.discovery.nostr.enabled { - warn!( - "Nostr overlay discovery configured but this build was compiled without the 'nostr-discovery' feature" - ); - } - // Connect to static peers before TUN is active // This allows handshake messages to be sent before we start accepting packets self.initiate_peer_connections().await; @@ -867,7 +855,6 @@ impl Node { .await; // Stop Nostr overlay discovery background work and withdraw any advert. - #[cfg(feature = "nostr-discovery")] if let Some(bootstrap) = self.nostr_discovery.take() && let Err(e) = bootstrap.shutdown().await { @@ -989,7 +976,6 @@ impl Node { .collect() } - #[cfg(feature = "nostr-discovery")] async fn nostr_peer_fallback_addresses( &self, peer_config: &PeerConfig, @@ -1045,7 +1031,6 @@ impl Node { fallback } - #[cfg(feature = "nostr-discovery")] fn overlay_endpoint_to_peer_address( endpoint: &OverlayEndpointAdvert, priority: u8, @@ -1074,21 +1059,13 @@ impl Node { if !allow_bootstrap_nat { continue; } - #[cfg(not(feature = "nostr-discovery"))] - { - debug!(npub = %peer_config.npub, "Skipping udp:nat address because this build does not include the nostr-discovery feature"); + let Some(bootstrap) = self.nostr_discovery.clone() else { + debug!(npub = %peer_config.npub, "No Nostr overlay runtime for udp:nat address"); continue; - } - #[cfg(feature = "nostr-discovery")] - { - let Some(bootstrap) = self.nostr_discovery.clone() else { - debug!(npub = %peer_config.npub, "No Nostr overlay runtime for udp:nat address"); - continue; - }; - bootstrap.request_connect(peer_config.clone()).await; - info!(npub = %peer_config.npub, "Started Nostr UDP NAT traversal attempt"); - return Ok(()); - } + }; + bootstrap.request_connect(peer_config.clone()).await; + info!(npub = %peer_config.npub, "Started Nostr UDP NAT traversal attempt"); + return Ok(()); } let (transport_id, remote_addr) = if addr.transport == "ethernet" { @@ -1163,7 +1140,6 @@ impl Node { ))) } - #[cfg(feature = "nostr-discovery")] async fn queue_open_discovery_retries(&mut self, bootstrap: &std::sync::Arc) { if !self.config.node.discovery.nostr.enabled || self.config.node.discovery.nostr.policy != crate::config::NostrDiscoveryPolicy::Open @@ -1251,7 +1227,6 @@ impl Node { } } - #[cfg(feature = "nostr-discovery")] fn available_outbound_slots(&self) -> usize { let connection_used = self .connections @@ -1272,7 +1247,6 @@ impl Node { connection_slots.min(peer_slots) } - #[cfg(feature = "nostr-discovery")] fn open_discovery_enqueue_budget(&self, configured_npubs: &HashSet) -> usize { let current_open_discovery_pending = self .retry_pending @@ -1291,7 +1265,6 @@ impl Node { cap_remaining.min(self.available_outbound_slots()) } - #[cfg(feature = "nostr-discovery")] fn open_discovery_retry_expires_at_ms(&self, now_ms: u64) -> u64 { now_ms.saturating_add( self.config @@ -1304,7 +1277,6 @@ impl Node { ) } - #[cfg(feature = "nostr-discovery")] fn build_overlay_advert(&self) -> Option { if !self.config.node.discovery.nostr.enabled { return None; @@ -1391,7 +1363,6 @@ impl Node { }) } - #[cfg(feature = "nostr-discovery")] async fn refresh_overlay_advert( &self, bootstrap: &std::sync::Arc, @@ -1400,7 +1371,6 @@ impl Node { bootstrap.update_local_advert(advert).await } - #[cfg(feature = "nostr-discovery")] fn lookup_udp_config(&self, transport_name: Option<&str>) -> Option<&crate::config::UdpConfig> { match (&self.config.transports.udp, transport_name) { (crate::config::TransportInstances::Single(cfg), None) => Some(cfg), @@ -1409,7 +1379,6 @@ impl Node { } } - #[cfg(feature = "nostr-discovery")] fn lookup_tcp_config(&self, transport_name: Option<&str>) -> Option<&crate::config::TcpConfig> { match (&self.config.transports.tcp, transport_name) { (crate::config::TransportInstances::Single(cfg), None) => Some(cfg), @@ -1418,7 +1387,6 @@ impl Node { } } - #[cfg(feature = "nostr-discovery")] fn lookup_tor_config(&self, transport_name: Option<&str>) -> Option<&crate::config::TorConfig> { match (&self.config.transports.tor, transport_name) { (crate::config::TransportInstances::Single(cfg), None) => Some(cfg), @@ -1449,7 +1417,6 @@ impl Node { return Ok(()); } - #[cfg(feature = "nostr-discovery")] { let fallback = self .nostr_peer_fallback_addresses(peer_config, &static_addresses) diff --git a/src/node/mod.rs b/src/node/mod.rs index 6467d3a..e20f0f0 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -431,7 +431,6 @@ pub struct Node { retry_pending: HashMap, /// Optional Nostr/STUN overlay discovery coordinator for `udp:nat` peers. - #[cfg(feature = "nostr-discovery")] nostr_discovery: Option>, /// Per-peer UDP transports adopted from NAT traversal handoff. bootstrap_transports: HashSet, @@ -596,7 +595,6 @@ impl Node { ), pending_connects: Vec::new(), retry_pending: HashMap::new(), - #[cfg(feature = "nostr-discovery")] nostr_discovery: None, bootstrap_transports: HashSet::new(), last_parent_reeval: None, @@ -724,7 +722,6 @@ impl Node { discovery_forward_limiter: DiscoveryForwardRateLimiter::new(), pending_connects: Vec::new(), retry_pending: HashMap::new(), - #[cfg(feature = "nostr-discovery")] nostr_discovery: None, bootstrap_transports: HashSet::new(), last_parent_reeval: None, diff --git a/testing/scripts/build.sh b/testing/scripts/build.sh index cf7b699..b72e47a 100755 --- a/testing/scripts/build.sh +++ b/testing/scripts/build.sh @@ -19,9 +19,10 @@ if [ ! -f "$PROJECT_ROOT/Cargo.toml" ]; then fi BUILD_DOCKER=true -# NAT harness binaries need Nostr bootstrap support; everything else is -# governed by platform cfg gates after PR #79's feature-matrix collapse. -DEFAULT_CARGO_BUILD_ARGS=(--features nostr-discovery) +# Default flags for the container-image cargo build. Empty by default; +# every subsystem is governed by platform cfg gates with no feature +# flags required. +DEFAULT_CARGO_BUILD_ARGS=() if [ -n "${FIPS_CARGO_BUILD_ARGS:-}" ]; then # shellcheck disable=SC2206 CARGO_BUILD_ARGS=($FIPS_CARGO_BUILD_ARGS)