diff --git a/README.md b/README.md
index b751761..5b12879 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,16 @@
# FIPS: Free Internetworking Peering System
+[](LICENSE)
+[](https://www.rust-lang.org/)
+[-yellow.svg)](#status--roadmap)
+
A distributed, decentralized network routing protocol for mesh nodes
connecting over arbitrary transports.
-> **Status: Experimental / Pre-release**
+> **Status: Alpha (0.1.0)**
>
> FIPS is under active development. The protocol and APIs are not stable.
-> Expect breaking changes.
+> Expect breaking changes. See [Status & Roadmap](#status--roadmap) below.
## Overview
@@ -38,8 +42,8 @@ sessions across the mesh.
measurement
- **Operator visibility** — `fipsctl` control socket interface for runtime
inspection of peers, links, sessions, tree state, and metrics
-- **Zero configuration** — sensible defaults; a node can run with no config
- file
+- **Zero configuration** — sensible defaults; a node can start with no config
+ file, though peer addresses are needed to join a network
## Quick Start
@@ -59,16 +63,77 @@ cargo build --release
### Run
```
-# With default configuration (ephemeral identity, default ports):
+# Start with default search paths (see below):
sudo ./target/release/fips
-# With a configuration file:
+# With an explicit configuration file:
sudo ./target/release/fips -c fips.yaml
```
+Without `-c`, the node searches for `fips.yaml` in these locations
+(highest priority first, values from later files override earlier ones):
+
+1. `./fips.yaml` (current directory)
+2. `~/.config/fips/fips.yaml` (user config)
+3. `/etc/fips/fips.yaml` (system)
+
+If no config file is found, the node starts with defaults (ephemeral
+identity, default ports, no peers).
+
+A minimal two-node setup (each node points at the other):
+
+```yaml
+# node-a.yaml # node-b.yaml
+node: # node:
+ identity: # identity:
+ nsec: "nsec1aaa..." # nsec: "nsec1bbb..."
+transports: # transports:
+ udp: # udp:
+ bind_addr: "0.0.0.0:4000" # bind_addr: "0.0.0.0:4000"
+peers: # peers:
+ - npub: "npub1bbb..." # - npub: "npub1aaa..."
+ addresses: # addresses:
+ - transport: udp # - transport: udp
+ addr: "10.0.0.2:4000" # addr: "10.0.0.1:4000"
+```
+
+The `nsec` field accepts bech32 (`nsec1...`) or hex-encoded secret keys.
+Omit it entirely for an ephemeral identity that changes each restart.
+
See [docs/design/fips-configuration.md](docs/design/fips-configuration.md) for
the full configuration reference.
+### Test Connectivity
+
+FIPS includes a built-in DNS resolver (enabled by default, port 5354)
+that maps `.fips` names to fd00::/8 IPv6 addresses derived from each
+node's public key. Configure your system to send `.fips` queries to it.
+
+With systemd-resolved:
+
+```
+sudo resolvectl dns fips0 127.0.0.1:5354
+sudo resolvectl domain fips0 ~fips
+```
+
+Or manually in `/etc/resolv.conf` (routes all DNS through FIPS for
+`.fips` names only if your resolver supports conditional forwarding;
+otherwise this sets it as a general nameserver):
+
+```
+nameserver 127.0.0.1
+options port:5354
+```
+
+Once DNS is configured, ping a peer by npub:
+
+```
+ping6 npub1bbb....fips
+```
+
+Any IPv6-capable application can reach FIPS nodes this way — `ping6`,
+`ssh`, `curl`, etc.
+
### Inspect
While a node is running, use `fipsctl` to inspect its state:
@@ -108,9 +173,37 @@ a layered protocol specification. Start with
src/ Rust source (library + fips/fipsctl binaries)
docs/design/ Protocol design specifications
testing/ Docker-based integration test harnesses
-benches/ Criterion benchmarks
```
+## Status & Roadmap
+
+FIPS is at **v0.1.0 (alpha)**. The core protocol works end-to-end over
+UDP/IP overlays but has not been tested beyond small meshes.
+
+### What works today
+
+- Spanning tree construction with greedy coordinate routing
+- Bloom filter discovery for finding nodes without global state
+- Noise IK (link layer) and Noise XK (session layer) encryption
+- IPv6 TUN adapter with DNS resolution of `.fips` names
+- Per-link metrics (RTT, loss, jitter, goodput)
+- Runtime inspection via `fipsctl`
+- Docker-based integration and chaos testing
+
+### Near-term priorities
+
+- Peer discovery via Nostr relays (bootstrap without static peer lists)
+- Additional transports (Ethernet, Tor)
+- Improved routing resilience under churn
+- Security audit of cryptographic protocols
+- CI pipeline and published crate
+
+### Longer-term
+
+- Mobile platform support
+- Bandwidth-aware routing and QoS
+- Protocol stability and versioned wire format
+
## License
MIT — see [LICENSE](LICENSE).
diff --git a/docs/design/README.md b/docs/design/README.md
index c4a2796..e171f1d 100644
--- a/docs/design/README.md
+++ b/docs/design/README.md
@@ -48,27 +48,4 @@ specific topics.
## Document Relationships
-```text
- fips-intro.md
- │
- ┌──────────────┼──────────────┐
- ▼ ▼ │
- fips-transport-layer fips-mesh- │
- │ operation │
- ▼ │ │
- fips-mesh-layer ◄────────┤ │
- │ │ │
- ▼ ├──► fips-spanning-tree
- fips-session-layer │ │
- │ └──► fips-bloom-filters
- ▼
- fips-ipv6-adapter
- fips-wire-formats
- (referenced by all layer docs)
-
- fips-configuration
- (standalone reference)
-
- spanning-tree-dynamics
- (pedagogical companion to fips-spanning-tree)
-```
+
diff --git a/docs/design/document-relationships.svg b/docs/design/document-relationships.svg
new file mode 100644
index 0000000..dcc0860
--- /dev/null
+++ b/docs/design/document-relationships.svg
@@ -0,0 +1,100 @@
+
diff --git a/docs/design/fips-configuration.md b/docs/design/fips-configuration.md
index 02e6f3a..4d3f00a 100644
--- a/docs/design/fips-configuration.md
+++ b/docs/design/fips-configuration.md
@@ -229,7 +229,7 @@ with the node for routing.
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
-| `dns.enabled` | bool | `false` | Enable DNS responder |
+| `dns.enabled` | bool | `true` | Enable DNS responder |
| `dns.bind_addr` | string | `"127.0.0.1"` | Bind address |
| `dns.port` | u16 | `5354` | Listen port |
| `dns.ttl` | u32 | `300` | AAAA record TTL in seconds |
@@ -387,7 +387,7 @@ tun:
mtu: 1280
dns:
- enabled: false
+ enabled: true
bind_addr: "127.0.0.1"
port: 5354
ttl: 300
diff --git a/src/config/mod.rs b/src/config/mod.rs
index bbe37e5..36ffd9e 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -186,10 +186,8 @@ impl Config {
if other.tun.mtu.is_some() {
self.tun.mtu = other.tun.mtu;
}
- // Merge dns section
- if other.dns.enabled {
- self.dns.enabled = true;
- }
+ // Merge dns section — higher-priority config always wins for enabled
+ self.dns.enabled = other.dns.enabled;
if other.dns.bind_addr.is_some() {
self.dns.bind_addr = other.dns.bind_addr;
}
diff --git a/src/upper/config.rs b/src/upper/config.rs
index 3286b61..c1e77aa 100644
--- a/src/upper/config.rs
+++ b/src/upper/config.rs
@@ -20,11 +20,15 @@ const DEFAULT_DNS_PORT: u16 = 5354;
/// Default DNS record TTL in seconds (5 minutes).
const DEFAULT_DNS_TTL: u32 = 300;
+fn default_true() -> bool {
+ true
+}
+
/// DNS responder configuration (`dns.*`).
-#[derive(Debug, Clone, Default, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DnsConfig {
- /// Enable DNS responder (`dns.enabled`).
- #[serde(default, skip_serializing_if = "std::ops::Not::not")]
+ /// Enable DNS responder (`dns.enabled`, default: true).
+ #[serde(default = "default_true")]
pub enabled: bool,
/// Bind address (`dns.bind_addr`).
@@ -40,6 +44,17 @@ pub struct DnsConfig {
pub ttl: Option,
}
+impl Default for DnsConfig {
+ fn default() -> Self {
+ Self {
+ enabled: true,
+ bind_addr: None,
+ port: None,
+ ttl: None,
+ }
+ }
+}
+
impl DnsConfig {
/// Get the bind address (default: 127.0.0.1).
pub fn bind_addr(&self) -> &str {