Files
fips/src/discovery.rs
T
Johnathan Corgan e641eb5b5f Drop the nostr-discovery cargo feature flag
Make Nostr-mediated overlay discovery unconditional, mirroring the
philosophy of PR #79's collapse of the tui/ble/gateway features in
favor of platform cfg gates. nostr / nostr-sdk are pure Rust over
WebSockets/TCP, so they build cleanly on every FIPS-supported
platform — there is no need for the parallel feature gate.

The flag was already in `default = [...]`, so no behavior change for
anyone using `cargo build` without `--no-default-features`. Operators
who explicitly disabled the feature will now find Nostr code present
in the binary; the runtime check `node.discovery.nostr.enabled` still
controls whether the runtime starts.

Cargo.toml:
- Remove the `[features]` table entirely.
- Drop `optional = true` from `nostr` and `nostr-sdk`.

Source: 27 cfg sites collapsed across 5 files —
`src/discovery.rs`, `src/discovery/nostr/mod.rs`,
`src/node/handlers/rx_loop.rs`, `src/node/lifecycle.rs`,
`src/node/mod.rs`. Two `#[cfg(not(feature = "nostr-discovery"))]`
fallback blocks (the udp:nat-without-runtime debug-log path and the
"feature not compiled in" warning at startup) were removed as dead
code; the always-on path already handles the missing-runtime case
via `nostr_discovery: Option<NostrDiscovery>`.

Packaging and tooling:
- `packaging/openwrt-ipk/Makefile`: drop a stale `--features gateway`
  flag (the `gateway` feature was already removed in PR #79; this
  was a leftover that the build path tolerated only because cargo
  ignored unknown feature names).
- `testing/scripts/build.sh`: drop `DEFAULT_CARGO_BUILD_ARGS=(--features
  nostr-discovery)`; defaults are empty.
- `packaging/common/fips.yaml`: drop the "requires the
  nostr-discovery feature" comment from the discovery section.

Bundled cleanup:
- Apply `cargo clippy --fix` against three pre-existing warnings in
  `src/discovery/nostr/runtime.rs` and `src/discovery/nostr/stun.rs`
  (collapsed `if let Some` chain; two redundant `as i32` casts).
  These were always present but masked when the feature gate was
  off; they surface now that the code is unconditionally compiled.
- `cargo fmt` settled two minor formatting drift sites in
  `src/bin/fips-gateway.rs` and `src/config/mod.rs`.

Tests: 1083 passed, 0 failed, 4 ignored. clippy clean. fmt clean.
2026-04-30 10:24:32 +00:00

104 lines
3.8 KiB
Rust

//! Bootstrap handoff types.
//!
//! These types model the boundary between an external rendezvous/bootstrap
//! runtime and the core FIPS transport/handshake stack. The rendezvous side
//! owns Nostr/STUN/UDP hole punching; once a direct UDP path is established,
//! it hands the live socket and selected remote endpoint to FIPS so the
//! existing Noise/FMP transport path can take over.
pub mod nostr;
use crate::config::UdpConfig;
use crate::{NodeAddr, TransportId};
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 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
/// [`PUNCH_MAGIC`].
pub const PUNCH_ACK_MAGIC: u32 = 0x4E505441;
/// Returns `true` if the first four bytes of `data` match a punch-probe or
/// punch-ack magic. Used by the UDP transport's receive loop to silently
/// drop stray probes that arrive on an adopted socket after the remote
/// peer's punch attempt has already timed out.
pub fn is_punch_packet(data: &[u8]) -> bool {
if data.len() < 4 {
return false;
}
let magic = u32::from_be_bytes([data[0], data[1], data[2], data[3]]);
magic == PUNCH_MAGIC || magic == PUNCH_ACK_MAGIC
}
/// Result of handing an established traversal session into FIPS.
#[derive(Debug, Clone)]
pub struct BootstrapHandoffResult {
/// Newly allocated transport ID used for the adopted UDP socket.
pub transport_id: TransportId,
/// Local socket address now owned by the FIPS UDP transport.
pub local_addr: SocketAddr,
/// Confirmed remote UDP endpoint selected by traversal.
pub remote_addr: SocketAddr,
/// Peer node address derived from the supplied peer identity.
pub peer_node_addr: NodeAddr,
/// Nostr session identifier used by the bootstrap runtime.
pub session_id: String,
}
/// Established UDP traversal ready to be handed into FIPS.
///
/// The socket must already be bound and must be the same socket used for the
/// traversal runtime's STUN and punch traffic so the NAT mapping is preserved.
#[derive(Debug)]
pub struct EstablishedTraversal {
/// Rendezvous session identifier for logging/correlation.
pub session_id: String,
/// Remote peer identity in `npub` form.
pub peer_npub: String,
/// The selected remote UDP endpoint to use for the FIPS handshake.
pub remote_addr: SocketAddr,
/// The live UDP socket carrying the established mapping.
pub socket: UdpSocket,
/// Optional name for the adopted UDP transport.
pub transport_name: Option<String>,
/// Optional UDP transport tuning overrides.
pub transport_config: Option<UdpConfig>,
}
impl EstablishedTraversal {
/// Construct an established traversal handoff.
pub fn new(
session_id: impl Into<String>,
peer_npub: impl Into<String>,
remote_addr: SocketAddr,
socket: UdpSocket,
) -> Self {
Self {
session_id: session_id.into(),
peer_npub: peer_npub.into(),
remote_addr,
socket,
transport_name: None,
transport_config: None,
}
}
/// Attach an explicit transport name to the adopted UDP transport.
pub fn with_transport_name(mut self, name: impl Into<String>) -> Self {
self.transport_name = Some(name.into());
self
}
/// Override UDP transport tuning for the adopted socket.
pub fn with_transport_config(mut self, config: UdpConfig) -> Self {
self.transport_config = Some(config);
self
}
}