Files
2026-05-08 10:54:03 -04:00

191 lines
5.0 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
TEST_URL="http://npub1crpldvy49ef8z34wlacwujnfudy4nd7k96aqdx5wgn6ckztz7z8q9t59ud.fips/index.html"
CURL_TIMEOUT="${CURL_TIMEOUT:-20}"
MIN_BYTES="${MIN_BYTES:-1000}"
if ! command -v curl >/dev/null 2>&1; then
echo "Error: curl is required." >&2
exit 1
fi
if ! command -v ip >/dev/null 2>&1; then
echo "Error: iproute2 (ip command) is required." >&2
exit 1
fi
if ! command -v python3 >/dev/null 2>&1; then
echo "Error: python3 is required." >&2
exit 1
fi
get_cmd_output() {
local out_file err_file
out_file="$(mktemp)"
err_file="$(mktemp)"
if "$@" >"${out_file}" 2>"${err_file}"; then
cat "${out_file}"
rm -f "${out_file}" "${err_file}"
return 0
fi
if command -v sudo >/dev/null 2>&1; then
if sudo "$@" >"${out_file}" 2>"${err_file}"; then
cat "${out_file}"
rm -f "${out_file}" "${err_file}"
return 0
fi
fi
cat "${err_file}" >&2 || true
rm -f "${out_file}" "${err_file}"
return 1
}
json_get() {
local json_input="$1"
local path="$2"
python3 - "$path" "$json_input" <<'PY'
import json
import sys
path = sys.argv[1].split('.')
obj = json.loads(sys.argv[2])
cur = obj
for p in path:
if isinstance(cur, dict) and p in cur:
cur = cur[p]
else:
print("n/a")
raise SystemExit(0)
if isinstance(cur, (dict, list)):
print(json.dumps(cur, separators=(",", ":")))
else:
print(cur)
PY
}
first_connected_peer() {
local json_input="$1"
python3 - "$json_input" <<'PY'
import json
import sys
obj = json.loads(sys.argv[1])
peers = obj.get("peers", [])
connected = [p for p in peers if p.get("connectivity") == "connected"]
if not connected:
print("none")
raise SystemExit(0)
p = connected[0]
name = p.get("display_name") or p.get("npub") or "unknown"
addr = p.get("transport_addr") or "n/a"
print(f"{name} @ {addr}")
PY
}
echo "==> Checking local FIPS service status"
if command -v systemctl >/dev/null 2>&1; then
if ! systemctl is-active --quiet fips.service; then
echo "Error: fips.service is not active." >&2
echo "Start it with: sudo systemctl start fips" >&2
exit 1
fi
else
echo "Warning: systemctl not found; skipping service-state check."
fi
if ! command -v fips >/dev/null 2>&1; then
echo "Error: fips binary not found in PATH." >&2
exit 1
fi
if ! command -v fipsctl >/dev/null 2>&1; then
echo "Error: fipsctl binary not found in PATH." >&2
exit 1
fi
FIPS_VERSION="$(fips --version | head -n1)"
FIPSCTL_VERSION="$(fipsctl --version | head -n1)"
STATUS_JSON="$(get_cmd_output fipsctl show status)"
PEERS_JSON="$(get_cmd_output fipsctl show peers)"
TUN_STATE="$(json_get "${STATUS_JSON}" tun_state)"
TUN_NAME="$(json_get "${STATUS_JSON}" tun_name)"
if [[ "${TUN_NAME}" == "n/a" || -z "${TUN_NAME}" ]]; then
TUN_NAME="fips0"
fi
if grep -Eq '^[[:space:]]*nameserver[[:space:]]+127\.0\.0\.1([[:space:]]|$)' /etc/resolv.conf 2>/dev/null; then
RESOLV_127_STATUS="present"
else
RESOLV_127_STATUS="missing"
fi
if [[ "${TUN_STATE}" != "active" ]]; then
echo "Error: expected tun_state=active, got ${TUN_STATE}." >&2
exit 1
fi
if ! ip -o link show dev "${TUN_NAME}" >/dev/null 2>&1; then
echo "Error: expected TUN interface ${TUN_NAME} to exist." >&2
exit 1
fi
FD00_ROUTE_LINE="$(ip -6 route show fd00::/8 2>/dev/null | head -n1 || true)"
if [[ -z "${FD00_ROUTE_LINE}" ]]; then
echo "Error: missing fd00::/8 route." >&2
exit 1
fi
if [[ "${FD00_ROUTE_LINE}" != *"dev ${TUN_NAME}"* ]]; then
echo "Error: fd00::/8 route is not installed via ${TUN_NAME}: ${FD00_ROUTE_LINE}" >&2
exit 1
fi
if [[ "${RESOLV_127_STATUS}" == "missing" ]]; then
echo "Warning: /etc/resolv.conf does not contain nameserver 127.0.0.1; .fips DNS may fail in some environments." >&2
fi
echo "==> Testing .fips URL reachability"
TMP_BODY="$(mktemp)"
trap 'rm -f "${TMP_BODY}"' EXIT
HTTP_CODE="$(curl -sS --max-time "${CURL_TIMEOUT}" -o "${TMP_BODY}" -w '%{http_code}' "${TEST_URL}")"
BYTES="$(wc -c < "${TMP_BODY}" | tr -d '[:space:]')"
if [[ "${HTTP_CODE}" != "200" ]]; then
echo "Error: expected HTTP 200, got ${HTTP_CODE}." >&2
exit 1
fi
if (( BYTES < MIN_BYTES )); then
echo "Error: response too small (${BYTES} bytes, expected at least ${MIN_BYTES})." >&2
exit 1
fi
echo ""
echo "FIPS health summary (10 key metrics)"
echo "1) fips_version: ${FIPS_VERSION}"
echo "2) fipsctl_version: ${FIPSCTL_VERSION}"
echo "3) node_state: $(json_get "${STATUS_JSON}" state)"
echo "4) uptime_secs: $(json_get "${STATUS_JSON}" uptime_secs)"
echo "5) npub: $(json_get "${STATUS_JSON}" npub)"
echo "6) ipv6_addr: $(json_get "${STATUS_JSON}" ipv6_addr)"
echo "7) peer_count: $(json_get "${STATUS_JSON}" peer_count)"
echo "8) link_count: $(json_get "${STATUS_JSON}" link_count)"
echo "9) session_count: $(json_get "${STATUS_JSON}" session_count)"
echo "10) connected_peer_example: $(first_connected_peer "${PEERS_JSON}")"
echo "11) tun_state: ${TUN_STATE}"
echo "12) tun_name: ${TUN_NAME}"
echo "13) fd00_route: ${FD00_ROUTE_LINE}"
echo "14) resolv_conf_nameserver_127.0.0.1: ${RESOLV_127_STATUS}"
echo ""
echo "URL test: HTTP=${HTTP_CODE}, bytes=${BYTES}"