mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
docs: four-section /docs/ restructure with new-user content, accuracy pass, and gateway feature-set rewrite
Restructures /docs/ by reader purpose (tutorials, how-to, reference, design), adds the new-user-progression and operator-recipe content the prior layout lacked, runs an accuracy pass against current source across the pre-existing design docs, and rewrites the gateway feature-set documentation end-to-end around its actual operational profile (a niche feature designed for systems already serving DHCP/DNS to a LAN, with two independent halves — outbound LAN→mesh, inbound mesh→LAN — sharing one nftables table, one binary, and one control socket). Top-level README and getting-started rewritten around two equally-weighted deployment modes (overlay on existing IP networks; ground-up over non-IP transports). ## Additions - 11 new tutorials in docs/tutorials/: an 8-step new-user progression from single-daemon test-mesh peering through to a ground-up two-device mesh, an IPv6-adapter side-trip walkthrough, an Advanced Tutorials index, and a hand-held OpenWrt walk-through for fips-gateway deployment that exercises both halves of the feature. - 12 new how-tos in docs/how-to/: firewall activation, Nostr discovery (resolve / advertise / open across five scenarios), Tor onion (directory + control_port modes), UDP buffer tuning, unprivileged-user setup, persistent identity, host aliases, Bluetooth LE peering, MTU diagnostics, manual Linux-host gateway deployment (covers both halves), gateway troubleshooting (organised by half), and a section index. - 9 new reference docs in docs/reference/: configuration, wire formats, control-socket protocol, four CLI references (fips, fipsctl, fipstop, fips-gateway), security posture matrix, and Nostr events catalog. Configuration and wire-formats are renamed-and-extended from prior design/ versions; the other seven are net-new. - 6 new design docs: fips-concepts, fips-architecture, and fips-prior-work split out of the deleted fips-intro.md; consolidated fips-mmp and fips-mtu aggregations; and a new generic port-advertisement-and-nat-traversal doc (Nostr-signaled port advertisement plus UDP NAT-traversal protocol, FIPS as an example implementation, suitable for eventual NIP submission). - Top-level docs/getting-started.md walking through the binary-installer-only Install story. - packaging/common/hosts pre-populated with the eight public test-mesh nodes so shortnames resolve out of the box on every fresh install. ## Changes - 23 wire-format diagrams relocated to reference/diagrams/ alongside the wire-formats move. - 4 design diagrams corrected against source code (fips-protocol-stack, fips-identity-derivation, fips-coordinate-discovery, fips-routing-decision). - 10 pre-existing design docs reconciled with current source. Numeric corrections: stale link-MMP report bounds (now [1s, 5s] with 200 ms cold-start floor); UDP default MTU (now 1280, IPv6 minimum); node_addr formula (SHA-256(pubkey)[..16]); Noise patterns (IK at link, XK at session); peer-ACL semantics (strict allowlist requires ALL in peers.deny); daemon DNS upstream ([::1]:5354); on-the-wire bloom-filter size (1,071 bytes); obsolete Cargo-feature references (PR #79 dropped them) removed. - Transport framing tightened across the docs: TCP is for UDP-filtered networks (not NAT traversal); Tor is a deployment mode (not failover); WebSocket dropped (not a shipped FIPS transport); WiFi promoted to Implemented via Ethernet in infrastructure mode; classic-Bluetooth row removed (BLE is the only Bluetooth-mode transport). - docs/design/fips-gateway.md rewritten end-to-end to lead with the niche-feature framing and the two-halves structure. Title moved from "FIPS Outbound LAN Gateway" to "FIPS Gateway"; architecture section describes the common machinery (the fips-gateway service, the nftables table, the control socket) before splitting into separate "Outbound Half" and "Inbound Half" sections of equal weight; security considerations split per-half; no Future Work section (speculative directions live in the project tracker, not in protocol design docs). Inbound port forwarding is a first-class half rather than a buried "Implemented Extensions" subsection. - Gateway terminology unified across all gateway docs as a separate Linux service running alongside the fips daemon (its own systemd unit / OpenWrt init script). Container- pattern terms (sidecar) are reserved for the Docker/Kubernetes sidecar deployment examples — the testing/sidecar/ tree, examples/k8s-sidecar/, examples/sidecar-nostr-relay/, examples/wireguard-sidecar-macos/, and the related CHANGELOG / top-level README entries — where the term carries its standard container meaning. - Net-new design body content: rekey section in fips-mesh-layer (Noise IK msg1/msg2 over the established link, K-bit cutover, drain window, smaller-NodeAddr-wins tie-breaker on dual-init); Mesh Size Estimation and Antipoison FPR Cap sections in fips-bloom-filters; Mesh-Interface Query Filter subsection in fips-ipv6-adapter; failure-suppression knobs and clock- skew tolerance in fips-nostr-discovery; loop-rejection and mid-chain ancestor swap added to spanning-tree propagation / stability rules; Priority Chain in fips-mesh-operation renumbered to match the routing-decision diagram. - Top-level README: dropped the stale nostr-discovery cargo-feature parenthetical. docs/README.md and the four section READMEs (tutorials, how-to, reference, design) refreshed for the new structure; index rows reflect both halves of the gateway feature and the new fips-gateway CLI reference. - Cargo.toml [package.metadata.deb] assets path updated for the fips-security.md move; .gitignore /reference/ rule anchored to repo root so docs/reference/ is trackable. - packaging/openwrt-ipk/files/etc/fips/fips.yaml configuration-doc URL updated to the new docs/reference/configuration.md location. ## Deletions - docs/design/fips-intro.md (split into the three new intro design docs). - docs/design/document-relationships.svg (orphan, no longer referenced). - docs/proposals/ tree removed; the only proposal it contained (the Nostr UDP hole-punch protocol) was rewritten as the new generic design/port-advertisement-and-nat-traversal.md.
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
# Nostr Event Reference
|
||||
|
||||
The Nostr-protocol surface FIPS uses for discovery and signaling. For
|
||||
the design of the discovery runtime and the rationale behind these
|
||||
event shapes, see
|
||||
[../design/fips-nostr-discovery.md](../design/fips-nostr-discovery.md).
|
||||
For operator activation recipes, see
|
||||
[../how-to/enable-nostr-discovery.md](../how-to/enable-nostr-discovery.md).
|
||||
|
||||
FIPS uses three Nostr event kinds:
|
||||
|
||||
| Kind | Name | Encryption | Storage | Purpose |
|
||||
| ---- | ---- | ---------- | ------- | ------- |
|
||||
| 37195 | Overlay advert | None (signed only) | Replaceable | Publish reachable transport endpoints |
|
||||
| 21059 | Traversal signaling | NIP-44 inside NIP-59 gift wrap | Ephemeral | Carry `TraversalOffer`/`TraversalAnswer` payloads |
|
||||
| 10050 | NIP-17 inbox relay list | None (signed only) | Replaceable | Tell dialers where to publish offers |
|
||||
|
||||
All three are signed with the node's FIPS identity key (the same
|
||||
secp256k1 keypair Nostr uses); there is no separate Nostr key.
|
||||
|
||||
## Kind 37195 — Overlay Advert
|
||||
|
||||
A parameterized replaceable event in the application-defined
|
||||
replaceable range `30000–39999` (the digits visually spell `FIPS`:
|
||||
7=F, 1=I, 9=P, 5=S). Each node has a single in-place-updatable advert
|
||||
under its identity.
|
||||
|
||||
### Tags
|
||||
|
||||
- `d` — fixed to the literal `fips-overlay-v1` (the application
|
||||
identifier baked into the binary). Together with `pubkey`, this
|
||||
identifies the unique replaceable event slot.
|
||||
- `protocol` — the configured `node.discovery.nostr.app` value
|
||||
(default `fips-overlay-v1`). Distinct from the `d` tag so the
|
||||
application string can evolve without breaking the replaceable
|
||||
event slot.
|
||||
- `version` — protocol version string (currently `"1"`).
|
||||
- `expiration` — NIP-40 expiration timestamp set to now +
|
||||
`node.discovery.nostr.advert_ttl_secs` (default 3600 seconds).
|
||||
Conforming relays stop serving the event after this time.
|
||||
|
||||
### Content
|
||||
|
||||
The event content is a JSON document shaped as `OverlayAdvert`:
|
||||
|
||||
```json
|
||||
{
|
||||
"identifier": "fips-overlay-v1",
|
||||
"version": 1,
|
||||
"endpoints": [
|
||||
{"transport": "udp", "addr": "203.0.113.45:2121"},
|
||||
{"transport": "tor", "addr": "xxxxx.onion:8443"},
|
||||
{"transport": "udp", "addr": "nat"}
|
||||
],
|
||||
"signalRelays": ["wss://relay.damus.io", "wss://nos.lol"],
|
||||
"stunServers": ["stun:stun.l.google.com:19302"]
|
||||
}
|
||||
```
|
||||
|
||||
Field semantics:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `identifier` | string | Application namespace; must match the `d` tag. |
|
||||
| `version` | integer | Advert schema version (currently 1). |
|
||||
| `endpoints` | array | List of transport endpoints. Each is `{transport, addr}` where `transport` is `"udp"`, `"tcp"`, or `"tor"`, and `addr` is `"host:port"`, `".onion:port"`, or the literal `"nat"` (for UDP NAT-punch). |
|
||||
| `signalRelays` | array? | Optional. Relays the publisher prefers for offer/answer signaling. Present only when at least one endpoint is `udp:nat`. |
|
||||
| `stunServers` | array? | Optional. STUN servers the publisher uses for reflexive discovery. Present only when at least one endpoint is `udp:nat`. Informational — peers do not use these to choose their own STUN targets. |
|
||||
|
||||
### Signature scope
|
||||
|
||||
The Nostr event signature covers the standard Nostr event ID
|
||||
(serialized `[0, pubkey, created_at, kind, tags, content]`), so the
|
||||
content JSON, tags, kind, and timestamp are all bound to the signing
|
||||
identity.
|
||||
|
||||
### Replacement and deletion
|
||||
|
||||
Because kind 37195 is replaceable, publishing a new advert replaces
|
||||
the prior one in the same `(pubkey, d-tag)` slot. To withdraw an
|
||||
advert without publishing a successor, the node publishes a NIP-9
|
||||
kind 5 delete event referencing the prior advert.
|
||||
|
||||
## Kind 21059 — Traversal Signaling
|
||||
|
||||
An ephemeral event (kinds in the 20000–29999 range are not stored by
|
||||
conforming relays). Used to deliver gift-wrapped, NIP-44-encrypted
|
||||
`TraversalOffer` and `TraversalAnswer` payloads between dialer and
|
||||
responder during a UDP NAT hole-punch.
|
||||
|
||||
### Encryption envelope
|
||||
|
||||
The wire shape is the standard NIP-59 gift wrap:
|
||||
|
||||
1. **Rumor** — the unsigned `TraversalOffer`/`TraversalAnswer`
|
||||
payload (JSON), authored by the actual sender's identity.
|
||||
2. **Seal** — a kind 13 event whose content is the rumor
|
||||
NIP-44-encrypted to the recipient's pubkey, signed by the sender.
|
||||
3. **Gift wrap** — a kind 21059 event whose content is the seal
|
||||
NIP-44-encrypted to the recipient under an ephemeral key, signed
|
||||
by that ephemeral key. The outer `pubkey` of the kind 21059 event
|
||||
is the ephemeral identity, not the sender's real identity.
|
||||
|
||||
Only the intended recipient can decrypt the wrap to recover the seal,
|
||||
and only the recipient can decrypt the seal to recover the rumor.
|
||||
|
||||
### Wrapped payloads
|
||||
|
||||
The `TraversalOffer` carries:
|
||||
|
||||
- `type` — message-type tag.
|
||||
- `sessionId` — unique identifier correlating offer and answer.
|
||||
- `senderNpub` / `recipientNpub` — bech32-encoded pubkeys, repeated
|
||||
inside the encrypted payload (the outer wrap pubkey is ephemeral).
|
||||
- `issuedAt` / `expiresAt` — Unix-ms timestamps; `expiresAt` is
|
||||
`issuedAt + signal_ttl_secs * 1000`.
|
||||
- `nonce` — random per-offer value.
|
||||
- `reflexiveAddress` — `{protocol, ip, port}` observed via STUN, or
|
||||
`null` if STUN failed or returned no usable address.
|
||||
- `localAddresses` — array of `{protocol, ip, port}` private
|
||||
candidates, populated when `share_local_candidates` is enabled.
|
||||
- `stunServer` — the STUN server actually used (informational).
|
||||
|
||||
The `TraversalAnswer` echoes `sessionId` and carries:
|
||||
|
||||
- `type`, `senderNpub`, `recipientNpub`, `issuedAt`, `expiresAt`,
|
||||
`nonce` — same shape as the offer.
|
||||
- `inReplyTo` — the offer's event id.
|
||||
- `accepted` — boolean; false when the responder has no usable
|
||||
addresses.
|
||||
- `reflexiveAddress` and `localAddresses` — the responder's
|
||||
candidates, in the same shape as the offer.
|
||||
- `stunServer` — informational.
|
||||
- `punch` — a `PunchHint { startAtMs, intervalMs, durationMs }`
|
||||
telling both sides when to begin probing and how aggressively.
|
||||
Absent on rejected offers.
|
||||
- `reason` — optional rejection string when `accepted` is false.
|
||||
- `offerReceivedAt` — optional responder wall-clock (Unix ms) at
|
||||
the moment it received the offer; the initiator uses this to
|
||||
derive a clock-skew estimate.
|
||||
|
||||
### Relay selection
|
||||
|
||||
Dialer publishes offers to the recipient's NIP-17 inbox relays (kind
|
||||
10050) when available; otherwise to the local
|
||||
`node.discovery.nostr.dm_relays` list. The responder publishes the
|
||||
answer back through the same relay channel.
|
||||
|
||||
## Kind 10050 — NIP-17 Inbox Relay List
|
||||
|
||||
A standard NIP-17 event used by FIPS to advertise which relays this
|
||||
node prefers for receiving direct-message-style signaling — for FIPS,
|
||||
the gift-wrapped traversal offers (kind 21059).
|
||||
|
||||
This is **NIP-17** (`kind 10050`, inbox relays for DM delivery), not
|
||||
NIP-65 (`kind 10002`, general read/write relay list). The two serve
|
||||
different purposes:
|
||||
|
||||
- Kind 10002 (NIP-65) — general read/write relays for ordinary event
|
||||
publication and subscription.
|
||||
- Kind 10050 (NIP-17) — relays the recipient prefers for receiving
|
||||
DM-shaped (NIP-59 wrapped) events.
|
||||
|
||||
FIPS publishes its own kind 10050 on startup so dialers can discover
|
||||
where to send traversal offers. When dialing a peer, FIPS first
|
||||
fetches the peer's kind 10050 from the peer's `advert_relays`; on
|
||||
fetch failure it falls back to the local `dm_relays` list.
|
||||
|
||||
### Tags
|
||||
|
||||
Standard NIP-17 form: each relay is encoded as an `r` tag whose
|
||||
single value is the relay URL.
|
||||
|
||||
```text
|
||||
["r", "wss://relay.damus.io"]
|
||||
["r", "wss://nos.lol"]
|
||||
```
|
||||
|
||||
### Content
|
||||
|
||||
Empty per NIP-17.
|
||||
|
||||
## See also
|
||||
|
||||
- [../design/fips-nostr-discovery.md](../design/fips-nostr-discovery.md)
|
||||
— discovery runtime design and the five activation scenarios
|
||||
- [../how-to/enable-nostr-discovery.md](../how-to/enable-nostr-discovery.md)
|
||||
— operator recipes
|
||||
- [../tutorials/resolve-peers-via-nostr.md](../tutorials/resolve-peers-via-nostr.md),
|
||||
[../tutorials/advertise-your-node.md](../tutorials/advertise-your-node.md),
|
||||
[../tutorials/open-discovery.md](../tutorials/open-discovery.md)
|
||||
— hand-held tutorial walkthroughs of the three capabilities
|
||||
- [../design/port-advertisement-and-nat-traversal.md](../design/port-advertisement-and-nat-traversal.md)
|
||||
— generic protocol reference (event tags, NIP usage, on-the-wire
|
||||
offer/answer schema), with FIPS values as worked examples
|
||||
- [security.md](security.md) — how the FIPS identity key signs both
|
||||
adverts and Noise handshakes
|
||||
Reference in New Issue
Block a user