156 lines
5.1 KiB
Bash
Executable File
156 lines
5.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ==============================================================================
|
|
# nx9-wg Production Diagnostic Collector
|
|
# ==============================================================================
|
|
# PURPOSE:
|
|
# Collects a comprehensive, non-destructive diagnostic snapshot across both
|
|
# desired SQLite state and live Linux kernel networking state:
|
|
# - Systemd service & journal log health
|
|
# - UDP socket bindings & conflict inspection
|
|
# - Kernel IP link, address, and routing status
|
|
# - Kernel WireGuard link/interface and peer telemetry (via secret-safe 'wg show')
|
|
# - Netfilter / nftables ruleset in 'table inet nx9_wg'
|
|
# - Linux sysctl IP packet forwarding
|
|
# - Application-level diagnostic subsystem inspections
|
|
#
|
|
# PREREQUISITES:
|
|
# - Root privileges (recommended for kernel/socket inspection, or run via sudo)
|
|
#
|
|
# SECURITY INVARIANTS:
|
|
# - NEVER calls 'wg showconf' (which prints private keys in cleartext).
|
|
# - Relies exclusively on 'wg show' which masks private keys.
|
|
# - Strictly non-destructive: only performs read-only inspections.
|
|
#
|
|
# USAGE:
|
|
# sudo bash scripts/diagnose.sh
|
|
# ./scripts/diagnose.sh
|
|
# ==============================================================================
|
|
|
|
set -uo pipefail
|
|
|
|
BIN="/usr/local/bin/nx9-wg"
|
|
if [[ ! -x "${BIN}" ]]; then
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
if [[ -x "${ROOT_DIR}/target/release/nx9-wg" ]]; then
|
|
BIN="${ROOT_DIR}/target/release/nx9-wg"
|
|
elif [[ -x "${ROOT_DIR}/target/debug/nx9-wg" ]]; then
|
|
BIN="${ROOT_DIR}/target/debug/nx9-wg"
|
|
fi
|
|
fi
|
|
|
|
section() {
|
|
echo -e "\n================================================================="
|
|
echo -e "\033[1;36m>> $*\033[0m"
|
|
echo -e "================================================================="
|
|
}
|
|
|
|
subsection() {
|
|
echo -e "\n\033[1;33m--- $*\033[0m"
|
|
}
|
|
|
|
section "1. System & Host Runtime Environment"
|
|
echo "Timestamp: $(date --iso-8601=seconds)"
|
|
echo "Hostname: $(hostname)"
|
|
echo "Kernel: $(uname -r)"
|
|
echo "Architecture: $(uname -m)"
|
|
echo "Uptime: $(uptime -p 2>/dev/null || uptime)"
|
|
if [[ -x "${BIN}" ]]; then
|
|
echo "nx9-wg: $("${BIN}" version | head -n 1)"
|
|
else
|
|
echo "nx9-wg: Binary not found"
|
|
fi
|
|
|
|
section "2. Systemd Service & Process State"
|
|
if command -v systemctl >/dev/null 2>&1; then
|
|
subsection "Service Status (nx9-wg.service)"
|
|
systemctl status nx9-wg --no-pager -l || true
|
|
|
|
subsection "Recent Journalctl Logs (Last 30 entries)"
|
|
journalctl -u nx9-wg -n 30 --no-pager || true
|
|
else
|
|
echo "systemctl not available on this host."
|
|
fi
|
|
|
|
section "3. UDP Sockets & Listen Port Inspection"
|
|
if command -v ss >/dev/null 2>&1; then
|
|
subsection "Active UDP Listen Sockets (ss -lunp)"
|
|
ss -lunp 2>/dev/null || true
|
|
else
|
|
echo "ss utility not found."
|
|
fi
|
|
|
|
section "4. Linux Network Interfaces & Addresses"
|
|
if command -v ip >/dev/null 2>&1; then
|
|
subsection "Brief Interface State (ip -br link)"
|
|
ip -br link show || true
|
|
|
|
subsection "Brief IPv4 / IPv6 Addresses (ip -br addr)"
|
|
ip -br addr show || true
|
|
|
|
subsection "WireGuard Interface Addresses"
|
|
if command -v wg >/dev/null 2>&1; then
|
|
WG_INTERFACES="$(wg show interfaces 2>/dev/null || true)"
|
|
if [[ -n "${WG_INTERFACES}" ]]; then
|
|
for WG_IFACE in ${WG_INTERFACES}; do
|
|
echo "Interface: ${WG_IFACE}"
|
|
ip addr show dev "${WG_IFACE}" 2>/dev/null || true
|
|
done
|
|
else
|
|
echo "No WireGuard interfaces reported by the kernel."
|
|
fi
|
|
else
|
|
echo "wg utility not found; WireGuard interface-specific address inspection skipped."
|
|
fi
|
|
else
|
|
echo "ip utility not found."
|
|
fi
|
|
|
|
section "5. Kernel Routing Table"
|
|
if command -v ip >/dev/null 2>&1; then
|
|
subsection "IPv4 Routes (ip route show)"
|
|
ip route show || true
|
|
|
|
subsection "IPv6 Routes (ip -6 route show)"
|
|
ip -6 route show || true
|
|
fi
|
|
|
|
section "6. Kernel WireGuard Telemetry (Secret-Safe 'wg show')"
|
|
if command -v wg >/dev/null 2>&1; then
|
|
wg show 2>&1 || echo "wg show returned non-zero (may require root privileges)."
|
|
else
|
|
echo "wg utility not found on host."
|
|
fi
|
|
|
|
section "7. Netfilter / nftables Firewall State (table inet nx9_wg)"
|
|
if command -v nft >/dev/null 2>&1; then
|
|
nft list table inet nx9_wg 2>/dev/null || echo "nftables table 'inet nx9_wg' not present."
|
|
else
|
|
echo "nft utility not found on host."
|
|
fi
|
|
|
|
section "8. IP Packet Forwarding (Kernel Sysctl)"
|
|
echo -n "net.ipv4.ip_forward: "
|
|
cat /proc/sys/net/ipv4/ip_forward 2>/dev/null || echo "Unable to read /proc/sys/net/ipv4/ip_forward"
|
|
echo -n "net.ipv6.conf.all.forwarding: "
|
|
cat /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || echo "Unable to read /proc/sys/net/ipv6/conf/all/forwarding"
|
|
|
|
section "9. Application Desired State & Health Checks"
|
|
if [[ -x "${BIN}" ]]; then
|
|
subsection "Appliance Health Check"
|
|
"${BIN}" system health 2>&1 || true
|
|
|
|
subsection "All Subsystems Diagnostics"
|
|
"${BIN}" diagnostics all 2>&1 || true
|
|
|
|
subsection "Reconciliation Drift Status"
|
|
"${BIN}" reconcile status 2>&1 || true
|
|
|
|
subsection "Live WireGuard Interface Status"
|
|
"${BIN}" live interface list 2>&1 || true
|
|
else
|
|
echo "nx9-wg binary not executable; skipping application-level diagnostics."
|
|
fi
|
|
|
|
section "Diagnostic Collection Complete"
|