Merge branch 'master' into next
Forward-merge of the docs-overhaul squash (5abf9a9) and top-level README rewrite (18019bb). Conflict resolution: - README.md: master's rewritten feature lists adopted, with the encryption bullets reflecting next's two-layer Noise XX (replacing the IK/XK pair master describes for v0.3.0). - 6 design/reference markdown files (fips-bloom-filters.md, fips-mesh-layer.md, fips-mesh-operation.md, fips-session-layer.md, fips-transport-layer.md, reference/wire-formats.md): master's reorg taken, next's protocol details preserved (XX handshake naming, bloom v2 RLE/delta wire format, v2 LookupRequest sizing). - fips-intro.md modify/delete: accepted master's split into fips-architecture.md / fips-concepts.md / fips-prior-work.md, then re-applied next's IK/XK -> XX transition and spin-bit removal across the relevant split files. Same pass swept docs/reference/security.md, docs/design/fips-mmp.md, docs/design/fips-security.md, docs/design/fips-nostr-discovery.md, docs/design/port-advertisement-and-nat-traversal.md, docs/how-to/enable-nostr-discovery.md, and the affected tutorials so no IK/XK or spin-bit prose remains in current-state docs. - Diagram path conflicts: noise-ik-msg{1,2}.svg removed (IK is gone); noise-xx-msg{1,2,3}.svg moved from docs/design/diagrams/ to docs/reference/diagrams/ to match master's diagram reorg. The wire-formats.md image references resolve correctly to the new path. Local verification: cargo build --release, cargo test (1265 passed, 4 ignored), cargo clippy -D warnings, cargo fmt --check all green.
@@ -0,0 +1,25 @@
|
||||
# Reference
|
||||
|
||||
Information-oriented technical descriptions for lookup on demand.
|
||||
Reference content describes *what is*: wire formats, configuration
|
||||
keys, command-line flags, control-socket commands, default values,
|
||||
file paths, exit codes. It is consulted, not read end-to-end.
|
||||
|
||||
Reference is austere by design: minimal narrative, no opinions, no
|
||||
guidance on when to use a feature. The "why" lives in design/; the
|
||||
"how do I accomplish X" lives in how-to/.
|
||||
|
||||
## Available Reference
|
||||
|
||||
| Document | Scope |
|
||||
| -------- | ----- |
|
||||
| [wire-formats.md](wire-formats.md) | All FMP and FSP message byte layouts, encapsulation walkthrough |
|
||||
| [configuration.md](configuration.md) | Full YAML configuration reference for the daemon and gateway |
|
||||
| [security.md](security.md) | nftables baseline, peer ACL, cryptographic primitives, rekey defaults, threat-resistance matrix |
|
||||
| [nostr-events.md](nostr-events.md) | Kind 37195 advert, Kind 21059 traversal signaling, Kind 10050 inbox relays |
|
||||
| [transports.md](transports.md) | Per-transport statistics counter inventory |
|
||||
| [control-socket.md](control-socket.md) | Line-delimited JSON control protocol for the daemon and gateway |
|
||||
| [cli-fips.md](cli-fips.md) | `fips` daemon CLI: options, exit codes, environment, files |
|
||||
| [cli-fipsctl.md](cli-fipsctl.md) | `fipsctl` control-client: subcommands, options, exit codes |
|
||||
| [cli-fipstop.md](cli-fipstop.md) | `fipstop` live-status TUI: tabs, keybindings |
|
||||
| [cli-fips-gateway.md](cli-fips-gateway.md) | `fips-gateway` service CLI: options, exit codes, files |
|
||||
@@ -0,0 +1,125 @@
|
||||
# `fips-gateway`
|
||||
|
||||
Long-running service that bridges a LAN segment into the FIPS mesh.
|
||||
|
||||
## Synopsis
|
||||
|
||||
```text
|
||||
fips-gateway [-c FILE] [-l LEVEL]
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
`fips-gateway` runs alongside `fips` on the same host, reads the same
|
||||
`fips.yaml`, and exposes two complementary functions to the LAN it
|
||||
fronts:
|
||||
|
||||
- **Outbound (LAN -> mesh).** Allocates a virtual IPv6 from a managed
|
||||
pool when a LAN client resolves `<npub>.fips`, installs nftables
|
||||
DNAT/SNAT/masquerade rules so the client's traffic is rewritten and
|
||||
carried into the mesh through the daemon's `fips0` adapter.
|
||||
- **Inbound (mesh -> LAN).** Installs nftables DNAT and LAN-side
|
||||
masquerade rules so mesh-side traffic arriving on `fips0` for the
|
||||
configured listen ports is rewritten to a LAN `host:port`, per the
|
||||
`gateway.port_forwards[]` block.
|
||||
|
||||
The service runs alongside `fips`, not as a replacement for it:
|
||||
the daemon must be running on the same host with the TUN adapter
|
||||
and DNS resolver enabled. The gateway is read-only with respect to the
|
||||
daemon's state, and connects to the daemon's resolver only — it is
|
||||
not a peer. For the architecture, see
|
||||
[../design/fips-gateway.md](../design/fips-gateway.md).
|
||||
|
||||
`fips-gateway` is **Linux-only**. The binary errors out and exits with
|
||||
status `1` on any other platform, since the NAT pipeline is built on
|
||||
nftables and proxy NDP. See
|
||||
[Configuration](#configuration) for the platform notes that follow
|
||||
from this.
|
||||
|
||||
## Options
|
||||
|
||||
| Flag | Argument | Default | Description |
|
||||
| ---- | -------- | ------- | ----------- |
|
||||
| `-c`, `--config` | `FILE` | *(default search paths)* | Use `FILE` as the configuration. Skips the default search paths. |
|
||||
| `-l`, `--log-level` | `LEVEL` | `info` | Tracing level: `trace`, `debug`, `info`, `warn`, `error`. Overridden by `RUST_LOG` if set (see [Environment](#environment)). |
|
||||
| `-V` | — | — | Print the short version. |
|
||||
| `--version` | — | — | Print the long version (short version plus build target triple). |
|
||||
| `-h`, `--help` | — | — | Print usage and exit. |
|
||||
|
||||
## Configuration
|
||||
|
||||
`fips-gateway` reads the same `fips.yaml` as `fips`; the gateway is
|
||||
configured under the top-level `gateway:` block. The block must
|
||||
include at minimum `enabled: true`, `pool`, and `lan_interface`. For
|
||||
each field — pool, LAN interface, DNS listener, conntrack overrides,
|
||||
and inbound `port_forwards[]` — see the
|
||||
[Gateway section](configuration.md#gateway-gateway) of the
|
||||
configuration reference.
|
||||
|
||||
The same default search paths apply as for `fips`
|
||||
(see [`fips`](cli-fips.md#files)); `-c FILE` overrides the search.
|
||||
The gateway must be able to read the same configuration file the
|
||||
daemon is reading, or the two will disagree about pool, DNS port,
|
||||
and LAN interface.
|
||||
|
||||
For deployment recipes, see
|
||||
[../how-to/deploy-gateway.md](../how-to/deploy-gateway.md) (manual
|
||||
Linux host) and
|
||||
[../tutorials/deploy-fips-gateway.md](../tutorials/deploy-fips-gateway.md)
|
||||
(OpenWrt walk-through).
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
| ---- | ------- |
|
||||
| `0` | Clean shutdown after `SIGINT` / `SIGTERM`. |
|
||||
| `1` | Non-Linux platform, configuration load failure, missing or invalid `gateway:` block, NAT/network setup failure, or control-socket bind failure. The reason is printed to stderr or the log before exit. |
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Description |
|
||||
| -------- | ----------- |
|
||||
| `RUST_LOG` | Tracing filter directive. Takes precedence over `--log-level`. Examples: `info`, `debug`, `fips=trace,fips::gateway=debug`. |
|
||||
|
||||
## Files
|
||||
|
||||
| Path | Purpose |
|
||||
| ---- | ------- |
|
||||
| `/etc/fips/fips.yaml` | Gateway configuration (top-level `gateway:` block). Same file the daemon reads. |
|
||||
| `/run/fips/gateway.sock` | Gateway control socket. Hardcoded path; chowned to group `fips` (mode `0770`) at startup so members of that group can query without sudo. |
|
||||
| `inet fips_gateway` (nftables) | NAT table the gateway installs and tears down. View with `nft list table inet fips_gateway`. |
|
||||
|
||||
The gateway also adds and removes a `local <pool-cidr> dev lo` route
|
||||
in the local routing table so the kernel accepts pool addresses as
|
||||
locally-owned.
|
||||
|
||||
## Control Socket
|
||||
|
||||
`fips-gateway` exposes a JSON line-protocol control socket separate
|
||||
from the daemon's. The command set (`show_gateway`, `show_mappings`)
|
||||
and JSON shapes are documented in the
|
||||
[Gateway Command Catalog](control-socket.md#gateway-command-catalog).
|
||||
|
||||
There is no `fipsctl` subcommand for the gateway — query the socket
|
||||
directly with `nc -U`, or watch the **Gateway** tab in
|
||||
[`fipstop`](cli-fipstop.md), which polls the gateway socket
|
||||
automatically.
|
||||
|
||||
## See also
|
||||
|
||||
- [`fips`](cli-fips.md) — the daemon. Required to be running on the
|
||||
same host.
|
||||
- [`fipstop`](cli-fipstop.md) — the live-status TUI; its Gateway tab
|
||||
polls the gateway control socket.
|
||||
- [configuration.md § Gateway](configuration.md#gateway-gateway) —
|
||||
full `gateway.*` block reference.
|
||||
- [control-socket.md § Gateway Command Catalog](control-socket.md#gateway-command-catalog)
|
||||
— wire protocol for the gateway socket.
|
||||
- [../design/fips-gateway.md](../design/fips-gateway.md) — design,
|
||||
NAT pipeline, virtual IP pool lifecycle.
|
||||
- [../how-to/deploy-gateway.md](../how-to/deploy-gateway.md) — manual
|
||||
Linux deployment.
|
||||
- [../how-to/troubleshoot-gateway.md](../how-to/troubleshoot-gateway.md)
|
||||
— diagnostic recipes.
|
||||
- [../tutorials/deploy-fips-gateway.md](../tutorials/deploy-fips-gateway.md)
|
||||
— OpenWrt walk-through.
|
||||
@@ -0,0 +1,93 @@
|
||||
# `fips`
|
||||
|
||||
The FIPS mesh network daemon.
|
||||
|
||||
## Synopsis
|
||||
|
||||
```text
|
||||
fips [-c FILE]
|
||||
```
|
||||
|
||||
On Windows the same binary additionally accepts `--install-service`,
|
||||
`--uninstall-service`, and (used internally by the service control
|
||||
manager) `--service`.
|
||||
|
||||
## Description
|
||||
|
||||
`fips` is the FIPS daemon. It loads a YAML configuration, resolves an
|
||||
identity, brings up the TUN adapter, listens on configured transports,
|
||||
authenticates peers, maintains the spanning tree, and forwards mesh
|
||||
traffic. There is one daemon per node.
|
||||
|
||||
The daemon stays in the foreground, logging to stderr, until it
|
||||
receives `SIGINT` or `SIGTERM`. On Windows, the service variant is
|
||||
controlled through the standard service control manager.
|
||||
|
||||
## Options
|
||||
|
||||
| Flag | Argument | Description |
|
||||
| ---- | -------- | ----------- |
|
||||
| `-c`, `--config` | `FILE` | Use `FILE` as the configuration. Skips the default search paths. |
|
||||
| `-V` | — | Print the short version (e.g. `0.3.0-dev (rev abcdef1)`). |
|
||||
| `--version` | — | Print the long version: short version plus build target triple. |
|
||||
| `-h`, `--help` | — | Print usage and exit. |
|
||||
| `--install-service` | — | (Windows only) Install `fips` as a Windows service. Requires Administrator. |
|
||||
| `--uninstall-service` | — | (Windows only) Uninstall the Windows service. Requires Administrator. |
|
||||
| `--service` | — | (Windows only, internal) Run as a Windows service. Invoked by the service control manager — not for direct use. |
|
||||
|
||||
There are no other CLI flags; all daemon behaviour is governed by the
|
||||
YAML configuration. See [configuration.md](configuration.md).
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
| ---- | ------- |
|
||||
| `0` | Clean shutdown after `SIGINT` / `SIGTERM`. |
|
||||
| `1` | Failed to load configuration, resolve identity, construct the node, or start the node. The reason is printed to stderr before exit. |
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Description |
|
||||
| -------- | ----------- |
|
||||
| `RUST_LOG` | Tracing filter directive. Overrides `node.log_level` from the config. Examples: `info`, `debug`, `fips=trace,fips::node::handlers::mmp=debug`. |
|
||||
| `XDG_RUNTIME_DIR` | Used to derive the default control-socket path when `/run/fips` does not exist. See [control-socket.md](control-socket.md). |
|
||||
| `FIPS_CONFIG` | (Windows service mode only) Path to the configuration file when the daemon runs under the service control manager. |
|
||||
|
||||
The daemon also clamps the `nostr_relay_pool`, `nostr_sdk`, and `nostr`
|
||||
log targets to `info` whenever the effective log level is below
|
||||
`trace`, so that `RUST_LOG=debug` does not flood the journal with raw
|
||||
relay frames. To see those frames, set the level to `trace`.
|
||||
|
||||
## Files
|
||||
|
||||
`fips` looks for `fips.yaml` in the following locations, lowest to
|
||||
highest priority. All present files are merged in priority order; the
|
||||
highest-priority value wins.
|
||||
|
||||
| Priority | Path | Purpose |
|
||||
| -------- | ---- | ------- |
|
||||
| 1 | `/etc/fips/fips.yaml` | System-wide defaults |
|
||||
| 2 | `~/.config/fips/fips.yaml` | User preferences |
|
||||
| 3 | `~/.fips.yaml` | Legacy user config |
|
||||
| 4 | `./fips.yaml` | Deployment-specific overrides |
|
||||
|
||||
Adjacent to the highest-priority config file the daemon reads (or
|
||||
writes, on first start) the identity files:
|
||||
|
||||
| File | Mode | Purpose |
|
||||
| ---- | ---- | ------- |
|
||||
| `fips.key` | `0600` | Bech32 nsec for the persistent identity (Unix only; Windows inherits parent ACLs). |
|
||||
| `fips.pub` | `0644` | Bech32 npub corresponding to `fips.key`. |
|
||||
|
||||
When `node.identity.persistent` is `false` (the default), a fresh
|
||||
keypair is written to these files on every start.
|
||||
|
||||
The control socket path is derived per
|
||||
[control-socket.md](control-socket.md).
|
||||
|
||||
## See also
|
||||
|
||||
- [`fipsctl`](cli-fipsctl.md) — control-socket client.
|
||||
- [`fipstop`](cli-fipstop.md) — live-status TUI.
|
||||
- [configuration.md](configuration.md) — YAML reference.
|
||||
- [control-socket.md](control-socket.md) — control-socket protocol.
|
||||
@@ -0,0 +1,148 @@
|
||||
# `fipsctl`
|
||||
|
||||
Command-line client for the FIPS daemon's control socket.
|
||||
|
||||
## Synopsis
|
||||
|
||||
```text
|
||||
fipsctl [-s SOCKET] <subcommand> [args...]
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
`fipsctl` connects to a running daemon over its control socket
|
||||
(Unix domain socket on Linux/macOS, TCP loopback on Windows), sends
|
||||
one JSON request, and pretty-prints the response. Exits with a
|
||||
non-zero status if the socket cannot be reached, the daemon returns an
|
||||
error, or the request times out.
|
||||
|
||||
`fipsctl keygen` is a special case: it does not contact the daemon and
|
||||
operates purely on local files.
|
||||
|
||||
For the line-delimited JSON wire protocol, see
|
||||
[control-socket.md](control-socket.md). For the YAML configuration
|
||||
that defines the socket location, see
|
||||
[configuration.md](configuration.md).
|
||||
|
||||
## Global Options
|
||||
|
||||
| Flag | Argument | Description |
|
||||
| ---- | -------- | ----------- |
|
||||
| `-s`, `--socket` | `PATH` | Override the control-socket path (Linux/macOS) or TCP port (Windows). |
|
||||
| `-V`, `--version` | — | Print the short version. |
|
||||
| `--version` | — | Print the long version. |
|
||||
| `-h`, `--help` | — | Print usage and exit. Per-subcommand help via `fipsctl <subcommand> --help`. |
|
||||
|
||||
## Subcommands
|
||||
|
||||
### `show <what>`
|
||||
|
||||
Read-only queries against the daemon. Each subcommand maps 1:1 to a
|
||||
control-socket query (see [control-socket.md](control-socket.md)) and
|
||||
prints the response's `data` object as pretty JSON.
|
||||
|
||||
| Subcommand | Control-socket command | Returns |
|
||||
| ---------- | ---------------------- | ------- |
|
||||
| `show status` | `show_status` | Node-level status: identity, version, peer/link/session counts, TUN state, recent sparklines. |
|
||||
| `show peers` | `show_peers` | Authenticated peer list with link IDs, transport addresses, MMP metrics, Noise/rekey state. |
|
||||
| `show links` | `show_links` | Active links (one per FMP-authenticated peer): direction, state, byte counters. |
|
||||
| `show tree` | `show_tree` | Spanning-tree state: root, my coordinates, parent, peer declarations. |
|
||||
| `show sessions` | `show_sessions` | End-to-end FSP sessions: state, traffic counters, session-MMP metrics, path MTU. |
|
||||
| `show bloom` | `show_bloom` | Bloom-filter state: own filter sequence, leaf dependents, per-peer filter summaries. |
|
||||
| `show mmp` | `show_mmp` | MMP metrics summary: per-peer link-layer metrics and per-session session-layer metrics. |
|
||||
| `show cache` | `show_cache` | Coordinate cache: TTL, fill ratio, per-destination coords and path MTU. |
|
||||
| `show connections` | `show_connections` | Pending handshake connections: state, idle time, resend count. |
|
||||
| `show transports` | `show_transports` | Transport instances: type, state, MTU, local address, per-transport stats. |
|
||||
| `show routing` | `show_routing` | Routing summary: pending lookups, retry state, forwarding/discovery/error/congestion counters. |
|
||||
| `show identity-cache` | `show_identity_cache` | Cached `(node_addr → npub)` entries with last-seen timestamps. |
|
||||
|
||||
### `acl <what>`
|
||||
|
||||
| Subcommand | Control-socket command | Returns |
|
||||
| ---------- | ---------------------- | ------- |
|
||||
| `acl show` | `show_acl` | Loaded peer-ACL state: allow/deny files, effective mode, default decision, entry counts. |
|
||||
|
||||
### `stats <what>`
|
||||
|
||||
Time-series metrics from the in-process history rings.
|
||||
|
||||
| Subcommand | Control-socket command | Description |
|
||||
| ---------- | ---------------------- | ----------- |
|
||||
| `stats list` | `show_stats_list` | Enumerate available metrics, their units, and the per-ring retention windows. |
|
||||
| `stats peers` | `show_stats_peers` | List peers tracked in stats history (active or recently active). |
|
||||
| `stats history <metric> [options]` | `show_stats_history` | Fetch a time-series window for one metric. |
|
||||
|
||||
`stats history` options:
|
||||
|
||||
| Flag | Argument | Default | Description |
|
||||
| ---- | -------- | ------- | ----------- |
|
||||
| `--peer` | `npub` or hostname | *(none)* | Required for per-peer metrics; resolves through `/etc/fips/hosts` if not an npub. |
|
||||
| `--window` | `<N>s` / `<N>m` / `<N>h` | `10m` | Window duration. |
|
||||
| `--granularity` | `1s` or `1m` | `1s` | Ring resolution. `1s` uses the fast ring; `1m` uses the slow ring. |
|
||||
| `--plot` | — | off | Render a Unicode-block sparkline to stdout instead of JSON. |
|
||||
|
||||
### `keygen [options]`
|
||||
|
||||
Generate a new FIPS identity keypair locally. Does not contact the
|
||||
daemon.
|
||||
|
||||
| Flag | Argument | Default | Description |
|
||||
| ---- | -------- | ------- | ----------- |
|
||||
| `-d`, `--dir` | `DIR` | `/etc/fips` (Unix), `%APPDATA%\fips` (Windows) | Output directory for `fips.key` and `fips.pub`. |
|
||||
| `-f`, `--force` | — | off | Overwrite an existing `fips.key`. |
|
||||
| `-s`, `--stdout` | — | off | Print `nsec` then `npub` to stdout instead of writing files. |
|
||||
|
||||
`fips.key` is written with mode `0600` and `fips.pub` with mode `0644`
|
||||
on Unix. After running `keygen`, set `node.identity.persistent: true`
|
||||
in `fips.yaml` or the daemon will overwrite the keys on next start.
|
||||
|
||||
### `connect <peer> <address> <transport>`
|
||||
|
||||
Tell the daemon to dial a peer over a specific transport.
|
||||
|
||||
| Argument | Description |
|
||||
| -------- | ----------- |
|
||||
| `peer` | npub (bech32) or hostname from `/etc/fips/hosts`. |
|
||||
| `address` | Transport endpoint, e.g. `192.168.1.10:2121`, `[2001:db8::1]:2121`, or a Tor onion. FIPS-mesh ULAs (`fd00::/8`) are rejected for the IP-based transports (udp, tcp, ethernet). |
|
||||
| `transport` | One of `udp`, `tcp`, `tor`, `ethernet`. |
|
||||
|
||||
### `disconnect <peer>`
|
||||
|
||||
Tell the daemon to drop a peer link.
|
||||
|
||||
| Argument | Description |
|
||||
| -------- | ----------- |
|
||||
| `peer` | npub (bech32) or hostname from `/etc/fips/hosts`. |
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
| ---- | ------- |
|
||||
| `0` | Daemon returned `{"status":"ok",...}`. |
|
||||
| `1` | Argument parse failure, control-socket connection failure, daemon returned `{"status":"error",...}`, or local I/O failure (keygen). The error message is printed to stderr. |
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Description |
|
||||
| -------- | ----------- |
|
||||
| `XDG_RUNTIME_DIR` | Used to derive the default control-socket path when `/run/fips` is absent. |
|
||||
|
||||
`fipsctl` does not consume `RUST_LOG`; logging is for the daemon.
|
||||
|
||||
## Files
|
||||
|
||||
| Path | Purpose |
|
||||
| ---- | ------- |
|
||||
| `/etc/fips/hosts` | Maps hostnames to npubs for the `connect`, `disconnect`, and `--peer` arguments. See [configuration.md](configuration.md). |
|
||||
| Control socket (default) | Same resolution as the daemon: `/run/fips/control.sock` if present, else `$XDG_RUNTIME_DIR/fips/control.sock`, else `/tmp/fips-control.sock` (Unix); TCP `localhost:21210` (Windows). |
|
||||
|
||||
If you get `Permission denied` connecting to the socket on Linux,
|
||||
add your user to the `fips` group (`sudo usermod -aG fips $USER`)
|
||||
and log out and back in.
|
||||
|
||||
## See also
|
||||
|
||||
- [`fips`](cli-fips.md) — the daemon.
|
||||
- [`fipstop`](cli-fipstop.md) — live-status TUI.
|
||||
- [control-socket.md](control-socket.md) — wire protocol.
|
||||
- [configuration.md](configuration.md) — YAML reference.
|
||||
@@ -0,0 +1,123 @@
|
||||
# `fipstop`
|
||||
|
||||
Live-status terminal UI for a running FIPS daemon.
|
||||
|
||||
## Synopsis
|
||||
|
||||
```text
|
||||
fipstop [-s SOCKET] [--gateway-socket PATH] [-r SECONDS]
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
`fipstop` is a `ratatui`-based dashboard. It opens the daemon control
|
||||
socket, polls a small set of `show_*` queries on a timer, and renders
|
||||
the state in a tabbed full-screen UI. A separate poll runs against the
|
||||
gateway control socket when the Gateway tab is active.
|
||||
|
||||
`fipstop` is read-only — it cannot mutate daemon state. Use
|
||||
[`fipsctl`](cli-fipsctl.md) for `connect` / `disconnect` and friends.
|
||||
|
||||
## Options
|
||||
|
||||
| Flag | Argument | Default | Description |
|
||||
| ---- | -------- | ------- | ----------- |
|
||||
| `-s`, `--socket` | `PATH` | (auto) | Daemon control-socket path / port. Same default as `fipsctl`. |
|
||||
| `--gateway-socket` | `PATH` | (auto) | `fips-gateway` control-socket path / port. Default: `/run/fips/gateway.sock` (Unix), TCP port `21211` (Windows). |
|
||||
| `-r`, `--refresh` | `SECONDS` | `2` | Poll interval. |
|
||||
| `-V`, `--version` | — | — | Print short version. |
|
||||
| `--version` | — | — | Print long version. |
|
||||
| `-h`, `--help` | — | — | Print usage and exit. |
|
||||
|
||||
## Tabs
|
||||
|
||||
Tabs cycle in this order. Each tab issues the listed control-socket
|
||||
query on its first activation and on every refresh tick while active.
|
||||
|
||||
| Tab | Query | Shows |
|
||||
| --- | ----- | ----- |
|
||||
| **Node** | `show_status` | Identity, version, uptime, peer/link/session counts, sparklines for mesh size, tree depth, peer count, bytes, loss. |
|
||||
| **Peers** | `show_peers` (+ `show_links`, `show_transports` cross-refs) | Authenticated peers in a table. Selecting a row and pressing Enter opens a detail view. |
|
||||
| **Transports** | `show_transports` (+ `show_links`, `show_peers` cross-refs) | Tree of transport instances with per-link children when expanded. |
|
||||
| **Sessions** | `show_sessions` | End-to-end FSP sessions. |
|
||||
| **Tree** | `show_tree` | Spanning-tree state and per-peer coordinates. |
|
||||
| **Filters** | `show_bloom` | Per-peer Bloom-filter state. |
|
||||
| **Performance** | `show_mmp` | Link-layer and session-layer MMP metrics. |
|
||||
| **Routing** | `show_routing` (+ `show_cache` cross-ref) | Forwarding/discovery counters, pending lookups, retry state. |
|
||||
| **Graphs** | `show_stats_history` family + `show_stats_peers` | Stacked time-series plots. Three modes: node-level metrics, one metric across peers, all metrics for one peer. |
|
||||
| **Gateway** | `show_gateway` and `show_mappings` against the gateway socket | Pool utilisation and per-mapping state when `fips-gateway` is running. Empty when the gateway socket is unreachable. |
|
||||
|
||||
The cycle order in the UI is: Node → Peers → Transports → Sessions →
|
||||
Tree → Filters → Performance → Routing → Graphs → Gateway. The Links
|
||||
and Cache tabs are not in the cycle but are fetched as cross-references
|
||||
to populate Peers, Transports, and Routing detail views.
|
||||
|
||||
## Keybindings
|
||||
|
||||
### Global
|
||||
|
||||
| Key | Action |
|
||||
| --- | ------ |
|
||||
| `q`, `Ctrl-C` | Quit. |
|
||||
| `Tab` | Next tab. |
|
||||
| `Shift-Tab` | Previous tab. |
|
||||
| `g` | Jump to the Graphs tab. |
|
||||
| `Esc` | Close detail view (if open). |
|
||||
|
||||
### Table tabs (Peers, Sessions, Transports, Gateway)
|
||||
|
||||
| Key | Action |
|
||||
| --- | ------ |
|
||||
| `Up`, `Down` | Move row selection. |
|
||||
| `Enter` | Open detail view for the selected row. |
|
||||
|
||||
### Transports tab (extra)
|
||||
|
||||
| Key | Action |
|
||||
| --- | ------ |
|
||||
| `Right`, `Space` | Expand the selected transport row to show its links. |
|
||||
| `Left` | Collapse the selected transport row. |
|
||||
| `e` | Expand all transports. |
|
||||
| `c` | Collapse all transports. |
|
||||
|
||||
### Graphs tab (extra)
|
||||
|
||||
| Key | Action |
|
||||
| --- | ------ |
|
||||
| `Up`, `Down` | Scroll within the stacked plots. |
|
||||
| `Right`, `Space` | Next time window. Cycles `1m / 1s` → `10m / 1s` → `1h / 1s` → `24h / 1m`. |
|
||||
| `Left` | Previous time window. |
|
||||
| `m` | Cycle view mode: `Node` (stacked node metrics) → `MetricByPeer` (one per-peer metric across all peers) → `PeerByMetric` (all per-peer metrics for one peer). |
|
||||
| `n` | Next selector (next per-peer metric in MetricByPeer; next peer in PeerByMetric). |
|
||||
| `Shift-N` | Previous selector. |
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
| ---- | ------- |
|
||||
| `0` | Normal quit. |
|
||||
| `1` | Failed to initialise the terminal. The reason is printed to stderr. |
|
||||
|
||||
A failure to reach the daemon socket is **not** fatal: the dashboard
|
||||
displays "Disconnected" in the status bar and retries on every refresh
|
||||
tick.
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Description |
|
||||
| -------- | ----------- |
|
||||
| `XDG_RUNTIME_DIR` | Used to derive the default control-socket and gateway-socket paths when `/run/fips` is absent. |
|
||||
|
||||
## Files
|
||||
|
||||
Same control-socket resolution rules as
|
||||
[`fipsctl`](cli-fipsctl.md#files). The gateway socket follows the same
|
||||
pattern with `gateway.sock` in place of `control.sock`, falling back
|
||||
to `/tmp/fips-gateway.sock` if neither system path nor
|
||||
`XDG_RUNTIME_DIR` is available.
|
||||
|
||||
## See also
|
||||
|
||||
- [`fipsctl`](cli-fipsctl.md) — issue mutating commands.
|
||||
- [`fips`](cli-fips.md) — the daemon.
|
||||
- [control-socket.md](control-socket.md) — wire protocol fipstop polls.
|
||||
@@ -0,0 +1,166 @@
|
||||
# Control Socket Protocol
|
||||
|
||||
The FIPS daemon and `fips-gateway` each expose a local control socket
|
||||
that accepts line-delimited JSON requests and returns line-delimited
|
||||
JSON responses. `fipsctl` and `fipstop` are clients of this protocol;
|
||||
operators can also drive it directly with any tool that can speak
|
||||
length-bounded JSON over a stream socket.
|
||||
|
||||
## Connection
|
||||
|
||||
### Linux / macOS
|
||||
|
||||
A Unix domain socket. The default path is resolved in this order:
|
||||
|
||||
1. `/run/fips/control.sock` (or `/run/fips/gateway.sock` for the
|
||||
gateway), if `/run/fips` exists. This is what the `fips.service`
|
||||
systemd unit creates.
|
||||
2. `$XDG_RUNTIME_DIR/fips/control.sock` otherwise.
|
||||
3. `/tmp/fips-control.sock` if neither of the above is available.
|
||||
|
||||
The daemon `chown`s the socket file and its parent directory to the
|
||||
`fips` group at bind time and sets mode `0770`. Members of the `fips`
|
||||
group can therefore connect without root. Add a user with
|
||||
`sudo usermod -aG fips $USER` (re-login required).
|
||||
|
||||
The path can be overridden at the daemon side via
|
||||
`node.control.socket_path` in the YAML config, and at the client side
|
||||
via `fipsctl -s PATH` or `fipstop -s PATH`.
|
||||
|
||||
### Windows
|
||||
|
||||
A TCP listener bound to `127.0.0.1`. The daemon's port is `21210` by
|
||||
default; the gateway's is `21211`. Only loopback connections are
|
||||
accepted. Override via `node.control.socket_path` (which takes a port
|
||||
number string on Windows).
|
||||
|
||||
Windows TCP does not provide filesystem-level ACLs — any local user
|
||||
can connect. See the security note in
|
||||
[configuration.md](configuration.md#control-socket-nodecontrol).
|
||||
|
||||
## Request Format
|
||||
|
||||
One JSON object per line, terminated by `\n`. Maximum request size is
|
||||
4096 bytes; longer requests are dropped with `request too large`.
|
||||
|
||||
```json
|
||||
{"command": "<name>", "params": {<object>}}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ----- | ---- | -------- | ----------- |
|
||||
| `command` | string | yes | Command name. See [Daemon command catalog](#daemon-command-catalog) and [Gateway command catalog](#gateway-command-catalog). |
|
||||
| `params` | object | only for commands that take parameters | Parameter object. Unknown fields are ignored; missing required fields produce an error response. |
|
||||
|
||||
Unknown top-level fields in the request are silently ignored.
|
||||
|
||||
## Response Format
|
||||
|
||||
One JSON object per line.
|
||||
|
||||
```json
|
||||
{"status": "ok", "data": {<object>}}
|
||||
{"status": "error", "message": "<reason>"}
|
||||
```
|
||||
|
||||
| Field | Type | When present |
|
||||
| ----- | ---- | ------------ |
|
||||
| `status` | string | always; one of `"ok"` or `"error"`. |
|
||||
| `data` | object | on `ok` responses. |
|
||||
| `message` | string | on `error` responses. |
|
||||
|
||||
### I/O timeouts
|
||||
|
||||
The daemon enforces a 5-second timeout for both the request read and
|
||||
the response write. If the connection idles longer than that, the
|
||||
daemon closes it with no response.
|
||||
|
||||
### Common error messages
|
||||
|
||||
| Message | Cause |
|
||||
| ------- | ----- |
|
||||
| `empty request` | Connection closed before a newline was received. |
|
||||
| `invalid request: <serde error>` | Malformed JSON or missing `command`. |
|
||||
| `request too large` | Request exceeded 4096 bytes. |
|
||||
| `read timeout` / `read error: ...` | Slow client or transport failure. |
|
||||
| `unknown command: <name>` | Command not registered with this daemon. |
|
||||
| `missing params for <name>` | Command requires `params` but none were provided. |
|
||||
| `missing '<field>' parameter` | Required parameter missing. |
|
||||
| `query timeout` | Internal handler did not respond within 5 seconds. |
|
||||
| `node shutting down` | Daemon is exiting. |
|
||||
| `gateway not yet initialized` | (Gateway socket only) snapshot has not been published yet. |
|
||||
|
||||
## Daemon Command Catalog
|
||||
|
||||
Read-only queries are dispatched in `src/control/queries.rs`;
|
||||
mutating commands are dispatched in `src/control/commands.rs`. The
|
||||
table below lists every command currently registered.
|
||||
|
||||
### Read-only queries
|
||||
|
||||
| Command | Params | `data` shape (top-level keys) |
|
||||
| ------- | ------ | ----------------------------- |
|
||||
| `show_status` | — | `version`, `npub`, `node_addr`, `ipv6_addr`, `state`, `is_leaf_only`, `peer_count`, `session_count`, `link_count`, `transport_count`, `connection_count`, `tun_state`, `tun_name`, `effective_ipv6_mtu`, `control_socket`, `pid`, `exe_path`, `uptime_secs`, `estimated_mesh_size`, `forwarding`, `sparklines`. |
|
||||
| `show_acl` | — | `allow_file`, `deny_file`, `enforcement_active`, `effective_mode`, `default_decision`, `allow_all`, `deny_all`, `allow_file_entries`, `deny_file_entries`, `allow_entries`, `deny_entries`. |
|
||||
| `show_peers` | — | `peers[]` — per-peer object: `node_addr`, `npub`, `display_name`, `ipv6_addr`, `connectivity`, `link_id`, `direction`, `transport_addr`, `transport_type`, `is_parent`, `is_child`, `tree_depth`, `stats`, `noise`, `current_k_bit`, `mmp`, plus optional `nostr_traversal`, `rekey_in_progress`, `rekey_draining`. |
|
||||
| `show_links` | — | `links[]` — `link_id`, `transport_id`, `remote_addr`, `direction`, `state`, `created_at_ms`, `stats`. |
|
||||
| `show_tree` | — | `my_node_addr`, `root`, `is_root`, `depth`, `my_coords[]`, `parent`, `parent_display_name`, `declaration_sequence`, `declaration_signed`, `peer_tree_count`, `peers[]`, `stats`. |
|
||||
| `show_sessions` | — | `sessions[]` — `remote_addr`, `npub`, `display_name`, `state` (`established`, `initiating`, `awaiting_msg3`, `unknown`), `is_initiator`, `last_activity_ms`, `stats`, optional `mmp`, `current_k_bit`, `is_draining`. |
|
||||
| `show_bloom` | — | `own_node_addr`, `is_leaf_only`, `sequence`, `leaf_dependent_count`, `leaf_dependents[]`, `peer_filters[]`, `stats`. |
|
||||
| `show_mmp` | — | `peers[]` (link-layer per peer), `sessions[]` (session-layer per session). Each entry includes loss/RTT/ETX/goodput, smoothed values, trends. |
|
||||
| `show_cache` | — | `count`, `max_entries`, `fill_ratio`, `default_ttl_ms`, `expired`, `avg_age_ms`, `entries[]` — per-destination coords, depth, age, last-used, optional `path_mtu`. |
|
||||
| `show_connections` | — | `connections[]` — pending handshakes: `link_id`, `direction`, `handshake_state`, `started_at_ms`, `idle_ms`, `resend_count`, optional `expected_peer`. |
|
||||
| `show_transports` | — | `transports[]` — `transport_id`, `type`, `state`, `mtu`, `name`, `local_addr`, optional `tor_mode`, `onion_address`, `tor_monitoring`, `stats`. |
|
||||
| `show_routing` | — | `coord_cache_entries`, `identity_cache_entries`, `pending_lookups[]`, `pending_tun_destinations`, `pending_tun_packets`, `recent_requests`, `retries[]`, `forwarding`, `discovery`, `error_signals`, `congestion`. |
|
||||
| `show_identity_cache` | — | `entries[]`, `count`, `max_entries`. Each entry: `node_addr`, `npub`, `display_name`, `ipv6_addr`, `last_seen_ms`, `age_ms`. |
|
||||
| `show_stats_list` | — | `metrics[]` (each with `name`, `unit`, `scope`), `fast_ring_seconds`, `slow_ring_minutes`, `peer_retention_seconds`. |
|
||||
| `show_stats_history` | `metric` (req), `peer` (req for per-peer metrics), `window` (`<N>s` / `<N>m` / `<N>h`, default `10m`), `granularity` (`1s` / `1m`, default `1s`) | A single `Series`: `metric`, `unit`, `granularity_seconds`, `values[]`. |
|
||||
| `show_stats_all_history` | `peer` (optional npub), `window`, `granularity` | `granularity_seconds`, `window_seconds`, `peer`, `series[]` (one per metric). |
|
||||
| `show_stats_peers` | — | `peers[]`, `count`. Each entry: `npub`, `node_addr`, `display_name`, `is_active`, `first_seen_secs_ago`, `last_contact_secs_ago`. |
|
||||
| `show_stats_history_all_peers` | `metric` (req per-peer name), `window`, `granularity` | `metric`, `unit`, `granularity_seconds`, `window_seconds`, `peers[]` (each with `node_addr`, `display_name`, `is_active`, `values[]`). |
|
||||
|
||||
The schema of each query response is pinned by snapshot tests in
|
||||
`src/control/snapshots/`; intentional schema changes regenerate those
|
||||
fixtures.
|
||||
|
||||
### Mutating commands
|
||||
|
||||
| Command | Required params | Behaviour |
|
||||
| ------- | --------------- | --------- |
|
||||
| `connect` | `npub` (bech32), `address` (transport endpoint), `transport` (`udp`, `tcp`, `tor`, `ethernet`) | Asks the node to dial the peer over the named transport. Returns the API result on success or an error string on failure. |
|
||||
| `disconnect` | `npub` (bech32) | Asks the node to drop the link to the named peer. |
|
||||
|
||||
Both commands run on the daemon's main task and may block briefly
|
||||
while the node mutates its state.
|
||||
|
||||
## Gateway Command Catalog
|
||||
|
||||
`fips-gateway` exposes a separate control socket with its own command
|
||||
set. Dispatch lives in `src/gateway/control.rs`.
|
||||
|
||||
| Command | Params | `data` shape |
|
||||
| ------- | ------ | ------------ |
|
||||
| `show_gateway` | — | `pool_total`, `pool_allocated`, `pool_active`, `pool_draining`, `pool_free`, `nat_mappings`, `dns_listen`, `uptime_secs`, `pool_cidr`, `lan_interface`, `dns_upstream`, `dns_ttl`, `pool_grace_period`. |
|
||||
| `show_mappings` | — | `mappings[]` — `virtual_ip`, `mesh_addr`, `node_addr`, `dns_name`, `state` (`Allocated`, `Active`, `Draining`), `sessions`, `age_secs`, `last_ref_secs`. |
|
||||
|
||||
Until the first snapshot has been published (very early in startup),
|
||||
both commands return `gateway not yet initialized`.
|
||||
|
||||
## Driving the Socket Directly
|
||||
|
||||
```sh
|
||||
# Linux / macOS
|
||||
echo '{"command":"show_status"}' | sudo nc -U /run/fips/control.sock
|
||||
|
||||
# Windows (PowerShell with a TCP-capable tool of your choice)
|
||||
```
|
||||
|
||||
The newline at the end of the request is required: the daemon reads
|
||||
one line per connection. The connection is closed after the single
|
||||
response is written.
|
||||
|
||||
## See also
|
||||
|
||||
- [`fipsctl`](cli-fipsctl.md) — full-featured client.
|
||||
- [`fipstop`](cli-fipstop.md) — read-only TUI.
|
||||
- [configuration.md](configuration.md) — `node.control.*` keys.
|
||||
@@ -0,0 +1,28 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 192" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="192" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">AncestryEntry (32 bytes)</text>
|
||||
|
||||
<!-- Row 0 (0–15): node_addr -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–15</text>
|
||||
|
||||
<rect x="55" y="36" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="58" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">node_addr</text>
|
||||
<text x="315" y="76" fill="#8af8f8" text-anchor="middle" font-size="10">16 bytes — routing identifier</text>
|
||||
|
||||
<!-- Row 1 (16–23): sequence -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">16–23</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">sequence</text>
|
||||
<text x="315" y="128" fill="#f8c88a" text-anchor="middle" font-size="10">8 bytes LE</text>
|
||||
|
||||
<!-- Row 2 (24–31): timestamp -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">24–31</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">timestamp</text>
|
||||
<text x="315" y="180" fill="#d8a0f8" text-anchor="middle" font-size="10">8 bytes LE — Unix seconds</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,39 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 160" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="160" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="290" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">FMP/FSP Common Prefix (4 bytes)</text>
|
||||
|
||||
<!-- Bit ruler -->
|
||||
<text x="65" y="50" fill="#888" font-size="10" text-anchor="middle">0</text>
|
||||
<text x="130" y="50" fill="#888" font-size="10" text-anchor="middle">4</text>
|
||||
<text x="195" y="50" fill="#888" font-size="10" text-anchor="middle">8</text>
|
||||
<text x="325" y="50" fill="#888" font-size="10" text-anchor="middle">16</text>
|
||||
<text x="530" y="50" fill="#888" font-size="10" text-anchor="middle">32</text>
|
||||
|
||||
<!-- Byte 0: version (high nibble) -->
|
||||
<rect x="35" y="56" width="95" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="82" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ver</text>
|
||||
<text x="82" y="98" fill="#8ab4f8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<!-- Byte 0: phase (low nibble) -->
|
||||
<rect x="130" y="56" width="95" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="177" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">phase</text>
|
||||
<text x="177" y="98" fill="#8af8c8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<!-- Byte 1: flags -->
|
||||
<rect x="225" y="56" width="130" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="290" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="290" y="98" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<!-- Bytes 2-3: payload_len -->
|
||||
<rect x="355" y="56" width="200" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="455" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">payload_len</text>
|
||||
<text x="455" y="98" fill="#d8a0f8" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Byte offset labels -->
|
||||
<text x="82" y="130" fill="#666" font-size="10" text-anchor="middle">byte 0</text>
|
||||
<text x="290" y="130" fill="#666" font-size="10" text-anchor="middle">byte 1</text>
|
||||
<text x="455" y="130" fill="#666" font-size="10" text-anchor="middle">bytes 2-3</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,34 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 218" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="218" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">CoordsRequired (0x20) — 34 bytes payload</text>
|
||||
|
||||
<!-- Row 0 (0–1): msg_type + flags -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–1</text>
|
||||
|
||||
<rect x="55" y="36" width="260" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="58" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="185" y="76" fill="#8ab4f8" text-anchor="middle" font-size="10">0x20</text>
|
||||
|
||||
<rect x="315" y="36" width="260" height="52" fill="#1f1f3a" stroke="#444" stroke-width="1" rx="3"/>
|
||||
<text x="445" y="62" fill="#666" text-anchor="middle" font-size="12">flags (reserved)</text>
|
||||
|
||||
<!-- Row 1 (2–17): dest_addr -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">2–17</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">dest_addr</text>
|
||||
<text x="315" y="128" fill="#d8a0f8" text-anchor="middle" font-size="10">16 bytes — NodeAddr we couldn't route to</text>
|
||||
|
||||
<!-- Row 2 (18–33): reporter -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">18–33</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">reporter</text>
|
||||
<text x="315" y="180" fill="#8af8f8" text-anchor="middle" font-size="10">16 bytes — NodeAddr of reporting router</text>
|
||||
|
||||
<!-- Note -->
|
||||
<text x="310" y="212" fill="#777" font-size="10" text-anchor="middle">plaintext error signal (U flag set) · total on wire: 38 bytes (4 prefix + 34 payload)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 114" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="114" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">Disconnect (0x50) — 2 bytes</text>
|
||||
|
||||
<!-- Row 0 (0–1): msg_type + reason -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–1</text>
|
||||
|
||||
<rect x="55" y="36" width="260" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="185" y="78" fill="#8ab4f8" text-anchor="middle" font-size="10">0x50</text>
|
||||
|
||||
<rect x="315" y="36" width="260" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="445" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">reason</text>
|
||||
<text x="445" y="78" fill="#f88aaa" text-anchor="middle" font-size="10">1 byte</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,91 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 498" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="498" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">Complete Encrypted Frame (37 + body bytes)</text>
|
||||
|
||||
<!-- Bit ruler -->
|
||||
<text x="85" y="50" fill="#888" font-size="10" text-anchor="middle">0</text>
|
||||
<text x="150" y="50" fill="#888" font-size="10" text-anchor="middle">4</text>
|
||||
<text x="215" y="50" fill="#888" font-size="10" text-anchor="middle">8</text>
|
||||
<text x="345" y="50" fill="#888" font-size="10" text-anchor="middle">16</text>
|
||||
<text x="550" y="50" fill="#888" font-size="10" text-anchor="middle">32</text>
|
||||
|
||||
<!-- Row 0: Common prefix (bytes 0-3) -->
|
||||
<text x="50" y="82" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="56" width="95" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="102" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ver</text>
|
||||
<text x="102" y="98" fill="#8ab4f8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="150" y="56" width="95" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="197" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">phase</text>
|
||||
<text x="197" y="98" fill="#8af8c8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="245" y="56" width="130" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="310" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="310" y="98" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="375" y="56" width="200" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="475" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">payload_len</text>
|
||||
<text x="475" y="98" fill="#d8a0f8" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Row 1: receiver_idx (bytes 4-7) -->
|
||||
<text x="50" y="134" fill="#666" font-size="10" text-anchor="end">4–7</text>
|
||||
|
||||
<rect x="55" y="108" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="132" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">receiver_idx</text>
|
||||
<text x="315" y="150" fill="#8af8f8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Row 2: counter low (bytes 8-11) -->
|
||||
<text x="50" y="186" fill="#666" font-size="10" text-anchor="end">8–11</text>
|
||||
|
||||
<rect x="55" y="160" width="520" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="190" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">counter / lower 4 bytes LE</text>
|
||||
|
||||
<!-- Row 3: counter high (bytes 12-15) -->
|
||||
<text x="50" y="238" fill="#666" font-size="10" text-anchor="end">12–15</text>
|
||||
|
||||
<rect x="55" y="212" width="520" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="242" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">counter / upper 4 bytes LE</text>
|
||||
|
||||
<!-- AAD bracket -->
|
||||
<text x="10" y="166" fill="#777" font-size="10" text-anchor="middle" transform="rotate(-90, 10, 166)">AAD</text>
|
||||
<line x1="18" y1="56" x2="18" y2="264" stroke="#555" stroke-width="1"/>
|
||||
<line x1="18" y1="56" x2="23" y2="56" stroke="#555" stroke-width="1"/>
|
||||
<line x1="18" y1="264" x2="23" y2="264" stroke="#555" stroke-width="1"/>
|
||||
|
||||
<!-- Separator: cleartext above / ciphertext below -->
|
||||
<line x1="55" y1="272" x2="575" y2="272" stroke="#555" stroke-width="1" stroke-dasharray="6,4"/>
|
||||
<text x="315" y="288" fill="#777" font-size="10" text-anchor="middle">── ciphertext (encrypted with ChaCha20-Poly1305) ──</text>
|
||||
|
||||
<!-- Row 4: timestamp (bytes 16-19, encrypted) -->
|
||||
<text x="50" y="322" fill="#666" font-size="10" text-anchor="end">16–19</text>
|
||||
|
||||
<rect x="55" y="296" width="520" height="52" fill="#3d4a2d" stroke="#8ad94a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="320" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">timestamp</text>
|
||||
<text x="315" y="338" fill="#c8f88a" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Row 5: msg_type (1 byte) + body starts -->
|
||||
<text x="50" y="374" fill="#666" font-size="10" text-anchor="end">20</text>
|
||||
|
||||
<rect x="55" y="348" width="130" height="52" fill="#4a3d2d" stroke="#d9b04a" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="372" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="120" y="390" fill="#f8d88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="185" y="348" width="390" height="52" fill="#1f1f3a" stroke="#444" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="380" y="374" fill="#666" text-anchor="middle" font-size="11">message body ...</text>
|
||||
|
||||
<!-- Row 6: body variable -->
|
||||
<text x="50" y="426" fill="#666" font-size="10" text-anchor="end">...</text>
|
||||
|
||||
<rect x="55" y="400" width="520" height="52" fill="#1f1f3a" stroke="#444" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="430" fill="#666" text-anchor="middle" font-size="11">message body (variable length)</text>
|
||||
|
||||
<!-- AEAD tag -->
|
||||
<text x="50" y="478" fill="#666" font-size="10" text-anchor="end">+16</text>
|
||||
|
||||
<rect x="55" y="452" width="520" height="30" fill="#4a2d4a" stroke="#b04ab0" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="472" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">Poly1305 AEAD tag (16 bytes)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 186" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="186" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">Established Frame Inner Header (5 bytes, plaintext after decrypt)</text>
|
||||
|
||||
<!-- Bit ruler -->
|
||||
<text x="85" y="50" fill="#888" font-size="10" text-anchor="middle">0</text>
|
||||
<text x="215" y="50" fill="#888" font-size="10" text-anchor="middle">8</text>
|
||||
<text x="345" y="50" fill="#888" font-size="10" text-anchor="middle">16</text>
|
||||
<text x="550" y="50" fill="#888" font-size="10" text-anchor="middle">32</text>
|
||||
|
||||
<!-- Row 0: timestamp (bytes 0-3) -->
|
||||
<text x="50" y="82" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="56" width="520" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">timestamp</text>
|
||||
<text x="315" y="98" fill="#8af8c8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Row 1: msg_type (byte 4) -->
|
||||
<text x="50" y="134" fill="#666" font-size="10" text-anchor="end">4</text>
|
||||
|
||||
<rect x="55" y="108" width="130" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="132" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="120" y="150" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<!-- Row 1: body starts -->
|
||||
<rect x="185" y="108" width="390" height="52" fill="#1f1f3a" stroke="#444" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="380" y="134" fill="#666" text-anchor="middle" font-size="11">message body ...</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,52 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 290" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="290" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">Established Frame Outer Header (16 bytes, AEAD AAD)</text>
|
||||
|
||||
<!-- Bit ruler -->
|
||||
<text x="85" y="50" fill="#888" font-size="10" text-anchor="middle">0</text>
|
||||
<text x="150" y="50" fill="#888" font-size="10" text-anchor="middle">4</text>
|
||||
<text x="215" y="50" fill="#888" font-size="10" text-anchor="middle">8</text>
|
||||
<text x="345" y="50" fill="#888" font-size="10" text-anchor="middle">16</text>
|
||||
<text x="550" y="50" fill="#888" font-size="10" text-anchor="middle">32</text>
|
||||
|
||||
<!-- Row 0: Common prefix (bytes 0-3) -->
|
||||
<text x="50" y="82" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="56" width="95" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="102" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ver</text>
|
||||
<text x="102" y="98" fill="#8ab4f8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="150" y="56" width="95" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="197" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">phase</text>
|
||||
<text x="197" y="98" fill="#8af8c8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="245" y="56" width="130" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="310" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="310" y="98" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="375" y="56" width="200" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="475" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">payload_len</text>
|
||||
<text x="475" y="98" fill="#d8a0f8" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Row 1: receiver_idx (bytes 4-7) -->
|
||||
<text x="50" y="134" fill="#666" font-size="10" text-anchor="end">4–7</text>
|
||||
|
||||
<rect x="55" y="108" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="132" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">receiver_idx</text>
|
||||
<text x="315" y="150" fill="#8af8f8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Row 2: counter low (bytes 8-11) -->
|
||||
<text x="50" y="186" fill="#666" font-size="10" text-anchor="end">8–11</text>
|
||||
|
||||
<rect x="55" y="160" width="520" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="190" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">counter / lower 4 bytes LE</text>
|
||||
|
||||
<!-- Row 3: counter high (bytes 12-15) -->
|
||||
<text x="50" y="238" fill="#666" font-size="10" text-anchor="end">12–15</text>
|
||||
|
||||
<rect x="55" y="212" width="520" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="242" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">counter / upper 4 bytes LE</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,52 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 374" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="374" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">FilterAnnounce (0x20) — 19-byte header + RLE payload</text>
|
||||
|
||||
<!-- Row 0 (0-1): msg_type + flags -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–1</text>
|
||||
|
||||
<rect x="55" y="36" width="130" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="56" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="120" y="74" fill="#8ab4f8" text-anchor="middle" font-size="10">0x20</text>
|
||||
|
||||
<rect x="185" y="36" width="390" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="380" y="56" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="380" y="74" fill="#8af8c8" text-anchor="middle" font-size="10">1 byte — bit 0: delta (XOR diff)</text>
|
||||
|
||||
<!-- Row 1 (2-9): sequence -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">2–9</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">sequence</text>
|
||||
<text x="315" y="128" fill="#f8c88a" text-anchor="middle" font-size="10">8 bytes LE — per-peer monotonic counter</text>
|
||||
|
||||
<!-- Row 2 (10-17): base_seq -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">10–17</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">base_seq</text>
|
||||
<text x="315" y="180" fill="#d8a0f8" text-anchor="middle" font-size="10">8 bytes LE — reference sequence for delta (0 if full)</text>
|
||||
|
||||
<!-- Row 3 (18): size_class -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">18</text>
|
||||
|
||||
<rect x="55" y="192" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="214" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">size_class</text>
|
||||
<text x="315" y="232" fill="#8af8f8" text-anchor="middle" font-size="10">1 byte — filter size = 512 « size_class bytes</text>
|
||||
|
||||
<!-- Row 4 (19-): compressed_payload -->
|
||||
<text x="50" y="270" fill="#666" font-size="10" text-anchor="end">19–</text>
|
||||
|
||||
<rect x="55" y="250" width="520" height="40" fill="#1f1f3a" stroke="#4a9090" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="274" fill="#8ad8d8" text-anchor="middle" font-size="11">compressed_payload (RLE: [count:2 LE][word:8 LE] per run)</text>
|
||||
|
||||
<!-- Explanation -->
|
||||
<rect x="55" y="304" width="520" height="32" fill="#1f1f3a" stroke="#444" stroke-width="1" rx="3"/>
|
||||
<text x="315" y="324" fill="#888" text-anchor="middle" font-size="10">delta: XOR diff of current vs last-sent filter — full: raw filter words</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="362" fill="#777" font-size="10" text-anchor="middle">19-byte header + variable compressed payload</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,97 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 524" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="524" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">FSP Complete Encrypted Message (34 + body bytes)</text>
|
||||
|
||||
<!-- Bit ruler -->
|
||||
<text x="85" y="50" fill="#888" font-size="10" text-anchor="middle">0</text>
|
||||
<text x="150" y="50" fill="#888" font-size="10" text-anchor="middle">4</text>
|
||||
<text x="215" y="50" fill="#888" font-size="10" text-anchor="middle">8</text>
|
||||
<text x="345" y="50" fill="#888" font-size="10" text-anchor="middle">16</text>
|
||||
<text x="550" y="50" fill="#888" font-size="10" text-anchor="middle">32</text>
|
||||
|
||||
<!-- Row 0: Common prefix (bytes 0-3) -->
|
||||
<text x="50" y="82" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="56" width="95" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="102" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ver</text>
|
||||
<text x="102" y="98" fill="#8ab4f8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="150" y="56" width="95" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="197" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">phase</text>
|
||||
<text x="197" y="98" fill="#8af8c8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="245" y="56" width="130" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="310" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="310" y="98" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="375" y="56" width="200" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="475" y="80" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">payload_len</text>
|
||||
<text x="475" y="98" fill="#d8a0f8" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Row 1: counter low (bytes 4-7) -->
|
||||
<text x="50" y="134" fill="#666" font-size="10" text-anchor="end">4–7</text>
|
||||
|
||||
<rect x="55" y="108" width="520" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="138" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">counter / lower 4 bytes LE</text>
|
||||
|
||||
<!-- Row 2: counter high (bytes 8-11) -->
|
||||
<text x="50" y="186" fill="#666" font-size="10" text-anchor="end">8–11</text>
|
||||
|
||||
<rect x="55" y="160" width="520" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="190" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">counter / upper 4 bytes LE</text>
|
||||
|
||||
<!-- AAD bracket -->
|
||||
<text x="10" y="134" fill="#777" font-size="10" text-anchor="middle" transform="rotate(-90, 10, 134)">AAD</text>
|
||||
<line x1="18" y1="56" x2="18" y2="212" stroke="#555" stroke-width="1"/>
|
||||
<line x1="18" y1="56" x2="23" y2="56" stroke="#555" stroke-width="1"/>
|
||||
<line x1="18" y1="212" x2="23" y2="212" stroke="#555" stroke-width="1"/>
|
||||
|
||||
<!-- Optional coords -->
|
||||
<text x="50" y="238" fill="#666" font-size="10" text-anchor="end">opt</text>
|
||||
|
||||
<rect x="55" y="220" width="520" height="40" fill="#1f1f3a" stroke="#4ad99a" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="244" fill="#8af8c8" text-anchor="middle" font-size="11">cleartext coordinates (if CP flag set, variable length)</text>
|
||||
|
||||
<!-- Separator: ciphertext below -->
|
||||
<line x1="55" y1="268" x2="575" y2="268" stroke="#555" stroke-width="1" stroke-dasharray="6,4"/>
|
||||
<text x="315" y="284" fill="#777" font-size="10" text-anchor="middle">── ciphertext (encrypted with ChaCha20-Poly1305) ──</text>
|
||||
|
||||
<!-- Row 3: timestamp (4 bytes, encrypted) -->
|
||||
<text x="50" y="318" fill="#666" font-size="10" text-anchor="end">+0–3</text>
|
||||
|
||||
<rect x="55" y="292" width="520" height="52" fill="#3d4a2d" stroke="#8ad94a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="316" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">timestamp</text>
|
||||
<text x="315" y="334" fill="#c8f88a" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Row 4: msg_type (1) + inner_flags (1) + body starts -->
|
||||
<text x="50" y="370" fill="#666" font-size="10" text-anchor="end">+4</text>
|
||||
|
||||
<rect x="55" y="344" width="130" height="52" fill="#4a3d2d" stroke="#d9b04a" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="368" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="120" y="386" fill="#f8d88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="185" y="344" width="130" height="52" fill="#3d3d2d" stroke="#a0a04a" stroke-width="1.5" rx="3"/>
|
||||
<text x="250" y="368" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">inner_flags</text>
|
||||
<text x="250" y="386" fill="#d8d88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="315" y="344" width="260" height="52" fill="#1f1f3a" stroke="#444" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="445" y="374" fill="#666" text-anchor="middle" font-size="11">body ...</text>
|
||||
|
||||
<!-- Row 5: body variable -->
|
||||
<text x="50" y="422" fill="#666" font-size="10" text-anchor="end">...</text>
|
||||
|
||||
<rect x="55" y="396" width="520" height="52" fill="#1f1f3a" stroke="#444" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="426" fill="#666" text-anchor="middle" font-size="11">message body (variable length)</text>
|
||||
|
||||
<!-- AEAD tag -->
|
||||
<text x="50" y="468" fill="#666" font-size="10" text-anchor="end">+16</text>
|
||||
|
||||
<rect x="55" y="452" width="520" height="30" fill="#4a2d4a" stroke="#b04ab0" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="472" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">Poly1305 AEAD tag (16 bytes)</text>
|
||||
|
||||
<!-- Totals -->
|
||||
<text x="310" y="510" fill="#777" font-size="10" text-anchor="middle">overhead: 34 bytes (12 header + 6 inner + 16 tag) · coords add variable length</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
@@ -0,0 +1,75 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 620 620" font-family="monospace" font-size="13">
|
||||
<defs>
|
||||
<marker id="arrowR" markerWidth="10" markerHeight="8" refX="9" refY="4" orient="auto" markerUnits="userSpaceOnUse">
|
||||
<polygon points="0,0 10,4 0,8" fill="#e0e0e0"/>
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
<!-- Background -->
|
||||
<rect width="620" height="620" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">FMP Handshake Flow (Noise XX)</text>
|
||||
|
||||
<!-- Column headers -->
|
||||
<text x="100" y="54" fill="#8ab4f8" text-anchor="middle" font-size="12" font-weight="bold">Initiator</text>
|
||||
<text x="520" y="54" fill="#8ab4f8" text-anchor="middle" font-size="12" font-weight="bold">Responder</text>
|
||||
|
||||
<!-- Lifelines -->
|
||||
<line x1="100" y1="62" x2="100" y2="600" stroke="#333" stroke-width="1" stroke-dasharray="4,4"/>
|
||||
<line x1="520" y1="62" x2="520" y2="600" stroke="#333" stroke-width="1" stroke-dasharray="4,4"/>
|
||||
|
||||
<!-- Step 1: Initiator prepares -->
|
||||
<text x="20" y="88" fill="#8af8c8" font-size="10">generates sender_idx</text>
|
||||
<text x="20" y="102" fill="#8af8c8" font-size="10">generates ephemeral keypair</text>
|
||||
|
||||
<!-- Arrow 1: msg1 (initiator -> responder) -->
|
||||
<line x1="100" y1="120" x2="520" y2="120" stroke="#4a90d9" stroke-width="1.5" marker-end="url(#arrowR)"/>
|
||||
<rect x="145" y="128" width="330" height="24" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1" rx="3"/>
|
||||
<text x="310" y="144" fill="#e0e0e0" text-anchor="middle" font-size="10">[0x11|flags=0|len] | sender_idx | noise_msg1</text>
|
||||
<text x="310" y="166" fill="#666" text-anchor="middle" font-size="9">phase 0x1 — 41 bytes — pattern: → e</text>
|
||||
|
||||
<!-- Step 2: Responder processes msg1 -->
|
||||
<text x="600" y="192" fill="#8af8c8" font-size="10" text-anchor="end">validates msg1 (ephemeral only)</text>
|
||||
<text x="600" y="206" fill="#8af8c8" font-size="10" text-anchor="end">generates sender_idx</text>
|
||||
<text x="600" y="220" fill="#8af8c8" font-size="10" text-anchor="end">generates ephemeral keypair</text>
|
||||
|
||||
<!-- Arrow 2: msg2 (responder -> initiator) -->
|
||||
<line x1="520" y1="244" x2="100" y2="244" stroke="#4ad99a" stroke-width="1.5" marker-end="url(#arrowR)"/>
|
||||
<rect x="115" y="252" width="390" height="24" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1" rx="3"/>
|
||||
<text x="310" y="268" fill="#e0e0e0" text-anchor="middle" font-size="9">[0x12|flags=0|len] | sender_idx | receiver_idx | noise_msg2 + negotiation</text>
|
||||
<text x="310" y="288" fill="#666" text-anchor="middle" font-size="9">phase 0x2 — 144 bytes — pattern: ← e, ee, s, es</text>
|
||||
<text x="600" y="300" fill="#d8a0f8" font-size="9" text-anchor="end">responder identity revealed</text>
|
||||
|
||||
<!-- Step 3: Initiator processes msg2, learns responder identity -->
|
||||
<text x="20" y="322" fill="#8af8c8" font-size="10">validates msg2</text>
|
||||
<text x="20" y="336" fill="#8af8c8" font-size="10">learns responder identity</text>
|
||||
<text x="20" y="350" fill="#8af8c8" font-size="10">checks epoch (restart detection)</text>
|
||||
|
||||
<!-- Arrow 3: msg3 (initiator -> responder) -->
|
||||
<line x1="100" y1="368" x2="520" y2="368" stroke="#d94a6a" stroke-width="1.5" marker-end="url(#arrowR)"/>
|
||||
<rect x="115" y="376" width="390" height="24" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1" rx="3"/>
|
||||
<text x="310" y="392" fill="#e0e0e0" text-anchor="middle" font-size="9">[0x13|flags=0|len] | sender_idx | receiver_idx | noise_msg3 + neg</text>
|
||||
<text x="310" y="412" fill="#666" text-anchor="middle" font-size="9">phase 0x3 — 111 bytes — pattern: → s, se</text>
|
||||
<text x="20" y="424" fill="#d8a0f8" font-size="9">initiator identity revealed</text>
|
||||
|
||||
<!-- Step 4: Responder processes msg3, learns initiator identity -->
|
||||
<text x="600" y="440" fill="#8af8c8" font-size="10" text-anchor="end">validates msg3</text>
|
||||
<text x="600" y="454" fill="#8af8c8" font-size="10" text-anchor="end">learns initiator identity</text>
|
||||
<text x="600" y="468" fill="#8af8c8" font-size="10" text-anchor="end">checks epoch, derives session keys</text>
|
||||
|
||||
<!-- Handshake complete separator -->
|
||||
<line x1="30" y1="488" x2="230" y2="488" stroke="#d9904a" stroke-width="1.5"/>
|
||||
<text x="310" y="492" fill="#d9904a" text-anchor="middle" font-size="11" font-weight="bold">HANDSHAKE COMPLETE</text>
|
||||
<line x1="390" y1="488" x2="590" y2="488" stroke="#d9904a" stroke-width="1.5"/>
|
||||
|
||||
<!-- Arrow 4: first encrypted frame -->
|
||||
<text x="20" y="516" fill="#777" font-size="10">first encrypted frame:</text>
|
||||
<line x1="100" y1="530" x2="520" y2="530" stroke="#d9b04a" stroke-width="1.5" marker-end="url(#arrowR)"/>
|
||||
<rect x="115" y="538" width="390" height="24" fill="#4a3d2d" stroke="#d9b04a" stroke-width="1" rx="3"/>
|
||||
<text x="310" y="554" fill="#e0e0e0" text-anchor="middle" font-size="9">[0x00|flags|len] | receiver_idx | counter=0 | ciphertext+tag</text>
|
||||
<text x="310" y="574" fill="#666" text-anchor="middle" font-size="9">phase 0x0 — established frame</text>
|
||||
|
||||
<!-- Legend -->
|
||||
<text x="310" y="600" fill="#555" text-anchor="middle" font-size="9">Both parties hold identical symmetric keys. Epoch + negotiation exchanged in msg2/msg3.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,63 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 430" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="430" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">LookupRequest (0x30) — 46 + 16n bytes</text>
|
||||
|
||||
<!-- Row 0 (0–3): msg_type + request_id starts -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="130" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="120" y="78" fill="#8ab4f8" text-anchor="middle" font-size="10">0x30</text>
|
||||
|
||||
<rect x="185" y="36" width="390" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="380" y="66" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">request_id</text>
|
||||
|
||||
<!-- Row 1 (4–8): request_id continued -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4–8</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="118" fill="#f8c88a" text-anchor="middle" font-size="10">8 bytes LE — unique random identifier</text>
|
||||
|
||||
<!-- Row 2 (9–24): target -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">9–24</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">target</text>
|
||||
<text x="315" y="180" fill="#8af8f8" text-anchor="middle" font-size="10">16 bytes — NodeAddr being sought</text>
|
||||
|
||||
<!-- Row 3 (25–40): origin -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">25–40</text>
|
||||
|
||||
<rect x="55" y="192" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="214" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">origin</text>
|
||||
<text x="315" y="232" fill="#d8a0f8" text-anchor="middle" font-size="10">16 bytes — requester's NodeAddr</text>
|
||||
|
||||
<!-- Row 4 (41–43): ttl + min_mtu -->
|
||||
<text x="50" y="270" fill="#666" font-size="10" text-anchor="end">41–43</text>
|
||||
|
||||
<rect x="55" y="244" width="130" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="268" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ttl</text>
|
||||
<text x="120" y="286" fill="#8af8c8" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="185" y="244" width="390" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="380" y="268" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">min_mtu</text>
|
||||
<text x="380" y="286" fill="#f88aaa" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Row 5 (44–45): origin_coords_cnt -->
|
||||
<text x="50" y="322" fill="#666" font-size="10" text-anchor="end">44–45</text>
|
||||
|
||||
<rect x="55" y="296" width="260" height="52" fill="#4a3d2d" stroke="#d9b04a" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="326" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">origin_coords_cnt</text>
|
||||
|
||||
<!-- Row 6 (46–): origin_coords -->
|
||||
<text x="50" y="370" fill="#666" font-size="10" text-anchor="end">46–</text>
|
||||
|
||||
<rect x="55" y="348" width="520" height="40" fill="#1f1f3a" stroke="#4ad9d9" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="372" fill="#8af8f8" text-anchor="middle" font-size="11">origin_coords × n (16 bytes each — NodeAddr only)</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="414" fill="#777" font-size="10" text-anchor="middle">total: 46 + (n × 16) bytes, where n = origin depth + 1</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,56 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 374" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="374" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">LookupResponse (0x31) — 93 + 16n bytes</text>
|
||||
|
||||
<!-- Row 0 (0–3): msg_type + request_id starts -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="130" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="120" y="78" fill="#8ab4f8" text-anchor="middle" font-size="10">0x31</text>
|
||||
|
||||
<rect x="185" y="36" width="390" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="380" y="66" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">request_id</text>
|
||||
|
||||
<!-- Row 1 (4–8): request_id continued -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4–8</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="118" fill="#f8c88a" text-anchor="middle" font-size="10">8 bytes LE — echoes the request's ID</text>
|
||||
|
||||
<!-- Row 2 (9–24): target -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">9–24</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">target</text>
|
||||
<text x="315" y="180" fill="#8af8f8" text-anchor="middle" font-size="10">16 bytes — NodeAddr that was found</text>
|
||||
|
||||
<!-- Row 3 (25–28): path_mtu + target_coords_cnt -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">25–28</text>
|
||||
|
||||
<rect x="55" y="192" width="260" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="214" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">path_mtu</text>
|
||||
<text x="185" y="232" fill="#f88aaa" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<rect x="315" y="192" width="260" height="52" fill="#4a3d2d" stroke="#d9b04a" stroke-width="1.5" rx="3"/>
|
||||
<text x="445" y="214" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">target_coords_cnt</text>
|
||||
<text x="445" y="232" fill="#f8d88a" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Row 4 (29–): target_coords -->
|
||||
<text x="50" y="270" fill="#666" font-size="10" text-anchor="end">29–</text>
|
||||
|
||||
<rect x="55" y="250" width="520" height="40" fill="#1f1f3a" stroke="#4ad9d9" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="274" fill="#8af8f8" text-anchor="middle" font-size="11">target_coords × n (16 bytes each — NodeAddr only)</text>
|
||||
|
||||
<!-- Row 5: proof -->
|
||||
<text x="50" y="316" fill="#666" font-size="10" text-anchor="end">+64</text>
|
||||
|
||||
<rect x="55" y="296" width="520" height="40" fill="#3d4a2d" stroke="#8ad94a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="320" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">Schnorr proof (64 bytes)</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="358" fill="#777" font-size="10" text-anchor="middle">total: 93 + (n × 16) bytes · proof signs (request_id || target || target_coords)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,41 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 270" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="270" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">MtuExceeded (0x22) — 36 bytes payload</text>
|
||||
|
||||
<!-- Row 0 (0–1): msg_type + flags -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–1</text>
|
||||
|
||||
<rect x="55" y="36" width="260" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="58" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="185" y="76" fill="#8ab4f8" text-anchor="middle" font-size="10">0x22</text>
|
||||
|
||||
<rect x="315" y="36" width="260" height="52" fill="#1f1f3a" stroke="#444" stroke-width="1" rx="3"/>
|
||||
<text x="445" y="62" fill="#666" text-anchor="middle" font-size="12">flags (reserved)</text>
|
||||
|
||||
<!-- Row 1 (2–17): dest_addr -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">2–17</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">dest_addr</text>
|
||||
<text x="315" y="128" fill="#d8a0f8" text-anchor="middle" font-size="10">16 bytes — destination being forwarded to</text>
|
||||
|
||||
<!-- Row 2 (18–33): reporter -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">18–33</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">reporter</text>
|
||||
<text x="315" y="180" fill="#8af8f8" text-anchor="middle" font-size="10">16 bytes — NodeAddr of reporting router</text>
|
||||
|
||||
<!-- Row 3 (34–35): mtu -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">34–35</text>
|
||||
|
||||
<rect x="55" y="192" width="260" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="214" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">mtu</text>
|
||||
<text x="185" y="232" fill="#f88aaa" text-anchor="middle" font-size="10">2 bytes LE — bottleneck MTU</text>
|
||||
|
||||
<!-- Note -->
|
||||
<text x="310" y="264" fill="#777" font-size="10" text-anchor="middle">plaintext error signal (U flag set) · total on wire: 40 bytes (4 prefix + 36 payload)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,43 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 218" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="218" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">Noise XX Message 1 — phase 0x1 (41 bytes)</text>
|
||||
|
||||
<!-- Row 0: Common prefix (bytes 0-3) -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="95" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="102" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ver</text>
|
||||
<text x="102" y="78" fill="#8ab4f8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="150" y="36" width="95" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="197" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">phase</text>
|
||||
<text x="197" y="78" fill="#8af8c8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="245" y="36" width="130" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="310" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="310" y="78" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="375" y="36" width="200" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="475" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">payload_len</text>
|
||||
<text x="475" y="78" fill="#d8a0f8" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Row 1: sender_idx (bytes 4-7) -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4–7</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="112" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">sender_idx</text>
|
||||
<text x="315" y="130" fill="#8af8f8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Row 2: ephemeral_pubkey (bytes 8-40, 33 bytes) -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">8–40</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="164" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ephemeral_pubkey</text>
|
||||
<text x="315" y="182" fill="#f8c88a" text-anchor="middle" font-size="10">33 bytes (compressed secp256k1)</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="210" fill="#777" font-size="10" text-anchor="middle">total: 41 bytes · payload_len = 37 · pattern: → e</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,82 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 478" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="478" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">Noise XX Message 2 — phase 0x2 (118–144 bytes)</text>
|
||||
|
||||
<!-- Row 0: Common prefix (bytes 0-3) -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="95" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="102" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ver</text>
|
||||
<text x="102" y="78" fill="#8ab4f8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="150" y="36" width="95" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="197" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">phase</text>
|
||||
<text x="197" y="78" fill="#8af8c8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="245" y="36" width="130" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="310" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="310" y="78" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="375" y="36" width="200" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="475" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">payload_len</text>
|
||||
<text x="475" y="78" fill="#d8a0f8" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Row 1: sender_idx (bytes 4-7) -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4–7</text>
|
||||
|
||||
<rect x="55" y="88" width="260" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="112" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">sender_idx</text>
|
||||
<text x="185" y="130" fill="#8af8f8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- receiver_idx (bytes 8-11) -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end"/>
|
||||
|
||||
<rect x="315" y="88" width="260" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="445" y="112" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">receiver_idx</text>
|
||||
<text x="445" y="130" fill="#8af8c8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Noise XX msg2 bracket -->
|
||||
<text x="10" y="290" fill="#777" font-size="10" text-anchor="middle" transform="rotate(-90, 10, 290)">Noise XX msg2 (106 bytes base)</text>
|
||||
<line x1="18" y1="140" x2="18" y2="400" stroke="#555" stroke-width="1"/>
|
||||
<line x1="18" y1="140" x2="23" y2="140" stroke="#555" stroke-width="1"/>
|
||||
<line x1="18" y1="400" x2="23" y2="400" stroke="#555" stroke-width="1"/>
|
||||
|
||||
<!-- Row 2: ephemeral_pubkey (bytes 12-44, 33 bytes) -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">12–44</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="164" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ephemeral_pubkey</text>
|
||||
<text x="315" y="182" fill="#f8c88a" text-anchor="middle" font-size="10">33 bytes (compressed secp256k1)</text>
|
||||
|
||||
<!-- Row 3: encrypted_static (bytes 45-93, 49 bytes) -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">45–93</text>
|
||||
|
||||
<rect x="55" y="192" width="520" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="216" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">encrypted_static</text>
|
||||
<text x="315" y="234" fill="#f88aaa" text-anchor="middle" font-size="10">49 bytes (static key 33 + AEAD tag 16)</text>
|
||||
|
||||
<!-- Row 4: encrypted_epoch (bytes 94-117, 24 bytes) -->
|
||||
<text x="50" y="270" fill="#666" font-size="10" text-anchor="end">94–117</text>
|
||||
|
||||
<rect x="55" y="244" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="268" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">encrypted_epoch</text>
|
||||
<text x="315" y="286" fill="#d8a0f8" text-anchor="middle" font-size="10">24 bytes (epoch 8 + AEAD tag 16)</text>
|
||||
|
||||
<!-- Row 5: negotiation payload (variable, optional) -->
|
||||
<text x="50" y="322" fill="#666" font-size="10" text-anchor="end">118+</text>
|
||||
|
||||
<rect x="55" y="296" width="520" height="52" fill="#2d4a4a" stroke="#4a9090" stroke-width="1.5" rx="3" stroke-dasharray="4,3"/>
|
||||
<text x="315" y="320" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">encrypted negotiation payload</text>
|
||||
<text x="315" y="338" fill="#8ad8d8" text-anchor="middle" font-size="10">26 bytes typical (10 payload + 16 AEAD tag)</text>
|
||||
|
||||
<!-- Row 6: AEAD explanation -->
|
||||
<rect x="55" y="362" width="520" height="38" fill="#1f1f3a" stroke="#444" stroke-width="1" rx="3"/>
|
||||
<text x="315" y="386" fill="#888" text-anchor="middle" font-size="10">negotiation appended via encrypt_payload() — extends Noise hash chain</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="425" fill="#777" font-size="10" text-anchor="middle">base: 118 bytes · with FMP negotiation: 144 bytes</text>
|
||||
<text x="310" y="442" fill="#777" font-size="10" text-anchor="middle">pattern: ← e, ee, s, es</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,72 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 426" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="426" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">Noise XX Message 3 — phase 0x3 (85–111 bytes)</text>
|
||||
|
||||
<!-- Row 0: Common prefix (bytes 0-3) -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="95" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="102" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ver</text>
|
||||
<text x="102" y="78" fill="#8ab4f8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="150" y="36" width="95" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="197" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">phase</text>
|
||||
<text x="197" y="78" fill="#8af8c8" text-anchor="middle" font-size="10">4 bits</text>
|
||||
|
||||
<rect x="245" y="36" width="130" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="310" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="310" y="78" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="375" y="36" width="200" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="475" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">payload_len</text>
|
||||
<text x="475" y="78" fill="#d8a0f8" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Row 1: sender_idx + receiver_idx (bytes 4-11) -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4–11</text>
|
||||
|
||||
<rect x="55" y="88" width="260" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="112" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">sender_idx</text>
|
||||
<text x="185" y="130" fill="#8af8f8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<rect x="315" y="88" width="260" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="445" y="112" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">receiver_idx</text>
|
||||
<text x="445" y="130" fill="#8af8c8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Noise XX msg3 bracket -->
|
||||
<text x="10" y="240" fill="#777" font-size="10" text-anchor="middle" transform="rotate(-90, 10, 240)">Noise XX msg3 (73 bytes base)</text>
|
||||
<line x1="18" y1="140" x2="18" y2="348" stroke="#555" stroke-width="1"/>
|
||||
<line x1="18" y1="140" x2="23" y2="140" stroke="#555" stroke-width="1"/>
|
||||
<line x1="18" y1="348" x2="23" y2="348" stroke="#555" stroke-width="1"/>
|
||||
|
||||
<!-- Row 2: encrypted_static (bytes 12-60, 49 bytes) -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">12–60</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="164" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">encrypted_static</text>
|
||||
<text x="315" y="182" fill="#f88aaa" text-anchor="middle" font-size="10">49 bytes (static key 33 + AEAD tag 16)</text>
|
||||
|
||||
<!-- Row 3: encrypted_epoch (bytes 61-84, 24 bytes) -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">61–84</text>
|
||||
|
||||
<rect x="55" y="192" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="216" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">encrypted_epoch</text>
|
||||
<text x="315" y="234" fill="#d8a0f8" text-anchor="middle" font-size="10">24 bytes (epoch 8 + AEAD tag 16)</text>
|
||||
|
||||
<!-- Row 4: negotiation payload (variable, optional) -->
|
||||
<text x="50" y="270" fill="#666" font-size="10" text-anchor="end">85+</text>
|
||||
|
||||
<rect x="55" y="244" width="520" height="52" fill="#2d4a4a" stroke="#4a9090" stroke-width="1.5" rx="3" stroke-dasharray="4,3"/>
|
||||
<text x="315" y="268" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">encrypted negotiation payload</text>
|
||||
<text x="315" y="286" fill="#8ad8d8" text-anchor="middle" font-size="10">26 bytes typical (10 payload + 16 AEAD tag)</text>
|
||||
|
||||
<!-- Row 5: explanation -->
|
||||
<rect x="55" y="310" width="520" height="38" fill="#1f1f3a" stroke="#444" stroke-width="1" rx="3"/>
|
||||
<text x="315" y="334" fill="#888" text-anchor="middle" font-size="10">negotiation appended via encrypt_payload() — extends Noise hash chain</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="378" fill="#777" font-size="10" text-anchor="middle">base: 85 bytes · with FMP negotiation: 111 bytes</text>
|
||||
<text x="310" y="395" fill="#777" font-size="10" text-anchor="middle">pattern: → s, se</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,43 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 296" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="296" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">PathBroken (0x21) — 36 + 16n bytes payload</text>
|
||||
|
||||
<!-- Row 0 (0–1): msg_type + flags -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–1</text>
|
||||
|
||||
<rect x="55" y="36" width="260" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="58" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="185" y="76" fill="#8ab4f8" text-anchor="middle" font-size="10">0x21</text>
|
||||
|
||||
<rect x="315" y="36" width="260" height="52" fill="#1f1f3a" stroke="#444" stroke-width="1" rx="3"/>
|
||||
<text x="445" y="62" fill="#666" text-anchor="middle" font-size="12">flags (reserved)</text>
|
||||
|
||||
<!-- Row 1 (2–17): dest_addr -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">2–17</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">dest_addr</text>
|
||||
<text x="315" y="128" fill="#d8a0f8" text-anchor="middle" font-size="10">16 bytes — unreachable NodeAddr</text>
|
||||
|
||||
<!-- Row 2 (18–33): reporter -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">18–33</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">reporter</text>
|
||||
<text x="315" y="180" fill="#8af8f8" text-anchor="middle" font-size="10">16 bytes — NodeAddr of reporting router</text>
|
||||
|
||||
<!-- Row 3 (34–35): last_coords_count -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">34–35</text>
|
||||
|
||||
<rect x="55" y="192" width="260" height="52" fill="#4a3d2d" stroke="#d9b04a" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="222" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">last_coords_count</text>
|
||||
|
||||
<!-- Row 4 (36–): last_known_coords -->
|
||||
<text x="50" y="264" fill="#666" font-size="10" text-anchor="end">36–</text>
|
||||
|
||||
<rect x="55" y="248" width="520" height="40" fill="#1f1f3a" stroke="#d9904a" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="272" fill="#f8c88a" text-anchor="middle" font-size="11">last_known_coords × n (16 bytes each — stale coords)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 114" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="114" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">PathMtuNotification (0x13) — 2 bytes body</text>
|
||||
|
||||
<!-- Row 0 (0–1): path_mtu -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–1</text>
|
||||
|
||||
<rect x="55" y="36" width="520" height="52" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="58" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">path_mtu</text>
|
||||
<text x="315" y="76" fill="#f88aaa" text-anchor="middle" font-size="10">2 bytes LE — minimum MTU observed along forward path</text>
|
||||
|
||||
<!-- Note -->
|
||||
<text x="310" y="108" fill="#777" font-size="10" text-anchor="middle">body only — carried inside FSP encrypted message (prefix + inner header + AEAD tag)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1000 B |
@@ -0,0 +1,97 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 634" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="634" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">ReceiverReport (0x02) — 54 bytes</text>
|
||||
|
||||
<!-- Row 0 (0-3): msg_type + format_version + total_length -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="130" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="56" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">msg_type</text>
|
||||
<text x="120" y="74" fill="#8ab4f8" text-anchor="middle" font-size="10">0x02</text>
|
||||
|
||||
<rect x="185" y="36" width="130" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="250" y="56" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">fmt_ver</text>
|
||||
<text x="250" y="74" fill="#8af8c8" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="315" y="36" width="260" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="445" y="56" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">total_length</text>
|
||||
<text x="445" y="74" fill="#d8a0f8" text-anchor="middle" font-size="10">2 bytes LE (= 50)</text>
|
||||
|
||||
<!-- Row 1 (4-7): timestamp_echo -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4–7</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">timestamp_echo</text>
|
||||
<text x="315" y="128" fill="#f8c88a" text-anchor="middle" font-size="10">4 bytes LE (echoed sender timestamp for RTT)</text>
|
||||
|
||||
<!-- Row 2 (8-9): dwell_time -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">8–9</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">dwell_time</text>
|
||||
<text x="315" y="180" fill="#8af8f8" text-anchor="middle" font-size="10">2 bytes LE (ms between receive and echo)</text>
|
||||
|
||||
<!-- Row 3 (10-17): highest_counter -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">10–17</text>
|
||||
|
||||
<rect x="55" y="192" width="520" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="214" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">highest_counter</text>
|
||||
<text x="315" y="232" fill="#8af8c8" text-anchor="middle" font-size="10">8 bytes LE</text>
|
||||
|
||||
<!-- Row 4 (18-25): cumulative_packets_recv -->
|
||||
<text x="50" y="270" fill="#666" font-size="10" text-anchor="end">18–25</text>
|
||||
|
||||
<rect x="55" y="244" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="266" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">cumulative_packets_recv</text>
|
||||
<text x="315" y="284" fill="#f8c88a" text-anchor="middle" font-size="10">8 bytes LE</text>
|
||||
|
||||
<!-- Row 5 (26-33): cumulative_bytes_recv -->
|
||||
<text x="50" y="322" fill="#666" font-size="10" text-anchor="end">26–33</text>
|
||||
|
||||
<rect x="55" y="296" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="318" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">cumulative_bytes_recv</text>
|
||||
<text x="315" y="336" fill="#8af8f8" text-anchor="middle" font-size="10">8 bytes LE</text>
|
||||
|
||||
<!-- Row 6 (34-41): jitter + ecn_ce_count -->
|
||||
<text x="50" y="374" fill="#666" font-size="10" text-anchor="end">34–41</text>
|
||||
|
||||
<rect x="55" y="348" width="260" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="370" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">jitter</text>
|
||||
<text x="185" y="388" fill="#d8a0f8" text-anchor="middle" font-size="10">4 bytes LE (µs)</text>
|
||||
|
||||
<rect x="315" y="348" width="260" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="445" y="370" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ecn_ce_count</text>
|
||||
<text x="445" y="388" fill="#8af8c8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Row 7 (42-49): owd_trend + burst_loss_count -->
|
||||
<text x="50" y="426" fill="#666" font-size="10" text-anchor="end">42–49</text>
|
||||
|
||||
<rect x="55" y="400" width="260" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="422" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">owd_trend</text>
|
||||
<text x="185" y="440" fill="#f8c88a" text-anchor="middle" font-size="10">i32 LE (µs/s)</text>
|
||||
|
||||
<rect x="315" y="400" width="260" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="445" y="422" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">burst_loss_count</text>
|
||||
<text x="445" y="440" fill="#8af8f8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Row 8 (50-53): cumulative_reorder_count -->
|
||||
<text x="50" y="478" fill="#666" font-size="10" text-anchor="end">50–53</text>
|
||||
|
||||
<rect x="55" y="452" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="474" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">cumulative_reorder_count</text>
|
||||
<text x="315" y="492" fill="#d8a0f8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Forward compat note -->
|
||||
<rect x="55" y="518" width="520" height="32" fill="#1f1f3a" stroke="#444" stroke-width="1" rx="3"/>
|
||||
<text x="315" y="538" fill="#888" text-anchor="middle" font-size="10">decoders skip trailing bytes beyond total_length (forward compatibility)</text>
|
||||
|
||||
<!-- Removed fields note -->
|
||||
<rect x="55" y="558" width="520" height="32" fill="#1f1f3a" stroke="#444" stroke-width="1" rx="3"/>
|
||||
<text x="315" y="578" fill="#666" text-anchor="middle" font-size="10">removed from v0.2: max_burst_loss, mean_burst_loss, interval_packets/bytes_recv</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="618" fill="#777" font-size="10" text-anchor="middle">total: 54 bytes · format_version = 0 · total_length = 50</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
@@ -0,0 +1,50 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 322" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="322" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">SenderReport (0x01) — 20 bytes</text>
|
||||
|
||||
<!-- Row 0 (0-3): msg_type + format_version + total_length -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="130" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="56" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">msg_type</text>
|
||||
<text x="120" y="74" fill="#8ab4f8" text-anchor="middle" font-size="10">0x01</text>
|
||||
|
||||
<rect x="185" y="36" width="130" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="250" y="56" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">fmt_ver</text>
|
||||
<text x="250" y="74" fill="#8af8c8" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="315" y="36" width="260" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="445" y="56" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">total_length</text>
|
||||
<text x="445" y="74" fill="#d8a0f8" text-anchor="middle" font-size="10">2 bytes LE (= 16)</text>
|
||||
|
||||
<!-- Row 1 (4-7): interval_packets_sent -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4–7</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">interval_packets_sent</text>
|
||||
<text x="315" y="128" fill="#f8c88a" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Row 2 (8-11): interval_bytes_sent -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">8–11</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">interval_bytes_sent</text>
|
||||
<text x="315" y="180" fill="#8af8f8" text-anchor="middle" font-size="10">4 bytes LE</text>
|
||||
|
||||
<!-- Row 3 (12-19): cumulative_packets_sent -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">12–19</text>
|
||||
|
||||
<rect x="55" y="192" width="520" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="214" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">cumulative_packets_sent</text>
|
||||
<text x="315" y="232" fill="#8af8c8" text-anchor="middle" font-size="10">8 bytes LE</text>
|
||||
|
||||
<!-- Forward compat note -->
|
||||
<rect x="55" y="258" width="520" height="32" fill="#1f1f3a" stroke="#444" stroke-width="1" rx="3"/>
|
||||
<text x="315" y="278" fill="#888" text-anchor="middle" font-size="10">decoders skip trailing bytes beyond total_length (forward compatibility)</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="314" fill="#777" font-size="10" text-anchor="middle">total: 20 bytes · format_version = 0 · total_length = 16</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,47 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 322" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="322" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">SessionAck (phase 0x2) — Noise XX msg2</text>
|
||||
|
||||
<!-- Row 0 (0–3): FSP prefix -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="520" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="58" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">FSP common prefix</text>
|
||||
<text x="315" y="76" fill="#8ab4f8" text-anchor="middle" font-size="10">ver=0, phase=0x2, flags=0, payload_len</text>
|
||||
|
||||
<!-- Row 1 (4): flags -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="315" y="128" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte — reserved</text>
|
||||
|
||||
<!-- Row 2 (5–): src_coords (acknowledger) -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">5–</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="40" fill="#1f1f3a" stroke="#4ad9d9" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="164" fill="#8af8f8" text-anchor="middle" font-size="11">src_coords_count(2) + src_coords(16 × n) — acknowledger</text>
|
||||
|
||||
<!-- Row 3: dest_coords (initiator) -->
|
||||
<text x="50" y="206" fill="#666" font-size="10" text-anchor="end">...</text>
|
||||
|
||||
<rect x="55" y="186" width="520" height="40" fill="#1f1f3a" stroke="#b04ad9" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="210" fill="#d8a0f8" text-anchor="middle" font-size="11">dest_coords_count(2) + dest_coords(16 × m) — initiator</text>
|
||||
|
||||
<!-- Row 4: handshake_len + handshake_payload -->
|
||||
<text x="50" y="252" fill="#666" font-size="10" text-anchor="end">...</text>
|
||||
|
||||
<rect x="55" y="232" width="130" height="52" fill="#4a3d2d" stroke="#d9b04a" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="254" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">hs_len</text>
|
||||
<text x="120" y="272" fill="#f8d88a" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<rect x="185" y="232" width="390" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="380" y="254" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">handshake_payload</text>
|
||||
<text x="380" y="272" fill="#8af8c8" text-anchor="middle" font-size="10">Noise XX msg2 (106+ bytes — ephemeral + static + epoch)</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="308" fill="#777" font-size="10" text-anchor="middle">typical ~240 bytes (depth-dependent, carries both endpoints' coords)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,46 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 374" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="374" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">SessionDatagram (0x00) — 36 + payload bytes</text>
|
||||
|
||||
<!-- Row 0 (0–3): msg_type + ttl + path_mtu -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="130" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="120" y="78" fill="#8ab4f8" text-anchor="middle" font-size="10">0x00</text>
|
||||
|
||||
<rect x="185" y="36" width="130" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="250" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ttl</text>
|
||||
<text x="250" y="78" fill="#8af8c8" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="315" y="36" width="260" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="445" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">path_mtu</text>
|
||||
<text x="445" y="78" fill="#f8c88a" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Row 1-4 (4–19): src_addr -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4–19</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">src_addr</text>
|
||||
<text x="315" y="128" fill="#8af8f8" text-anchor="middle" font-size="10">16 bytes — source NodeAddr</text>
|
||||
|
||||
<!-- Row 5-8 (20–35): dest_addr -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">20–35</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">dest_addr</text>
|
||||
<text x="315" y="180" fill="#d8a0f8" text-anchor="middle" font-size="10">16 bytes — destination NodeAddr</text>
|
||||
|
||||
<!-- Row 9 (36–): payload -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">36–</text>
|
||||
|
||||
<rect x="55" y="198" width="520" height="40" fill="#1f1f3a" stroke="#444" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="222" fill="#666" text-anchor="middle" font-size="11">payload (variable — session-layer message)</text>
|
||||
|
||||
<!-- Notes -->
|
||||
<text x="310" y="262" fill="#777" font-size="10" text-anchor="middle">fixed header: 36 bytes · payload opaque to transit nodes</text>
|
||||
<text x="310" y="278" fill="#777" font-size="10" text-anchor="middle">ttl decremented and path_mtu min'd at each forwarding hop</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,35 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 244" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="244" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">SessionMsg3 (phase 0x3) — Noise XX msg3</text>
|
||||
|
||||
<!-- Row 0 (0–3): FSP prefix -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="520" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="58" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">FSP common prefix</text>
|
||||
<text x="315" y="76" fill="#8ab4f8" text-anchor="middle" font-size="10">ver=0, phase=0x3, flags=0, payload_len</text>
|
||||
|
||||
<!-- Row 1 (4–6): flags + handshake_len -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4–6</text>
|
||||
|
||||
<rect x="55" y="88" width="130" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="120" y="128" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte</text>
|
||||
|
||||
<rect x="185" y="88" width="390" height="52" fill="#4a3d2d" stroke="#d9b04a" stroke-width="1.5" rx="3"/>
|
||||
<text x="380" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">handshake_len</text>
|
||||
<text x="380" y="128" fill="#f8d88a" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<!-- Row 2 (7–): handshake_payload -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">7–</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">handshake_payload</text>
|
||||
<text x="315" y="180" fill="#8af8c8" text-anchor="middle" font-size="10">Noise XX msg3 (73+ bytes — encrypted static + epoch + optional negotiation)</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="218" fill="#777" font-size="10" text-anchor="middle">~80 bytes · no coordinates (both endpoints already have them)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,47 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 322" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="322" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">SessionSetup (phase 0x1) — Noise XX msg1</text>
|
||||
|
||||
<!-- Row 0 (0–3): FSP prefix -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="520" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="58" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">FSP common prefix</text>
|
||||
<text x="315" y="76" fill="#8ab4f8" text-anchor="middle" font-size="10">ver=0, phase=0x1, flags=0, payload_len</text>
|
||||
|
||||
<!-- Row 1 (4): flags -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="110" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">flags</text>
|
||||
<text x="315" y="128" fill="#f8c88a" text-anchor="middle" font-size="10">1 byte — bit 0: REQUEST_ACK, bit 1: BIDIRECTIONAL</text>
|
||||
|
||||
<!-- Row 2 (5–): src_coords -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">5–</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="40" fill="#1f1f3a" stroke="#4ad9d9" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="164" fill="#8af8f8" text-anchor="middle" font-size="11">src_coords_count(2) + src_coords(16 × n)</text>
|
||||
|
||||
<!-- Row 3: dest_coords -->
|
||||
<text x="50" y="206" fill="#666" font-size="10" text-anchor="end">...</text>
|
||||
|
||||
<rect x="55" y="186" width="520" height="40" fill="#1f1f3a" stroke="#b04ad9" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="210" fill="#d8a0f8" text-anchor="middle" font-size="11">dest_coords_count(2) + dest_coords(16 × m)</text>
|
||||
|
||||
<!-- Row 4: handshake_len + handshake_payload -->
|
||||
<text x="50" y="252" fill="#666" font-size="10" text-anchor="end">...</text>
|
||||
|
||||
<rect x="55" y="232" width="130" height="52" fill="#4a3d2d" stroke="#d9b04a" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="254" fill="#e0e0e0" text-anchor="middle" font-size="11" font-weight="bold">hs_len</text>
|
||||
<text x="120" y="272" fill="#f8d88a" text-anchor="middle" font-size="10">2 bytes LE</text>
|
||||
|
||||
<rect x="185" y="232" width="390" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="380" y="254" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">handshake_payload</text>
|
||||
<text x="380" y="272" fill="#8af8c8" text-anchor="middle" font-size="10">Noise XX msg1 (33 bytes — ephemeral key)</text>
|
||||
|
||||
<!-- Total -->
|
||||
<text x="310" y="308" fill="#777" font-size="10" text-anchor="middle">typical ~170 bytes (depth-dependent)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,59 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 580 374" font-family="monospace" font-size="13">
|
||||
<!-- Background -->
|
||||
<rect width="580" height="374" fill="#1a1a2e" rx="4"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="310" y="26" fill="#e0e0e0" text-anchor="middle" font-size="14" font-weight="bold">TreeAnnounce (0x10) — 100 + 32n bytes</text>
|
||||
|
||||
<!-- Row 0 (0–3): msg_type(1) + version(1) + sequence starts -->
|
||||
<text x="50" y="62" fill="#666" font-size="10" text-anchor="end">0–3</text>
|
||||
|
||||
<rect x="55" y="36" width="130" height="52" fill="#2d4a7a" stroke="#4a90d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="120" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">msg_type</text>
|
||||
<text x="120" y="78" fill="#8ab4f8" text-anchor="middle" font-size="10">0x10</text>
|
||||
|
||||
<rect x="185" y="36" width="130" height="52" fill="#2d5a4a" stroke="#4ad99a" stroke-width="1.5" rx="3"/>
|
||||
<text x="250" y="60" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">version</text>
|
||||
<text x="250" y="78" fill="#8af8c8" text-anchor="middle" font-size="10">0x01</text>
|
||||
|
||||
<rect x="315" y="36" width="260" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="445" y="66" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">sequence</text>
|
||||
|
||||
<!-- Row 1 (4–9): sequence continued -->
|
||||
<text x="50" y="114" fill="#666" font-size="10" text-anchor="end">4–9</text>
|
||||
|
||||
<rect x="55" y="88" width="520" height="52" fill="#5a3d2d" stroke="#d9904a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="118" fill="#f8c88a" text-anchor="middle" font-size="10">8 bytes LE — monotonic counter</text>
|
||||
|
||||
<!-- Row 2 (10–17): timestamp -->
|
||||
<text x="50" y="166" fill="#666" font-size="10" text-anchor="end">10–17</text>
|
||||
|
||||
<rect x="55" y="140" width="520" height="52" fill="#4a2d5a" stroke="#b04ad9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="162" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">timestamp</text>
|
||||
<text x="315" y="180" fill="#d8a0f8" text-anchor="middle" font-size="10">8 bytes LE — Unix seconds</text>
|
||||
|
||||
<!-- Row 3 (18–33): parent -->
|
||||
<text x="50" y="218" fill="#666" font-size="10" text-anchor="end">18–33</text>
|
||||
|
||||
<rect x="55" y="192" width="520" height="52" fill="#2d5a5a" stroke="#4ad9d9" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="214" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">parent</text>
|
||||
<text x="315" y="232" fill="#8af8f8" text-anchor="middle" font-size="10">16 bytes — NodeAddr (self = root)</text>
|
||||
|
||||
<!-- Row 4 (34–35): ancestry_count -->
|
||||
<text x="50" y="270" fill="#666" font-size="10" text-anchor="end">34–35</text>
|
||||
|
||||
<rect x="55" y="250" width="260" height="40" fill="#5a2d3d" stroke="#d94a6a" stroke-width="1.5" rx="3"/>
|
||||
<text x="185" y="274" fill="#e0e0e0" text-anchor="middle" font-size="12" font-weight="bold">ancestry_count</text>
|
||||
|
||||
<!-- Row 5 (36–): ancestry entries -->
|
||||
<text x="50" y="316" fill="#666" font-size="10" text-anchor="end">36–</text>
|
||||
|
||||
<rect x="55" y="296" width="520" height="40" fill="#1f1f3a" stroke="#d9904a" stroke-width="1" stroke-dasharray="4,3" rx="3"/>
|
||||
<text x="315" y="320" fill="#f8c88a" text-anchor="middle" font-size="11">AncestryEntry × n (32 bytes each)</text>
|
||||
|
||||
<!-- Signature -->
|
||||
<text x="50" y="360" fill="#666" font-size="10" text-anchor="end">+64</text>
|
||||
|
||||
<rect x="55" y="342" width="520" height="26" fill="#3d4a2d" stroke="#8ad94a" stroke-width="1.5" rx="3"/>
|
||||
<text x="315" y="360" fill="#e0e0e0" text-anchor="middle" font-size="10" font-weight="bold">Schnorr signature (64 bytes)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -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
|
||||
@@ -0,0 +1,235 @@
|
||||
# Security Reference
|
||||
|
||||
Consolidated security reference covering the nftables baseline, peer
|
||||
ACL file format, cryptographic primitives, rekey defaults, replay
|
||||
window, filesystem permissions, threat-resistance matrix, and default
|
||||
network exposures per transport. For the threat-model design and
|
||||
rationale, see [../design/fips-security.md](../design/fips-security.md).
|
||||
For the operator activation steps and drop-in recipes, see
|
||||
[../how-to/enable-mesh-firewall.md](../how-to/enable-mesh-firewall.md).
|
||||
|
||||
## nftables Baseline
|
||||
|
||||
The shipped baseline is `/etc/fips/fips.nft`. It defines a single
|
||||
nftables table `inet fips` with one chain hooked at `input`, structured
|
||||
as follows:
|
||||
|
||||
| Step | Rule | Effect |
|
||||
| ---- | ---- | ------ |
|
||||
| 1 | `iifname != "fips0" return` | Match only traffic arriving on `fips0`; everything else short-circuits. |
|
||||
| 2 | `ct state established,related accept` | Allow conntrack replies and related ICMPv6 errors. |
|
||||
| 3 | `icmpv6 type echo-request accept` | Allow IPv6 echo (ping6 reachability). |
|
||||
| 4 | `include "/etc/fips/fips.d/*.nft"` | Splice in operator drop-ins (empty matches nothing). |
|
||||
| 5 | `counter drop` | Default-deny everything else; counter increments on every drop. |
|
||||
|
||||
Outbound from `fips0` is unrestricted. The baseline is a documented
|
||||
dpkg conffile — operator edits to `/etc/fips/fips.nft` are preserved
|
||||
across upgrades.
|
||||
|
||||
The systemd unit is `fips-firewall.service` (oneshot). It is **not**
|
||||
enabled by default; activation is an explicit operator gesture
|
||||
documented in
|
||||
[../how-to/enable-mesh-firewall.md](../how-to/enable-mesh-firewall.md).
|
||||
|
||||
## Drop-In File Format
|
||||
|
||||
Operator extensions live under `/etc/fips/fips.d/` with the `.nft`
|
||||
suffix. Each file is included inline into the `inbound` chain at the
|
||||
marked point and may contain any nftables rule lines valid in that
|
||||
context.
|
||||
|
||||
Naming convention: `<purpose>-from-<source>.nft` keeps drop-ins easy
|
||||
to scan. Examples shipped in the design discussion:
|
||||
|
||||
- `ssh-from-bastion.nft` — accept TCP/22 from a single mesh-node address
|
||||
- `http-from-cluster.nft` — accept TCP/80 from a `/64` mesh-address prefix
|
||||
- `dns-public.nft` — accept UDP/53 and TCP/53 from any mesh node
|
||||
- `git-from-trusted.nft` — accept TCP/9418 from a set of mesh-node addresses
|
||||
|
||||
After editing, reload via
|
||||
`sudo systemctl reload-or-restart fips-firewall.service` (or
|
||||
equivalently `sudo nft -f /etc/fips/fips.nft` since the file is
|
||||
idempotent).
|
||||
|
||||
## Cryptographic Primitives
|
||||
|
||||
| Component | Choice | Where Used |
|
||||
| --------- | ------ | ---------- |
|
||||
| Curve | secp256k1 | FMP XX, FSP XX, Schnorr signatures |
|
||||
| Diffie-Hellman | ECDH on secp256k1 (x-only normalized) | Noise XX (both layers) |
|
||||
| AEAD | ChaCha20-Poly1305 | FMP link encryption, FSP session encryption |
|
||||
| Hash | SHA-256 | NodeAddr derivation, Noise transcript |
|
||||
| Key derivation | HKDF-SHA256 | Noise key schedule |
|
||||
| Signatures | secp256k1 Schnorr | TreeAnnounce, LookupResponse proof, Nostr adverts |
|
||||
| Noise pattern (link) | `Noise_XX_secp256k1_ChaChaPoly_SHA256` | FMP link layer (XX with negotiation payload) |
|
||||
| Noise pattern (session) | `Noise_XX_secp256k1_ChaChaPoly_SHA256` | FSP session layer (XX with negotiation payload) |
|
||||
|
||||
These choices align with the Nostr cryptographic stack
|
||||
(secp256k1 + ChaCha20-Poly1305 + SHA-256) and the NIP-44 encrypted
|
||||
messaging standard.
|
||||
|
||||
## Rekey Defaults
|
||||
|
||||
Both link-layer and session-layer Noise sessions rekey under one of
|
||||
two triggers, configurable under `node.rekey.*`:
|
||||
|
||||
| Parameter | Default | Description |
|
||||
| --------- | ------- | ----------- |
|
||||
| `enabled` | `true` | Master switch. |
|
||||
| `after_secs` | `120` | Time-based rekey threshold. |
|
||||
| `after_messages` | `65536` | Message-count rekey threshold. |
|
||||
|
||||
In addition to the configurable triggers, the daemon retains the old
|
||||
session keys for a fixed **10-second drain window** after each
|
||||
cutover (compile-time constant `DRAIN_WINDOW_SECS` in
|
||||
`src/node/handlers/rekey.rs`). Rekey rotates the Noise key schedule
|
||||
and the session indices; old session keys are kept in
|
||||
`previous_session` for the drain window so in-flight packets
|
||||
encrypted under the old keys still decrypt.
|
||||
|
||||
## Replay Window
|
||||
|
||||
Both layers use explicit per-packet counters with a sliding bitmap
|
||||
window for replay protection. The bitmap is **2048 entries** at both
|
||||
layers — large enough to accommodate UDP reordering and packet loss
|
||||
without false-positive replay rejection. Counters older than the
|
||||
window are rejected. The same `ReplayWindow` and
|
||||
`decrypt_with_replay_check()` implementation is used at both the FMP
|
||||
and FSP layers.
|
||||
|
||||
## Peer ACL
|
||||
|
||||
Mesh-level ACL files at `/etc/fips/peers.allow` and
|
||||
`/etc/fips/peers.deny` give the operator allowlist/blocklist control
|
||||
over which npubs may complete the FMP Noise XX link handshake.
|
||||
|
||||
File format:
|
||||
|
||||
- One entry per line. An entry is either a bech32 `npub1...`,
|
||||
an alias defined in `/etc/fips/hosts`, or the literal `ALL`
|
||||
wildcard (case-insensitive).
|
||||
- Lines beginning with `#` are comments.
|
||||
- Blank lines are ignored.
|
||||
|
||||
Evaluation order (first match wins, default-allow on no match):
|
||||
|
||||
1. `peers.allow` — if the peer matches an entry here (or `ALL` is
|
||||
in `peers.allow`), the handshake is admitted, regardless of any
|
||||
`peers.deny` entry.
|
||||
2. `peers.deny` — if the peer matches an entry here (or `ALL` is
|
||||
in `peers.deny`), the handshake is refused.
|
||||
3. Otherwise the peer is admitted.
|
||||
|
||||
`peers.allow` is **not** an exclusive gate on its own: an unlisted
|
||||
peer falls through to step 3 and is admitted unless it appears in
|
||||
`peers.deny`. To turn `peers.allow` into a strict allowlist, place
|
||||
`ALL` in `peers.deny` so every unlisted peer is rejected at step 2.
|
||||
|
||||
The `ALL` wildcard makes the operator's posture explicit:
|
||||
|
||||
- `ALL` in `peers.allow` admits every peer (same effect as the
|
||||
default-allow behavior, but documented in the file).
|
||||
- `ALL` in `peers.deny` blocks every peer except those listed in
|
||||
`peers.allow` — the "allowlist-strict" posture.
|
||||
|
||||
In practice this collapses to a few common postures:
|
||||
|
||||
- **Default-allow with denylist**: leave `peers.allow` empty;
|
||||
populate `peers.deny`. All npubs may peer except those listed.
|
||||
- **Allowlist-strict**: populate `peers.allow` and put `ALL`
|
||||
in `peers.deny`. Only the listed npubs may peer; everyone else
|
||||
is rejected at step 2.
|
||||
|
||||
A populated `peers.allow` with an empty `peers.deny` is not a
|
||||
strict allowlist — it is equivalent to default-allow plus an
|
||||
explicit "always-admit" set. The strict variant requires `ALL`
|
||||
in `peers.deny`.
|
||||
|
||||
Aliases are resolved through `/etc/fips/hosts` at file-load
|
||||
time. If `peers.allow` lists `core-vm` and `/etc/fips/hosts`
|
||||
maps `core-vm` to a specific npub, that npub is admitted. If
|
||||
`core-vm` is later remapped to a different npub, the ACL
|
||||
re-resolves on the next mtime change. Operators should be aware
|
||||
that ACL semantics follow the `hosts`-file aliasing, not just
|
||||
the literal npubs visible in the file.
|
||||
|
||||
Both files are reloaded automatically when their mtime changes
|
||||
— no daemon restart or signal is needed. ACL evaluation runs
|
||||
after msg1 decryption but before any further peer-state
|
||||
mutation; rate-limited msg1s never reach the ACL.
|
||||
|
||||
## Filesystem Permissions
|
||||
|
||||
| Path | Owner | Mode | Purpose |
|
||||
| ---- | ----- | ---- | ------- |
|
||||
| `/etc/fips/fips.key` | root:root | `0600` | Persistent identity private key (sensitive). |
|
||||
| `/etc/fips/fips.pub` | root:root | `0644` | Public key (npub). |
|
||||
| `/etc/fips/fips.yaml` | root:root | `0644` | Daemon configuration (dpkg conffile). |
|
||||
| `/etc/fips/fips.nft` | root:root | `0644` | nftables baseline (dpkg conffile). |
|
||||
| `/etc/fips/fips.d/` | root:root | `0755` | Operator drop-in directory. |
|
||||
| `/etc/fips/hosts` | root:root | `0644` | Optional hostname → npub map (dpkg conffile). |
|
||||
| `/etc/fips/peers.allow` | root:root | `0644` | Optional peer allowlist. |
|
||||
| `/etc/fips/peers.deny` | root:root | `0644` | Optional peer denylist. |
|
||||
| `/run/fips/control.sock` | root:fips | `0770` | Control socket (members of `fips` group can use `fipsctl`). |
|
||||
| `/run/fips/` | root:fips | `0750` | Control socket parent directory. |
|
||||
|
||||
Adding a user to the `fips` group grants `fipsctl` access without
|
||||
requiring root. The daemon `chown`s the control socket and its parent
|
||||
directory at bind time.
|
||||
|
||||
## Threat-Resistance Matrix
|
||||
|
||||
The link layer's threat-resistance matrix is consolidated here from
|
||||
the FMP design document:
|
||||
|
||||
| Threat | Mitigation |
|
||||
| ------ | ---------- |
|
||||
| Connection exhaustion | Token-bucket rate limit + connection count limit |
|
||||
| CPU exhaustion (msg1 flood) | Rate limit before crypto operations |
|
||||
| Replay attacks | Counter-based nonces with sliding window (2048 entries) |
|
||||
| State confusion | Strict handshake state machine validation |
|
||||
| Spoofed encrypted packets | Index lookup + AEAD verification |
|
||||
| Spoofed msg2 | Index lookup + Noise ephemeral key binding |
|
||||
| Address spoofing | Cryptographic authority, not address-based |
|
||||
| Session correlation | Index rotation on rekey |
|
||||
| Inbound exposure on `fips0` | Default-deny nftables baseline (operator opt-in) |
|
||||
| Sybil identities | Discretionary peering + handshake rate limiting + optional peer ACL |
|
||||
| Eclipse attack | Diverse peering across independent operators and transports |
|
||||
| Unauthorized peer admission | Optional `peers.allow` allowlist consulted before handshake |
|
||||
|
||||
See [../design/fips-mesh-layer.md](../design/fips-mesh-layer.md) for
|
||||
the unauthenticated-attack-surface analysis (only handshake msg1 is
|
||||
reachable by unauthenticated parties), and
|
||||
[../design/fips-mesh-operation.md](../design/fips-mesh-operation.md#privacy-considerations)
|
||||
for the metadata-privacy model and the rejection of onion routing.
|
||||
|
||||
## Default Network Exposures by Transport
|
||||
|
||||
| Transport | Default Inbound | Default Bind | Opt-in |
|
||||
| --------- | --------------- | ------------ | ------ |
|
||||
| UDP | None until `bind_addr` set | `0.0.0.0:2121` typical | Operator sets `transports.udp.bind_addr` |
|
||||
| TCP | None until `bind_addr` set | None — outbound-only without bind | Operator sets `transports.tcp.bind_addr` |
|
||||
| Ethernet | Listens on configured interface (raw `AF_PACKET`) | EtherType 0x2121 on selected interface | Per-flag `discovery`, `announce`, `auto_connect`, `accept_connections` |
|
||||
| Tor | None until `directory_service` configured | `127.0.0.1:8443` (loopback only) | Operator sets `transports.tor.directory_service` and configures `HiddenServiceDir` in `torrc` |
|
||||
| BLE | Off by default | n/a | Operator enables `transports.ble.*` |
|
||||
| Nostr discovery | Off by default | n/a (relay client, not a listener) | Operator sets `node.discovery.nostr.enabled: true` |
|
||||
|
||||
The mesh-layer `fips0` interface is reachable from any mesh node that
|
||||
can route to you, not only direct peers — your direct peers forward
|
||||
traffic from any reachable mesh node onto your `fips0`. The
|
||||
default-deny nftables baseline (operator opt-in) is the recommended
|
||||
way to restrict inbound traffic on `fips0`. See
|
||||
[../how-to/enable-mesh-firewall.md](../how-to/enable-mesh-firewall.md).
|
||||
|
||||
## See also
|
||||
|
||||
- [../design/fips-security.md](../design/fips-security.md) — threat
|
||||
model and design rationale for the `fips0` baseline
|
||||
- [../design/fips-mesh-layer.md](../design/fips-mesh-layer.md) — FMP
|
||||
link encryption, replay protection, rate limiting
|
||||
- [../design/fips-session-layer.md](../design/fips-session-layer.md)
|
||||
— FSP end-to-end encryption, Noise XX, replay window
|
||||
- [../how-to/enable-mesh-firewall.md](../how-to/enable-mesh-firewall.md)
|
||||
— operator activation and drop-in recipes
|
||||
- [configuration.md](configuration.md) — full `node.rekey.*`,
|
||||
`node.rate_limit.*` parameter tables
|
||||
@@ -0,0 +1,92 @@
|
||||
# Transport Statistics Reference
|
||||
|
||||
Per-transport statistics counter inventories. Counters are exposed
|
||||
through the daemon control socket (`fipsctl show transports`) and the
|
||||
`fipstop` operator UI. For the transport-layer design (services
|
||||
provided to FMP, transport categories, the trait surface, connection
|
||||
model), see
|
||||
[../design/fips-transport-layer.md](../design/fips-transport-layer.md).
|
||||
|
||||
All transports report counters via `fipsctl show transports`; the
|
||||
tables below are source-extracted from each transport's `stats.rs`
|
||||
module.
|
||||
|
||||
## UDP
|
||||
|
||||
| Counter | Description |
|
||||
| ------- | ----------- |
|
||||
| `packets_sent` / `bytes_sent` | Successful sends |
|
||||
| `packets_recv` / `bytes_recv` | Successful receives |
|
||||
| `send_errors` / `recv_errors` | Send/receive failures |
|
||||
| `mtu_exceeded` | Packets rejected for MTU violation |
|
||||
| `kernel_drops` | Kernel `SO_RXQ_OVFL` drop count (feeds ECN congestion detection) |
|
||||
|
||||
## TCP
|
||||
|
||||
| Counter | Description |
|
||||
| ------- | ----------- |
|
||||
| `packets_sent` / `bytes_sent` | Successful sends |
|
||||
| `packets_recv` / `bytes_recv` | Successful receives |
|
||||
| `send_errors` / `recv_errors` | Send/receive failures |
|
||||
| `mtu_exceeded` | Packets rejected for MTU violation |
|
||||
| `connections_established` | Successful outbound connections |
|
||||
| `connections_accepted` | Accepted inbound connections |
|
||||
| `connections_rejected` | Rejected inbound connections (limit exceeded) |
|
||||
| `connect_timeouts` | Connection timeout count |
|
||||
| `connect_refused` | Connection refused count |
|
||||
|
||||
## Ethernet
|
||||
|
||||
| Counter | Description |
|
||||
| ------- | ----------- |
|
||||
| `frames_sent` / `frames_recv` | Successful frame send/receive |
|
||||
| `bytes_sent` / `bytes_recv` | Byte counters |
|
||||
| `send_errors` / `recv_errors` | Send/receive failures |
|
||||
| `beacons_sent` / `beacons_recv` | Peer-discovery beacon traffic |
|
||||
| `frames_too_short` | Frames below minimum length, dropped |
|
||||
| `frames_too_long` | Frames above transport MTU, dropped |
|
||||
|
||||
## Tor
|
||||
|
||||
| Counter | Description |
|
||||
| ------- | ----------- |
|
||||
| `packets_sent` / `bytes_sent` | Successful sends |
|
||||
| `packets_recv` / `bytes_recv` | Successful receives |
|
||||
| `send_errors` / `recv_errors` | Send/receive failures |
|
||||
| `connections_established` | Successful SOCKS5 connections |
|
||||
| `connect_timeouts` | Connection timeout count |
|
||||
| `connect_refused` | Connection refused count |
|
||||
| `socks5_errors` | SOCKS5 protocol errors |
|
||||
| `mtu_exceeded` | Packets rejected for MTU violation |
|
||||
| `connections_accepted` | Accepted inbound connections via onion service |
|
||||
| `connections_rejected` | Rejected inbound connections (limit exceeded) |
|
||||
| `control_errors` | Tor control port errors |
|
||||
|
||||
## Bluetooth
|
||||
|
||||
| Counter | Description |
|
||||
| ------- | ----------- |
|
||||
| `packets_sent` / `bytes_sent` | Successful L2CAP CoC sends |
|
||||
| `packets_recv` / `bytes_recv` | Successful L2CAP CoC receives |
|
||||
| `send_errors` / `recv_errors` | Send/receive failures |
|
||||
| `mtu_exceeded` | Packets rejected for MTU violation |
|
||||
| `connections_established` | Successful outbound L2CAP connections |
|
||||
| `connections_accepted` | Accepted inbound L2CAP connections |
|
||||
| `connections_rejected` | Rejected inbound (limit exceeded) |
|
||||
| `connect_timeouts` | Connection timeout count |
|
||||
| `pool_evictions` | Connection-pool entries evicted |
|
||||
| `advertisements_sent` | BLE advertisements emitted |
|
||||
| `scan_results` | BLE scan results observed |
|
||||
|
||||
## See also
|
||||
|
||||
- [../design/fips-transport-layer.md](../design/fips-transport-layer.md)
|
||||
— transport-layer design, trait surface, per-transport sections
|
||||
- [configuration.md](configuration.md) — `transports.*` configuration
|
||||
blocks
|
||||
- [../how-to/tune-udp-buffers.md](../how-to/tune-udp-buffers.md) —
|
||||
host-side `net.core.rmem_max` / `net.core.wmem_max` setup for UDP
|
||||
- [../how-to/deploy-tor-onion.md](../how-to/deploy-tor-onion.md) —
|
||||
Tor `directory` mode operator setup
|
||||
- [../how-to/set-up-bluetooth-peer.md](../how-to/set-up-bluetooth-peer.md)
|
||||
— Linux BLE peer config
|
||||