fix(server): web UI listens on IPv6 — the mesh could never load it
The mesh is IPv6-only; the main web listener bound 0.0.0.0 only, so a phone reaching a node over its fips0 ULA got RST on :80 (ERR_CONNECTION_ABORTED) — UI over mesh was structurally impossible. Confirmed 2026-07-26 on framework-pt: v4:80 = 200, v6:80 = refused. Mirror an IPv4-any main listener with a V6ONLY [::] socket on the same port; V6ONLY so it coexists with the v4 listener regardless of net.ipv6.bindv6only. Also: fips.yaml generator carries the fast-reconnect profile (validated live on framework-pt since 2026-07-24; snapshot tests updated). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -48,6 +48,30 @@ pub struct FipsConfig {
|
||||
pub struct NodeSection {
|
||||
pub identity: IdentitySection,
|
||||
pub discovery: DiscoverySection,
|
||||
pub retry: RetrySection,
|
||||
pub rate_limit: RateLimitSection,
|
||||
}
|
||||
|
||||
/// Fast-reconnect profile (`node.retry.*`). Upstream defaults (5s base
|
||||
/// doubling to 300s) are tuned for stable always-on links; a node redialing
|
||||
/// a recycled anchor sat off-mesh for ~90s. Field names verified live on
|
||||
/// 2026-07-24: a daemon restarted with these keys in fips.yaml and peered.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub struct RetrySection {
|
||||
pub base_interval_secs: u64,
|
||||
pub max_backoff_secs: u64,
|
||||
pub max_retries: u32,
|
||||
}
|
||||
|
||||
/// Session-handshake resend pacing (`node.rate_limit.*`). Stock 1s x2.0
|
||||
/// gaps out to 8-16s between resends exactly when a route has just
|
||||
/// appeared; 400ms x1.5 keeps continuous coverage through the connect
|
||||
/// window (phone measured session-after-route: 225ms).
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub struct RateLimitSection {
|
||||
pub handshake_resend_interval_ms: u64,
|
||||
pub handshake_resend_backoff: f64,
|
||||
pub handshake_max_resends: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
@@ -60,6 +84,14 @@ pub struct IdentitySection {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub struct DiscoverySection {
|
||||
/// Lookup completion timeout. Lookups fired while the tree position is
|
||||
/// still settling are doomed; failing them fast (5s, not 10s) lets the
|
||||
/// 1s-backoff retry find the route the moment it exists.
|
||||
pub timeout_secs: u64,
|
||||
pub backoff_base_secs: u64,
|
||||
pub backoff_max_secs: u64,
|
||||
pub retry_interval_secs: u64,
|
||||
pub max_attempts: u8,
|
||||
pub lan: LanDiscoverySection,
|
||||
}
|
||||
|
||||
@@ -123,8 +155,23 @@ impl Default for FipsConfig {
|
||||
node: NodeSection {
|
||||
identity: IdentitySection { persistent: true },
|
||||
discovery: DiscoverySection {
|
||||
timeout_secs: 5,
|
||||
backoff_base_secs: 1,
|
||||
backoff_max_secs: 30,
|
||||
retry_interval_secs: 2,
|
||||
max_attempts: 3,
|
||||
lan: LanDiscoverySection { enabled: true },
|
||||
},
|
||||
retry: RetrySection {
|
||||
base_interval_secs: 1,
|
||||
max_backoff_secs: 30,
|
||||
max_retries: 30,
|
||||
},
|
||||
rate_limit: RateLimitSection {
|
||||
handshake_resend_interval_ms: 400,
|
||||
handshake_resend_backoff: 1.5,
|
||||
handshake_max_resends: 10,
|
||||
},
|
||||
},
|
||||
tun: TunSection {
|
||||
enabled: true,
|
||||
@@ -318,8 +365,21 @@ node:
|
||||
identity:
|
||||
persistent: true
|
||||
discovery:
|
||||
timeout_secs: 5
|
||||
backoff_base_secs: 1
|
||||
backoff_max_secs: 30
|
||||
retry_interval_secs: 2
|
||||
max_attempts: 3
|
||||
lan:
|
||||
enabled: true
|
||||
retry:
|
||||
base_interval_secs: 1
|
||||
max_backoff_secs: 30
|
||||
max_retries: 30
|
||||
rate_limit:
|
||||
handshake_resend_interval_ms: 400
|
||||
handshake_resend_backoff: 1.5
|
||||
handshake_max_resends: 10
|
||||
tun:
|
||||
enabled: true
|
||||
name: fips0
|
||||
|
||||
Reference in New Issue
Block a user