Setup fips in a qube

This commit is contained in:
Laan Tungir
2026-04-11 14:20:42 -04:00
commit a351883b67
27 changed files with 1427 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
#!/bin/bash
# ==============================================================================
# 00-build-fips.sh
#
# Build FIPS binaries from the bundled ./fips source tree and stage them into
# ./bin so the whole fips_setup directory can be copied to sys-fips.
#
# Usage:
# bash ./scripts/00-build-fips.sh
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
FIPS_DIR="${ROOT_DIR}/fips"
OUT_DIR="${ROOT_DIR}/bin"
if [ ! -f "${FIPS_DIR}/Cargo.toml" ]; then
echo "✗ Missing bundled fips source at: ${FIPS_DIR}"
exit 1
fi
echo "=== Building FIPS binaries from ${FIPS_DIR} ==="
echo ""
cd "${FIPS_DIR}"
cargo build --release --bin fips --bin fipsctl --bin fipstop
mkdir -p "${OUT_DIR}"
install -m 755 "${FIPS_DIR}/target/release/fips" "${OUT_DIR}/fips"
install -m 755 "${FIPS_DIR}/target/release/fipsctl" "${OUT_DIR}/fipsctl"
install -m 755 "${FIPS_DIR}/target/release/fipstop" "${OUT_DIR}/fipstop"
echo ""
echo "✓ Staged binaries in ${OUT_DIR}:"
ls -lh "${OUT_DIR}/fips" "${OUT_DIR}/fipsctl" "${OUT_DIR}/fipstop"
+99
View File
@@ -0,0 +1,99 @@
#!/bin/bash
# ==============================================================================
# 01-dom0-create-proxyvm.sh
#
# Run this script in dom0 to create the sys-fips ProxyVM.
#
# Usage (in dom0):
# sudo bash 01-dom0-create-proxyvm.sh [template] [upstream_netvm]
#
# Arguments:
# template TemplateVM to base on (default: debian-12)
# upstream_netvm Upstream NetVM (default: sys-firewall, can be sys-vpn)
# ==============================================================================
set -euo pipefail
TEMPLATE="${1:-debian-12}"
UPSTREAM_NETVM="${2:-sys-firewall}"
VM_NAME="sys-fips"
VM_LABEL="blue"
echo "=== sys-fips ProxyVM Creation ==="
echo ""
echo " VM Name: $VM_NAME"
echo " Template: $TEMPLATE"
echo " Upstream NetVM: $UPSTREAM_NETVM"
echo " Label: $VM_LABEL"
echo ""
# Check if VM already exists
if qvm-check "$VM_NAME" 2>/dev/null; then
echo "⚠ VM '$VM_NAME' already exists."
echo " To recreate, first remove it:"
echo " qvm-shutdown $VM_NAME"
echo " qvm-remove $VM_NAME"
exit 1
fi
# Verify template exists
if ! qvm-check "$TEMPLATE" 2>/dev/null; then
echo "✗ Template '$TEMPLATE' does not exist."
echo " Available templates:"
qvm-ls --raw-list --fields name,klass | grep TemplateVM | awk '{print " " $1}'
exit 1
fi
# Verify upstream netvm exists
if ! qvm-check "$UPSTREAM_NETVM" 2>/dev/null; then
echo "✗ Upstream NetVM '$UPSTREAM_NETVM' does not exist."
exit 1
fi
echo "Creating ProxyVM..."
# Create as AppVM + provides_network=True => ProxyVM behavior
qvm-create "$VM_NAME" \
--class AppVM \
--template "$TEMPLATE" \
--label "$VM_LABEL" \
--prop provides_network=True \
--prop netvm="$UPSTREAM_NETVM"
echo "✓ Created $VM_NAME"
# Memory defaults (lightweight baseline)
qvm-prefs "$VM_NAME" memory 512
qvm-prefs "$VM_NAME" maxmem 2048
echo "✓ Memory: 512MB initial, 2048MB max"
# Ensure networking prefs
qvm-prefs "$VM_NAME" netvm "$UPSTREAM_NETVM"
qvm-prefs "$VM_NAME" provides_network True
echo "✓ NetVM: $UPSTREAM_NETVM"
echo "✓ provides_network: True"
echo ""
echo "=== sys-fips Created Successfully ==="
echo ""
echo "Network chain examples:"
echo " AppVM -> sys-fips -> sys-firewall -> sys-net -> Internet"
echo " AppVM -> sys-fips -> sys-vpn -> sys-firewall -> sys-net -> Internet"
echo ""
echo "Next steps:"
echo ""
echo " 1) Start the VM:"
echo " qvm-start $VM_NAME"
echo ""
echo " 2) Copy FIPS binaries (from your build AppVM):"
echo " qvm-copy-to-vm $VM_NAME /home/user/lt/fips/target/release/fips"
echo " qvm-copy-to-vm $VM_NAME /home/user/lt/fips/target/release/fipsctl"
echo " qvm-copy-to-vm $VM_NAME /home/user/lt/fips/target/release/fipstop"
echo ""
echo " 3) Copy this setup directory:"
echo " qvm-copy-to-vm $VM_NAME /home/user/anvil/fips_setup/"
echo ""
echo " 4) In sys-fips terminal run:"
echo " cd ~/QubesIncoming/*/fips_setup/scripts/"
echo " sudo bash 02-install-fips.sh"
echo " bash 03-configure-identity.sh"
echo " sudo bash 04-start-fips.sh"
+190
View File
@@ -0,0 +1,190 @@
#!/bin/bash
# ==============================================================================
# 02-install-fips.sh
#
# Run inside sys-fips to install FIPS binaries, dependencies, config, and service.
#
# Usage:
# sudo bash 02-install-fips.sh
# ==============================================================================
set -euo pipefail
echo "=== sys-fips Installation ==="
echo ""
if [ "$(id -u)" -ne 0 ]; then
echo "✗ This script must be run as root (sudo)"
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
# ── Install dependencies ────────────────────────────────────────────────────────
echo "Installing system dependencies..."
apt-get update -qq
apt-get install -y --no-install-recommends \
iproute2 iputils-ping dnsutils \
dnsmasq iptables \
curl python3 jq \
openssh-server openssh-client \
iperf3 2>/dev/null || {
echo "⚠ Some packages may not be available — continuing"
}
echo "✓ Dependencies installed"
# ── Ensure control-socket access group exists ──────────────────────────────────
if ! getent group fips >/dev/null 2>&1; then
groupadd --system fips
echo "✓ Created system group: fips"
else
echo "✓ Group exists: fips"
fi
# ── Locate binaries ─────────────────────────────────────────────────────────────
echo ""
echo "Looking for FIPS binaries..."
FIPS_BIN=""
FIPSCTL_BIN=""
FIPSTOP_BIN=""
LOCAL_BIN_DIR="${ROOT_DIR}/bin"
LOCAL_RELEASE_DIR="${ROOT_DIR}/fips/target/release"
# Preferred: binaries prebuilt in this same repo copy
[ -z "$FIPS_BIN" ] && [ -f "${LOCAL_BIN_DIR}/fips" ] && FIPS_BIN="${LOCAL_BIN_DIR}/fips"
[ -z "$FIPSCTL_BIN" ] && [ -f "${LOCAL_BIN_DIR}/fipsctl" ] && FIPSCTL_BIN="${LOCAL_BIN_DIR}/fipsctl"
[ -z "$FIPSTOP_BIN" ] && [ -f "${LOCAL_BIN_DIR}/fipstop" ] && FIPSTOP_BIN="${LOCAL_BIN_DIR}/fipstop"
# Fallback: release artifacts in bundled fips source tree
[ -z "$FIPS_BIN" ] && [ -f "${LOCAL_RELEASE_DIR}/fips" ] && FIPS_BIN="${LOCAL_RELEASE_DIR}/fips"
[ -z "$FIPSCTL_BIN" ] && [ -f "${LOCAL_RELEASE_DIR}/fipsctl" ] && FIPSCTL_BIN="${LOCAL_RELEASE_DIR}/fipsctl"
[ -z "$FIPSTOP_BIN" ] && [ -f "${LOCAL_RELEASE_DIR}/fipstop" ] && FIPSTOP_BIN="${LOCAL_RELEASE_DIR}/fipstop"
# Legacy fallback: individually copied binaries in QubesIncoming
for incoming_dir in /home/user/QubesIncoming/*/; do
[ -z "$FIPS_BIN" ] && [ -f "${incoming_dir}fips" ] && FIPS_BIN="${incoming_dir}fips"
[ -z "$FIPSCTL_BIN" ] && [ -f "${incoming_dir}fipsctl" ] && FIPSCTL_BIN="${incoming_dir}fipsctl"
[ -z "$FIPSTOP_BIN" ] && [ -f "${incoming_dir}fipstop" ] && FIPSTOP_BIN="${incoming_dir}fipstop"
done
if [ -z "$FIPS_BIN" ]; then
echo "✗ Could not find 'fips' binary in this repo copy."
echo " Expected one of:"
echo " ${LOCAL_BIN_DIR}/fips"
echo " ${LOCAL_RELEASE_DIR}/fips"
echo ""
echo " Build before copying into sys-fips:"
echo " bash ./scripts/00-build-fips.sh"
exit 1
fi
echo " Found fips: $FIPS_BIN"
[ -n "$FIPSCTL_BIN" ] && echo " Found fipsctl: $FIPSCTL_BIN"
[ -n "$FIPSTOP_BIN" ] && echo " Found fipstop: $FIPSTOP_BIN"
# ── Install binaries ────────────────────────────────────────────────────────────
install -m 755 "$FIPS_BIN" /usr/local/bin/fips
echo "✓ Installed /usr/local/bin/fips"
if [ -n "$FIPSCTL_BIN" ]; then
install -m 755 "$FIPSCTL_BIN" /usr/local/bin/fipsctl
echo "✓ Installed /usr/local/bin/fipsctl"
fi
if [ -n "$FIPSTOP_BIN" ]; then
install -m 755 "$FIPSTOP_BIN" /usr/local/bin/fipstop
echo "✓ Installed /usr/local/bin/fipstop"
fi
# ── Ensure runtime dirs and TUN ─────────────────────────────────────────────────
mkdir -p /etc/fips /var/log/fips /var/run/fips
if [ ! -c /dev/net/tun ]; then
echo "Creating /dev/net/tun..."
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 666 /dev/net/tun
fi
echo "✓ Runtime directories and TUN are ready"
# ── Install config ──────────────────────────────────────────────────────────────
if [ -f /etc/fips/fips.yaml ]; then
echo "⚠ /etc/fips/fips.yaml already exists; preserving existing file"
else
if [ -f "${ROOT_DIR}/configs/fips.yaml" ]; then
install -m 600 "${ROOT_DIR}/configs/fips.yaml" /etc/fips/fips.yaml
echo "✓ Installed /etc/fips/fips.yaml"
else
cat > /etc/fips/fips.yaml << 'EOF'
node:
identity:
persistent: true
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"
mtu: 1472
peers: []
EOF
chmod 600 /etc/fips/fips.yaml
echo "✓ Installed default /etc/fips/fips.yaml"
fi
fi
# ── Install systemd service (single node) ──────────────────────────────────────
cat > /etc/systemd/system/fips.service << 'EOF'
[Unit]
Description=FIPS Mesh Network Daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/fips --config /etc/fips/fips.yaml
Restart=on-failure
RestartSec=5
RuntimeDirectory=fips
RuntimeDirectoryMode=0750
ProtectHome=yes
PrivateTmp=yes
ProtectKernelModules=yes
ProtectKernelTunables=no
[Install]
WantedBy=multi-user.target
EOF
echo "✓ Installed /etc/systemd/system/fips.service"
systemctl daemon-reload
systemctl enable fips >/dev/null 2>&1 || true
echo ""
echo "=== Installation complete ==="
echo ""
if [ -n "${SUDO_USER:-}" ] && [ "${SUDO_USER}" != "root" ]; then
echo "Control socket access tip:"
echo " sudo usermod -aG fips ${SUDO_USER}"
echo " (then log out/in, or use 'sudo fipsctl ...')"
echo ""
fi
echo "Next steps:"
echo " sudo bash 03-configure-identity.sh"
echo " sudo bash 04-start-fips.sh"
echo " sudo bash 06-configure-dns.sh"
echo " sudo bash 07-route-appvms.sh"
+94
View File
@@ -0,0 +1,94 @@
#!/bin/bash
# ==============================================================================
# 03-configure-identity.sh
#
# Configure identity behavior for single-node sys-fips.
#
# Usage:
# sudo bash 03-configure-identity.sh
# ==============================================================================
set -euo pipefail
CONFIG_FILE="/etc/fips/fips.yaml"
echo "=== FIPS Identity Configuration ==="
echo ""
if [ "$(id -u)" -ne 0 ]; then
echo "✗ Run as root: sudo bash 03-configure-identity.sh"
exit 1
fi
if [ ! -f "$CONFIG_FILE" ]; then
echo "$CONFIG_FILE not found"
echo " Run: sudo bash 02-install-fips.sh"
exit 1
fi
if [ -f /etc/fips/fips.pub ]; then
echo "Current identity detected:"
echo " npub: $(cat /etc/fips/fips.pub)"
echo ""
fi
echo "Identity modes:"
echo " 1) persistent (recommended): key auto-generated once and reused"
echo " 2) explicit nsec: pin node identity to a specific key"
echo ""
read -r -p "Select mode [1/2] (default 1): " MODE
MODE="${MODE:-1}"
set_identity_block() {
local identity_line="$1"
local tmp
tmp=$(mktemp)
# Replace node.identity block in known config format: node: ... then tun:
awk -v ident="$identity_line" '
BEGIN { replaced=0; skipping=0 }
/^node:[[:space:]]*$/ && replaced==0 {
print "node:";
print " identity:";
print " " ident;
replaced=1;
skipping=1;
next;
}
skipping==1 {
if (/^tun:[[:space:]]*$/) {
skipping=0;
print $0;
}
next;
}
{ print $0 }
' "$CONFIG_FILE" > "$tmp"
mv "$tmp" "$CONFIG_FILE"
chmod 600 "$CONFIG_FILE"
}
case "$MODE" in
1)
set_identity_block "persistent: true"
echo "✓ Set node.identity.persistent=true"
;;
2)
read -r -p "Enter nsec (bech32 or 64-char hex): " NSEC
if [ -z "$NSEC" ]; then
echo "✗ Empty nsec is not allowed"
exit 1
fi
set_identity_block "nsec: \"$NSEC\""
echo "✓ Set node.identity.nsec"
;;
*)
echo "✗ Invalid selection"
exit 1
;;
esac
echo ""
echo "Config updated: $CONFIG_FILE"
echo "Next: sudo bash 04-start-fips.sh"
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
# Compatibility wrapper: old two-node script name -> new single-node identity script
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec bash "${SCRIPT_DIR}/03-configure-identity.sh"
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
# Compatibility wrapper: old two-node script name -> new single-node start script
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec bash "${SCRIPT_DIR}/04-start-fips.sh"
+81
View File
@@ -0,0 +1,81 @@
#!/bin/bash
# ==============================================================================
# 04-start-fips.sh
#
# Start a single FIPS node in sys-fips, wait for fips0, and set route.
#
# Usage:
# sudo bash 04-start-fips.sh
# ==============================================================================
set -euo pipefail
CONFIG_FILE="/etc/fips/fips.yaml"
ENV_FILE="/etc/fips/node.env"
echo "=== Starting FIPS (single node) ==="
echo ""
if [ "$(id -u)" -ne 0 ]; then
echo "✗ This script must be run as root (sudo)"
exit 1
fi
if [ ! -f "$CONFIG_FILE" ]; then
echo "$CONFIG_FILE not found"
echo " Run: sudo bash 02-install-fips.sh"
exit 1
fi
sysctl -w net.ipv6.conf.all.disable_ipv6=0 >/dev/null 2>&1 || true
sysctl -w net.ipv6.conf.all.forwarding=1 >/dev/null 2>&1 || true
echo "✓ IPv6 + forwarding enabled"
systemctl daemon-reload
systemctl restart fips
sleep 1
if ! systemctl is-active --quiet fips; then
echo "✗ fips service is not active"
echo " Check: journalctl -u fips -n 100 --no-pager"
exit 1
fi
echo "✓ fips service active"
echo "Waiting for fips0..."
for i in $(seq 1 30); do
if ip link show fips0 >/dev/null 2>&1; then
break
fi
sleep 1
done
if ! ip link show fips0 >/dev/null 2>&1; then
echo "✗ fips0 did not appear within 30s"
echo " Check: journalctl -u fips -n 100 --no-pager"
exit 1
fi
IPV6=$(ip -6 addr show fips0 scope global 2>/dev/null | awk '/inet6/{print $2}' | cut -d/ -f1 | head -1)
NPUB=""
if [ -f /etc/fips/fips.pub ]; then
NPUB=$(cat /etc/fips/fips.pub)
elif command -v fipsctl >/dev/null 2>&1; then
NPUB=$(fipsctl show status 2>/dev/null | python3 -c 'import json,sys; print(json.load(sys.stdin).get("npub",""))' 2>/dev/null || true)
fi
ip -6 route replace fd00::/8 dev fips0 2>/dev/null || true
cat > "$ENV_FILE" << EOF
NPUB=${NPUB}
IPV6=${IPV6}
EOF
echo ""
echo "✓ fips0 is up"
echo " npub: ${NPUB:-unknown}"
echo " ipv6: ${IPV6:-unknown}"
echo " route: fd00::/8 -> fips0"
echo ""
echo "Next: sudo bash 06-configure-dns.sh"
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
# Compatibility wrapper: old two-node script name -> new single-node stop script
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec bash "${SCRIPT_DIR}/05-stop-fips.sh"
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
# ==============================================================================
# 05-stop-fips.sh
#
# Stop single FIPS node and clean up route.
#
# Usage:
# sudo bash 05-stop-fips.sh
# ==============================================================================
set -euo pipefail
echo "=== Stopping FIPS (single node) ==="
echo ""
if [ "$(id -u)" -ne 0 ]; then
echo "✗ This script must be run as root (sudo)"
exit 1
fi
systemctl stop fips 2>/dev/null || true
ip -6 route del fd00::/8 dev fips0 2>/dev/null || true
echo "✓ fips service stopped"
if ip link show fips0 >/dev/null 2>&1; then
echo " fips0 still present (will disappear when process exits completely)"
else
echo " fips0 removed"
fi
echo ""
echo "Done"
+93
View File
@@ -0,0 +1,93 @@
#!/bin/bash
# ==============================================================================
# 06-configure-dns.sh
#
# Configure dnsmasq in sys-fips so .fips queries are forwarded to local
# FIPS DNS resolver on 127.0.0.1:5354, and all other DNS goes upstream.
#
# Usage:
# sudo bash 06-configure-dns.sh
# ==============================================================================
set -euo pipefail
echo "=== sys-fips DNS Configuration ==="
echo ""
if [ "$(id -u)" -ne 0 ]; then
echo "✗ This script must be run as root (sudo)"
exit 1
fi
systemctl stop dnsmasq 2>/dev/null || true
killall dnsmasq 2>/dev/null || true
UPSTREAM_DNS=$(grep '^nameserver' /etc/resolv.conf | awk '{print $2}' | head -1)
UPSTREAM_DNS="${UPSTREAM_DNS:-10.139.1.1}"
echo " Upstream DNS: $UPSTREAM_DNS"
mkdir -p /etc/dnsmasq.d
cat > /etc/dnsmasq.d/fips.conf << EOF
# sys-fips DNS resolution
port=53
listen-address=0.0.0.0
bind-interfaces
# .fips domains -> FIPS resolver
server=/fips/127.0.0.1#5354
# everything else -> upstream
server=$UPSTREAM_DNS
no-resolv
no-hosts
# log-queries
EOF
if [ ! -f /etc/dnsmasq.conf ]; then
touch /etc/dnsmasq.conf
fi
if ! grep -q 'conf-dir=/etc/dnsmasq.d/,*.conf' /etc/dnsmasq.conf; then
echo 'conf-dir=/etc/dnsmasq.d/,*.conf' >> /etc/dnsmasq.conf
fi
if ! dnsmasq --test >/dev/null 2>&1; then
echo "✗ dnsmasq config failed validation"
exit 1
fi
# Qubes AppVMs often use /32 point-to-point addressing.
# Debian's dnsmasq systemd-helper adds --local-service by default,
# which can reject DNS queries from downstream AppVMs in this topology.
DNSMASQ_HELPER="/usr/share/dnsmasq/systemd-helper"
if [ -f "$DNSMASQ_HELPER" ] && grep -q -- '--local-service' "$DNSMASQ_HELPER"; then
cp "$DNSMASQ_HELPER" "${DNSMASQ_HELPER}.bak"
sed -i 's/--local-service//g' "$DNSMASQ_HELPER"
echo " Patched dnsmasq helper: removed --local-service for Qubes /32 compatibility"
fi
if command -v systemctl >/dev/null 2>&1; then
systemctl restart dnsmasq || true
fi
if ! pgrep -x dnsmasq >/dev/null 2>&1; then
dnsmasq
fi
echo ""
echo "Verifying DNS..."
if dig @127.0.0.1 google.com A +short +time=2 >/dev/null 2>&1; then
echo " Upstream DNS: OK"
else
echo " Upstream DNS: WARN (may be expected in isolated setup)"
fi
STATUS=$(dig @127.0.0.1 test.fips AAAA +time=2 2>&1 | grep 'status:' || true)
if echo "$STATUS" | grep -qE 'NXDOMAIN|SERVFAIL|NOERROR'; then
echo " .fips forwarding: OK"
else
echo " .fips forwarding: WARN"
fi
echo ""
echo "✓ DNS configured"
+72
View File
@@ -0,0 +1,72 @@
#!/bin/bash
# ==============================================================================
# 07-route-appvms.sh
#
# Configure IPv6 forwarding and ip6tables rules in sys-fips so AppVMs routed
# through sys-fips can reach FIPS fd00::/8 addresses via fips0.
#
# Usage:
# sudo bash 07-route-appvms.sh
# ==============================================================================
set -euo pipefail
echo "=== sys-fips AppVM Routing Configuration ==="
echo ""
if [ "$(id -u)" -ne 0 ]; then
echo "✗ This script must be run as root (sudo)"
exit 1
fi
sysctl -w net.ipv6.conf.all.forwarding=1 >/dev/null
sysctl -w net.ipv6.conf.all.proxy_ndp=1 >/dev/null 2>&1 || true
sysctl -w net.ipv6.conf.all.disable_ipv6=0 >/dev/null 2>&1 || true
echo " IPv6 forwarding enabled"
if ! ip link show fips0 >/dev/null 2>&1; then
echo " WARNING: fips0 not found (start fips first)"
fi
ip -6 route replace fd00::/8 dev fips0 2>/dev/null || true
echo " route: fd00::/8 -> fips0"
# idempotent rule refresh
ip6tables -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
ip6tables -D FORWARD -d fd00::/8 -o fips0 -j ACCEPT 2>/dev/null || true
ip6tables -D FORWARD -s fd00::/8 -i fips0 -j ACCEPT 2>/dev/null || true
ip6tables -I FORWARD 1 -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -I FORWARD 2 -d fd00::/8 -o fips0 -j ACCEPT
ip6tables -I FORWARD 3 -s fd00::/8 -i fips0 -j ACCEPT
echo " ip6tables forwarding rules installed"
RCLOCAL="/rw/config/rc.local"
MARK_START="# === SYS-FIPS ROUTING START ==="
MARK_END="# === SYS-FIPS ROUTING END ==="
if [ -f "$RCLOCAL" ]; then
sed -i "/$MARK_START/,/$MARK_END/d" "$RCLOCAL"
fi
cat >> "$RCLOCAL" << 'EOF'
# === SYS-FIPS ROUTING START ===
sysctl -w net.ipv6.conf.all.forwarding=1 >/dev/null 2>&1
sysctl -w net.ipv6.conf.all.disable_ipv6=0 >/dev/null 2>&1
ip6tables -I FORWARD 1 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null
ip6tables -I FORWARD 2 -d fd00::/8 -o fips0 -j ACCEPT 2>/dev/null
ip6tables -I FORWARD 3 -s fd00::/8 -i fips0 -j ACCEPT 2>/dev/null
# === SYS-FIPS ROUTING END ===
EOF
chmod +x "$RCLOCAL"
echo ""
echo "Current fd00 routes:"
ip -6 route show | grep fd00 || true
echo ""
echo "✓ AppVM routing configured"
echo ""
echo "In dom0, point an AppVM at sys-fips:"
echo " qvm-prefs <appvm-name> netvm sys-fips"
+88
View File
@@ -0,0 +1,88 @@
#!/bin/bash
# ==============================================================================
# 08-add-peer.sh
#
# Add a static UDP peer to /etc/fips/fips.yaml (single-node mode).
#
# Usage:
# sudo bash 08-add-peer.sh [npub] [alias] [host:port]
#
# If arguments are omitted, prompts interactively.
# ==============================================================================
set -euo pipefail
CONFIG_FILE="/etc/fips/fips.yaml"
echo "=== Add FIPS Peer ==="
echo ""
if [ "$(id -u)" -ne 0 ]; then
echo "✗ This script must be run as root (sudo)"
exit 1
fi
if [ ! -f "$CONFIG_FILE" ]; then
echo "$CONFIG_FILE not found"
echo " Run: sudo bash 02-install-fips.sh"
exit 1
fi
NPUB="${1:-}"
ALIAS="${2:-}"
ADDR="${3:-}"
if [ -z "$NPUB" ]; then
read -r -p "Peer npub: " NPUB
fi
if [ -z "$ALIAS" ]; then
read -r -p "Alias (default peer): " ALIAS
ALIAS="${ALIAS:-peer}"
fi
if [ -z "$ADDR" ]; then
read -r -p "UDP address (host:port): " ADDR
fi
if ! echo "$NPUB" | grep -q '^npub1'; then
echo "✗ npub must start with 'npub1'"
exit 1
fi
if ! echo "$ADDR" | grep -q ':'; then
echo "✗ address must be in host:port format"
exit 1
fi
tmp=$(mktemp)
if grep -q '^peers:[[:space:]]*\[\][[:space:]]*$' "$CONFIG_FILE"; then
sed 's/^peers:[[:space:]]*\[\][[:space:]]*$/peers:/' "$CONFIG_FILE" > "$tmp"
cat >> "$tmp" << EOF
- npub: "$NPUB"
alias: "$ALIAS"
addresses:
- transport: udp
addr: "$ADDR"
connect_policy: auto_connect
EOF
else
cp "$CONFIG_FILE" "$tmp"
cat >> "$tmp" << EOF
- npub: "$NPUB"
alias: "$ALIAS"
addresses:
- transport: udp
addr: "$ADDR"
connect_policy: auto_connect
EOF
fi
mv "$tmp" "$CONFIG_FILE"
chmod 600 "$CONFIG_FILE"
echo ""
echo "✓ Peer added"
echo " npub: $NPUB"
echo " alias: $ALIAS"
echo " addr: $ADDR"
echo ""
echo "Restart FIPS to apply:"
echo " sudo systemctl restart fips"
+65
View File
@@ -0,0 +1,65 @@
#!/bin/bash
# ==============================================================================
# 09-add-known-peers.sh
#
# Add known public bootstrap peers to /etc/fips/fips.yaml.
# Safe to run multiple times (idempotent by npub check).
#
# Usage:
# sudo bash 09-add-known-peers.sh
# ==============================================================================
set -euo pipefail
CONFIG_FILE="/etc/fips/fips.yaml"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ADD_PEER_SCRIPT="${SCRIPT_DIR}/08-add-peer.sh"
PEER1_NPUB="npub1qmc3cvfz0yu2hx96nq3gp55zdan2qclealn7xshgr448d3nh6lks7zel98"
PEER1_ALIAS="fips-test-node"
PEER1_ADDR="217.77.8.91:2121"
PEER2_NPUB="npub1zv58cn7v83mxvttl70w5fwjwuclfmntv9cnmv5wmz2nzz88u5urqvdx96n"
PEER2_ALIAS="fips.v0l.io"
PEER2_ADDR="fips.v0l.io:2121"
if [ "$(id -u)" -ne 0 ]; then
echo "✗ This script must be run as root (sudo)"
exit 1
fi
if [ ! -f "$CONFIG_FILE" ]; then
echo "$CONFIG_FILE not found"
echo " Run: sudo bash 02-install-fips.sh"
exit 1
fi
if [ ! -x "$ADD_PEER_SCRIPT" ]; then
echo "✗ Missing helper script: $ADD_PEER_SCRIPT"
exit 1
fi
add_if_missing() {
local npub="$1"
local alias="$2"
local addr="$3"
if grep -q "$npub" "$CONFIG_FILE"; then
echo "• already present: $alias ($npub)"
else
bash "$ADD_PEER_SCRIPT" "$npub" "$alias" "$addr"
fi
}
echo "=== Add Known Bootstrap Peers ==="
echo ""
add_if_missing "$PEER1_NPUB" "$PEER1_ALIAS" "$PEER1_ADDR"
add_if_missing "$PEER2_NPUB" "$PEER2_ALIAS" "$PEER2_ADDR"
echo ""
echo "Restarting fips service..."
systemctl restart fips
echo ""
echo "✓ Known peers configured"
echo "Check with: sudo fipsctl show peers"
+132
View File
@@ -0,0 +1,132 @@
#!/bin/bash
# ==============================================================================
# test-connectivity.sh
#
# Unified connectivity tests for sys-fips.
#
# Modes:
# --local tests expected to run in sys-fips
# --appvm tests expected to run in an AppVM routed via sys-fips
# --full run everything reasonably applicable (default)
# ==============================================================================
set -euo pipefail
MODE="${1:---full}"
PASSED=0
FAILED=0
SKIPPED=0
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
NC='\033[0m'
pass() { echo -e "${GREEN}PASS${NC}: $1"; PASSED=$((PASSED + 1)); }
fail() { echo -e "${RED}FAIL${NC}: $1"; FAILED=$((FAILED + 1)); }
skip() { echo -e "${YELLOW}SKIP${NC}: $1"; SKIPPED=$((SKIPPED + 1)); }
is_sys_fips=false
if ip link show fips0 >/dev/null 2>&1 || [ -f /etc/systemd/system/fips.service ]; then
is_sys_fips=true
fi
echo "=== FIPS Connectivity Test ($MODE) ==="
echo ""
run_local_tests() {
if command -v fips >/dev/null 2>&1; then
pass "fips binary installed"
else
fail "fips binary missing"
fi
if systemctl is-active --quiet fips 2>/dev/null; then
pass "fips service active"
else
fail "fips service not active"
fi
if ip link show fips0 >/dev/null 2>&1; then
pass "fips0 exists"
IPV6=$(ip -6 addr show fips0 scope global 2>/dev/null | awk '/inet6/{print $2}' | cut -d/ -f1 | head -1)
if [ -n "${IPV6:-}" ]; then
pass "fips0 has IPv6 (${IPV6})"
else
fail "fips0 has no global IPv6"
fi
else
fail "fips0 missing"
fi
if ip -6 route show | grep -q 'fd00::/8'; then
pass "fd00::/8 route present"
else
fail "fd00::/8 route missing"
fi
if pgrep -x dnsmasq >/dev/null 2>&1; then
pass "dnsmasq running"
else
fail "dnsmasq not running"
fi
if dig @127.0.0.1 test.fips AAAA +time=2 >/dev/null 2>&1; then
pass ".fips DNS query path reachable"
else
fail ".fips DNS query path failed"
fi
}
run_appvm_tests() {
GW=$(ip route show default 2>/dev/null | awk '{print $3}' | head -1)
if [ -n "$GW" ]; then
pass "default gateway present ($GW)"
else
fail "default gateway missing"
fi
if [ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6 2>/dev/null || echo 1)" = "0" ]; then
pass "IPv6 enabled"
else
fail "IPv6 disabled"
fi
if command -v dig >/dev/null 2>&1; then
STATUS=$(dig test.fips AAAA +time=3 2>&1 | grep 'status:' || true)
if echo "$STATUS" | grep -qE 'NXDOMAIN|SERVFAIL|NOERROR'; then
pass ".fips DNS forwarding path reachable"
else
fail ".fips DNS forwarding path unreachable"
fi
else
skip "dig not installed"
fi
}
case "$MODE" in
--local)
run_local_tests
;;
--appvm)
run_appvm_tests
;;
--full)
if [ "$is_sys_fips" = true ]; then
run_local_tests
else
skip "local sys-fips checks skipped (not in sys-fips)"
fi
run_appvm_tests
;;
*)
echo "Usage: $0 [--local|--appvm|--full]"
exit 1
;;
esac
echo ""
echo "Results: pass=$PASSED fail=$FAILED skip=$SKIPPED"
if [ "$FAILED" -gt 0 ]; then
exit 1
fi
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# Compatibility wrapper
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec bash "${SCRIPT_DIR}/test-connectivity.sh" --appvm
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# Compatibility wrapper
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec bash "${SCRIPT_DIR}/test-connectivity.sh" --full
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# Compatibility wrapper
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec bash "${SCRIPT_DIR}/test-connectivity.sh" --local