feat(fips): peer dialing + dedicated fips0 listener with path whitelist
Wires the FIPS transport end-to-end so peer-to-peer calls can reach other nodes over the mesh without going through Tor: - fips::dial — raw RFC 1035 DNS client (zero new deps) that queries the FIPS daemon's local resolver at 127.0.0.1:5354 for `<npub>.fips` AAAA records. Exposes peer_base_url(npub) → "http://[fd9d:…]:5679" plus a reqwest client factory for call-site migrations. - fips::iface — parses /proc/net/if_inet6 to find the ULA address on `fips0`. Runs under the archipelago service user without extra caps. - FipsTransport::is_available() — live probe of archipelago-fips and upstream fips.service via `systemctl is-active`, cached 10s so the send hot path doesn't thrash DBus. - FipsTransport::send() — resolve npub, POST TransportMessage JSON to the peer's /transport/inbox. Today /transport/inbox isn't wired on the receive side, so call-site migrations use dial::peer_base_url directly against the already-signed endpoints (/rpc/v1, /archipelago/node-message, /content/*). The inbox handler lands as part of the Settings/transport work. - server::serve_with_shutdown — takes an optional peer_addr and spawns a second listener bound specifically to the fips0 ULA on port 5679. The peer listener applies is_peer_allowed_path() — a whitelist of endpoints that already do per-request signature auth — and returns 404 for everything else. Shutdown cascades to both listeners via a watch channel; 5s drain window preserved. - main.rs — if fips0 has a ULA at startup, pass the peer SocketAddr to serve_with_shutdown; otherwise run the main listener only. Security: the peer listener is bound to the fips0 ULA directly, not wildcard, so it's unreachable from WAN IPv6. The path whitelist limits exposure to endpoints whose handlers verify ed25519 signatures or federation DID headers server-side. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
becdb1af5a
commit
5479e225d7
@@ -149,6 +149,19 @@ async fn main() -> Result<()> {
|
||||
.parse()
|
||||
.context("Invalid bind address")?;
|
||||
|
||||
// If the FIPS daemon has brought up `fips0` with a ULA address, bind a
|
||||
// second listener there for peer-to-peer traffic. The peer listener
|
||||
// applies a path whitelist (see server::is_peer_allowed_path) so FIPS
|
||||
// peers can only reach signed peer endpoints, not internal surfaces.
|
||||
// No address → no peer listener (fresh install pre-onboarding, fips
|
||||
// service down, etc.); peers fall through to Tor until next restart.
|
||||
let peer_addr: Option<SocketAddr> = fips::iface::fips0_ula().map(|ip| {
|
||||
SocketAddr::new(std::net::IpAddr::V6(ip), fips::dial::PEER_PORT)
|
||||
});
|
||||
if let Some(pa) = peer_addr {
|
||||
info!("FIPS peer listener will bind {}", pa);
|
||||
}
|
||||
|
||||
// Spawn background update scheduler
|
||||
let update_data_dir = config.data_dir.clone();
|
||||
tokio::spawn(async move {
|
||||
@@ -199,7 +212,7 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
};
|
||||
|
||||
server.serve_with_shutdown(addr, shutdown).await?;
|
||||
server.serve_with_shutdown(addr, peer_addr, shutdown).await?;
|
||||
|
||||
// Clean shutdown: remove PID marker so next startup doesn't trigger recovery
|
||||
crash_recovery::remove_pid_marker(&config.data_dir).await;
|
||||
|
||||
Reference in New Issue
Block a user