diff --git a/Cargo.toml b/Cargo.toml index 1682b18..219b1a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,30 @@ futures = "0.3" simple-dns = "0.11.2" socket2 = { version = "0.6.2", features = ["all"] } +[package.metadata.deb] +maintainer = "Johnathan Corgan " +copyright = "2026 Johnathan Corgan" +license-file = ["LICENSE", "0"] +section = "net" +priority = "optional" +depends = "libc6, systemd" +extended-description = """\ +FIPS is a distributed, decentralized network routing protocol for mesh \ +nodes connecting over arbitrary transports including UDP, TCP, and Ethernet. \ +It provides encrypted peer-to-peer connectivity with automatic key management, \ +TUN-based virtual networking, and .fips DNS resolution.""" +maintainer-scripts = "packaging/debian/" +assets = [ + ["target/release/fips", "/usr/bin/", "755"], + ["target/release/fipsctl", "/usr/bin/", "755"], + ["target/release/fipstop", "/usr/bin/", "755"], + ["packaging/common/fips.yaml", "/etc/fips/fips.yaml", "600"], + ["packaging/debian/fips.service", "/lib/systemd/system/fips.service", "644"], + ["packaging/debian/fips-dns.service", "/lib/systemd/system/fips-dns.service", "644"], + ["packaging/debian/fips.tmpfiles", "/usr/lib/tmpfiles.d/fips.conf", "644"], +] +conf-files = ["/etc/fips/fips.yaml"] + [dev-dependencies] tempfile = "3.15" criterion = { version = "0.8.2", features = ["html_reports"] } diff --git a/README.md b/README.md index 968b188..b886045 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,19 @@ identities, discover each other, and route traffic without any central authority or global topology knowledge. FIPS uses Nostr keypairs (secp256k1/schnorr) as native node identities, -making every Nostr user a potential network participant. Nodes address each -other by npub, and the same cryptographic identity used in the Nostr ecosystem -serves as both the routing address and the basis for end-to-end encrypted -sessions across the mesh. +allowing users to generate their own persistent or ephemeral node addresses. +Nodes address each other by npub, and the same cryptographic identity serves +as both the routing address and the basis for end-to-end encrypted sessions +across the mesh. + +FIPS allows existing TCP/IP based network software to use the FIPS mesh +network by generating a local IP address from the node npub and tunnelling +IP packets to other endpoints transparently knowing only their npub. Native +FIPS-aware applications do not need this IP tunneling or emulation capability. + +All traffic over the FIPS mesh is encrypted and authenticated both +hop-to-hop between peers and independently end-to-end between FIPS +endpoints. ## Features @@ -42,129 +51,177 @@ sessions across the mesh. measurement - **ECN congestion signaling** — hop-by-hop CE flag relay with RFC 3168 IPv6 marking, transport kernel drop detection -- **Operator visibility** — `fipsctl` control socket interface for runtime - inspection of peers, links, sessions, tree state, and metrics +- **Operator visibility** — `fipsctl` CLI and `fipstop` TUI dashboard for + runtime inspection of peers, links, sessions, tree state, and metrics - **Zero configuration** — sensible defaults; a node can start with no config file, though peer addresses are needed to join a network -## Quick Start +## Building -### Requirements - -- Rust 1.85+ (edition 2024) -- Linux (TUN interface requires `CAP_NET_ADMIN` or root) - -### Build - -``` +```bash git clone https://github.com/fips-network/fips.git cd fips cargo build --release ``` -### Run +Requires Rust 1.85+ (edition 2024) and Linux with TUN support. -``` -# Start with default search paths (see below): -sudo ./target/release/fips +## Installation -# With an explicit configuration file: -sudo ./target/release/fips -c fips.yaml +After building, choose one of the following methods to install. + +### Debian / Ubuntu (.deb) + +Requires [cargo-deb](https://crates.io/crates/cargo-deb): + +```bash +cargo install cargo-deb +cargo deb +sudo dpkg -i target/debian/fips_*.deb ``` -Without `-c`, the node searches for `fips.yaml` in these locations -(highest priority first, values from later files override earlier ones): +This installs the daemon, CLI tools, systemd units, and a default +configuration. Edit `/etc/fips/fips.yaml` before starting: -1. `./fips.yaml` (current directory) -2. `~/.config/fips/fips.yaml` (user config) -3. `/etc/fips/fips.yaml` (system) +```bash +sudo nano /etc/fips/fips.yaml +sudo systemctl start fips +``` -If no config file is found, the node starts with defaults (ephemeral -identity, default ports, no peers). +The service is enabled at boot automatically. To use `fipsctl` and +`fipstop` without sudo, add your user to the `fips` group: -A minimal two-node setup (each node points at the other): +```bash +sudo usermod -aG fips $USER # log out and back in to take effect +``` + +Remove with `sudo dpkg -r fips` (preserves config) or +`sudo dpkg -P fips` (removes everything including identity keys). + +### Generic Linux (systemd tarball) + +```bash +./packaging/systemd/build-tarball.sh +tar xzf deploy/fips-*-linux-*.tar.gz +cd fips-*-linux-*/ +sudo ./install.sh +``` + +See [packaging/systemd/README.install.md](packaging/systemd/README.install.md) +for the full installation and configuration guide. + +## Configuration + +The default configuration file is installed at `/etc/fips/fips.yaml`: ```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:2121" # bind_addr: "0.0.0.0:2121" -peers: # peers: - - npub: "npub1bbb..." # - npub: "npub1aaa..." - addresses: # addresses: - - transport: udp # - transport: udp - addr: "10.0.0.2:2121" # addr: "10.0.0.1:2121" +# FIPS Node Configuration + +node: + identity: + # By default, a new ephemeral keypair is generated on each start. + # Uncomment persistent to keep the same identity across restarts; + # on first start a keypair is saved to fips.key/fips.pub next to + # this config file (mode 0600/0644). + # persistent: true + # + # Or set an explicit key (overrides persistent): + # nsec: "nsec1..." + +tun: + enabled: true + name: fips0 + mtu: 1280 + +dns: + enabled: true + bind_addr: "127.0.0.1" + port: 5354 + +transports: + udp: + bind_addr: "0.0.0.0:2121" + + tcp: + # Accepts inbound connections. No static outbound peers. + bind_addr: "0.0.0.0:8443" + + # Ethernet transport — uncomment and set your interface name. + # ethernet: + # interface: "eth0" + # discovery: true + # announce: true + # auto_connect: true + # accept_connections: true + +peers: [] + # Static peers for bootstrapping (UDP or TCP): + # - npub: "npub1..." + # alias: "gateway" + # addresses: + # - transport: udp + # addr: "217.77.8.91:2121" # public FIPS testing node + # connect_policy: auto_connect ``` -The `nsec` field accepts bech32 (`nsec1...`) or hex-encoded secret keys. -Omit `nsec` for an ephemeral identity that changes each restart, or set -`node.identity.persistent: true` to auto-generate and reuse a stable -identity via key file (see -[fips-configuration.md](docs/design/fips-configuration.md#identity-nodeidentity)). +See [docs/design/fips-configuration.md](docs/design/fips-configuration.md) +for the full reference. -See [docs/design/fips-configuration.md](docs/design/fips-configuration.md) for -the full configuration reference. +## Usage -### Test Connectivity +### DNS Resolution -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. +FIPS includes a DNS resolver (enabled by default, port 5354) that maps +`.fips` names to fd00::/8 IPv6 addresses. With systemd-resolved: -With systemd-resolved: - -``` +```bash 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): +Then reach any FIPS node by npub with standard IPv6 tools: -``` -nameserver 127.0.0.1 -options port:5354 -``` - -Once DNS is configured, ping a peer by npub: - -``` +```bash ping6 npub1bbb....fips +ssh npub1bbb....fips ``` -Any IPv6-capable application can reach FIPS nodes this way — `ping6`, -`ssh`, `curl`, etc. +### Monitoring -### Inspect +Use `fipsctl` to query a running node: -While a node is running, use `fipsctl` to inspect its state: - -``` +```bash fipsctl show status # Node status overview fipsctl show peers # Authenticated peers fipsctl show links # Active links fipsctl show tree # Spanning tree state fipsctl show sessions # End-to-end sessions -fipsctl show bloom # Bloom filter state -fipsctl show mmp # MMP metrics summary -fipsctl show cache # Coordinate cache stats -fipsctl show connections # Pending handshake connections fipsctl show transports # Transport instances fipsctl show routing # Routing table summary ``` -`fipsctl` communicates with the node via a Unix domain control socket -(enabled by default). All queries are read-only. Use `-s ` to -override the socket path. +`fipstop` provides an interactive TUI dashboard with live-updating +views of node status, peers, links, sessions, tree state, transports, +and routing: -### Multi-node Testing +```bash +fipstop # connect to local daemon +fipstop -r 1 # 1-second refresh interval +``` -See [testing/](testing/) for Docker-based integration test harnesses including -static topology tests and stochastic chaos simulation. +### Service Management + +```bash +sudo systemctl start fips +sudo systemctl stop fips +sudo systemctl restart fips +sudo journalctl -u fips -f +``` + +### Testing + +See [testing/](testing/) for Docker-based integration test harnesses +including static topology tests and stochastic chaos simulation. ## Documentation @@ -175,7 +232,8 @@ a layered protocol specification. Start with ## Project Structure ``` -src/ Rust source (library + fips/fipsctl binaries) +src/ Rust source (library + fips/fipsctl/fipstop binaries) +packaging/ Debian, systemd tarball, and shared packaging files docs/design/ Protocol design specifications testing/ Docker-based integration test harnesses ``` diff --git a/packaging/debian/build-deb.sh b/packaging/debian/build-deb.sh new file mode 100755 index 0000000..216abf3 --- /dev/null +++ b/packaging/debian/build-deb.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Build a .deb package for FIPS using cargo-deb. +# +# Usage: ./build-deb.sh +# +# Prerequisites: cargo-deb (install with: cargo install cargo-deb) +# Output: deploy/fips__.deb + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_ROOT="${SCRIPT_DIR}/../.." + +cd "${PROJECT_ROOT}" + +# Ensure cargo-deb is available +if ! command -v cargo-deb &>/dev/null; then + echo "cargo-deb not found. Install with: cargo install cargo-deb" >&2 + exit 1 +fi + +# Build the .deb package +echo "Building .deb package..." +cargo deb + +# Move output to deploy/ +mkdir -p deploy +DEB_FILE=$(find target/debian -name '*.deb' -printf '%T@ %p\n' | sort -rn | head -1 | cut -d' ' -f2) + +if [ -z "${DEB_FILE}" ]; then + echo "Error: No .deb file found in target/debian/" >&2 + exit 1 +fi + +cp "${DEB_FILE}" deploy/ +BASENAME=$(basename "${DEB_FILE}") +echo "Package built: deploy/${BASENAME}" +echo "" +echo "Install with: sudo dpkg -i deploy/${BASENAME}" +echo "Remove with: sudo dpkg -r fips" +echo "Purge with: sudo dpkg -P fips (removes config and identity keys)" diff --git a/packaging/debian/copyright b/packaging/debian/copyright new file mode 100644 index 0000000..408c102 --- /dev/null +++ b/packaging/debian/copyright @@ -0,0 +1,27 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: fips +Upstream-Contact: Johnathan Corgan +Source: https://github.com/fips-network/fips + +Files: * +Copyright: 2026 Johnathan Corgan +License: MIT + +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packaging/debian/fips-dns.service b/packaging/debian/fips-dns.service new file mode 100644 index 0000000..459e810 --- /dev/null +++ b/packaging/debian/fips-dns.service @@ -0,0 +1,12 @@ +[Unit] +Description=Configure DNS routing for .fips domain +After=systemd-resolved.service +Wants=systemd-resolved.service + +[Service] +Type=oneshot +ExecStart=/usr/bin/bash -c 'while ! ip link show fips0 >/dev/null 2>&1; do sleep 1; done; /usr/bin/resolvectl dns fips0 127.0.0.1:5354; /usr/bin/resolvectl domain fips0 ~fips' +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/packaging/debian/fips.service b/packaging/debian/fips.service new file mode 100644 index 0000000..77d237d --- /dev/null +++ b/packaging/debian/fips.service @@ -0,0 +1,28 @@ +[Unit] +Description=FIPS Mesh Network Daemon +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +ExecStart=/usr/bin/fips --config /etc/fips/fips.yaml +Restart=on-failure +RestartSec=5 + +# Logging: RUST_LOG controls verbosity. +# Use "info" for production, "debug" for troubleshooting. +Environment=RUST_LOG=info + +# Control socket directory (/run/fips/). +# Group-readable so 'fips' group members can use fipsctl/fipstop. +RuntimeDirectory=fips +RuntimeDirectoryMode=0750 + +# Security hardening (daemon runs as root for TUN and raw sockets) +ProtectHome=yes +PrivateTmp=yes +ProtectKernelModules=yes +ProtectKernelTunables=no + +[Install] +WantedBy=multi-user.target diff --git a/packaging/debian/fips.tmpfiles b/packaging/debian/fips.tmpfiles new file mode 100644 index 0000000..3cb9cdf --- /dev/null +++ b/packaging/debian/fips.tmpfiles @@ -0,0 +1 @@ +d /run/fips 0750 root fips - diff --git a/packaging/debian/postinst b/packaging/debian/postinst new file mode 100755 index 0000000..c7e971d --- /dev/null +++ b/packaging/debian/postinst @@ -0,0 +1,34 @@ +#!/bin/sh +# FIPS post-install script for Debian/Ubuntu +set -e + +case "$1" in + configure) + # Create fips system group for control socket access + if ! getent group fips >/dev/null 2>&1; then + groupadd --system fips + fi + + # Ensure runtime directory exists with correct ownership + if [ -d /run/systemd/system ]; then + systemd-tmpfiles --create /usr/lib/tmpfiles.d/fips.conf 2>/dev/null || true + fi + + # Reload systemd and enable services + if [ -d /run/systemd/system ]; then + systemctl daemon-reload + systemctl enable fips.service 2>/dev/null || true + systemctl enable fips-dns.service 2>/dev/null || true + + # On upgrade, restart services that were running before + if [ -n "$2" ]; then + systemctl start fips.service 2>/dev/null || true + systemctl start fips-dns.service 2>/dev/null || true + fi + fi + ;; +esac + +#DEBHELPER# + +exit 0 diff --git a/packaging/debian/postrm b/packaging/debian/postrm new file mode 100755 index 0000000..696cfa4 --- /dev/null +++ b/packaging/debian/postrm @@ -0,0 +1,25 @@ +#!/bin/sh +# FIPS post-removal script for Debian/Ubuntu +set -e + +case "$1" in + purge) + # Remove configuration and identity keys + rm -rf /etc/fips/ + + # Remove tmpfiles.d entry + rm -f /usr/lib/tmpfiles.d/fips.conf + + # Remove runtime directory + rm -rf /run/fips/ + + # Remove fips system group + if getent group fips >/dev/null 2>&1; then + groupdel fips 2>/dev/null || true + fi + ;; +esac + +#DEBHELPER# + +exit 0 diff --git a/packaging/debian/prerm b/packaging/debian/prerm new file mode 100755 index 0000000..b8961ac --- /dev/null +++ b/packaging/debian/prerm @@ -0,0 +1,26 @@ +#!/bin/sh +# FIPS pre-removal script for Debian/Ubuntu +set -e + +case "$1" in + remove|purge) + if [ -d /run/systemd/system ]; then + systemctl stop fips-dns.service 2>/dev/null || true + systemctl disable fips-dns.service 2>/dev/null || true + systemctl stop fips.service 2>/dev/null || true + systemctl disable fips.service 2>/dev/null || true + systemctl daemon-reload + fi + ;; + upgrade) + # Stop services before upgrade; postinst will restart them + if [ -d /run/systemd/system ]; then + systemctl stop fips-dns.service 2>/dev/null || true + systemctl stop fips.service 2>/dev/null || true + fi + ;; +esac + +#DEBHELPER# + +exit 0