diff options
| author | batsumaru <> | 2026-07-01 16:52:22 +0900 |
|---|---|---|
| committer | batsumaru <> | 2026-07-01 16:52:22 +0900 |
| commit | a034c6724381b172ba4b6d36357682c44f18b8de (patch) | |
| tree | acb122f89c9432d56f3964c9a29d99ee1cf8647e /statuspage | |
| parent | bb3567aa4bd5d03fcd0fa74eea42381f159227b0 (diff) | |
Add pf visibility and a wg-quick watcher check, add a neutral row status
checks/pf.sh reports pf enabled/disabled, state table usage (warn/down
as it nears the configured limit), and the loaded filter/nat rule
count, then lists each active rule as its own row for at-a-glance
visibility into what's actually being enforced.
Those rule rows use a new "info" status (gray square) rather than
"ok" - they're not a health check on any individual rule, so a green
square there would misleadingly imply otherwise. render.sh maps
info -> gray; anything else still falls back to red.
checks/wg-watcher.sh checks the route-monitor process wg-quick spawns
to react to WAN interface/address changes - it isn't rc.d-managed, so
there's no `service status` for it, hence the new proc_running helper
in lib/common.sh (pgrep -f based).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'statuspage')
| -rw-r--r-- | statuspage/README.md | 2 | ||||
| -rwxr-xr-x | statuspage/checks/pf.sh | 49 | ||||
| -rwxr-xr-x | statuspage/checks/wg-watcher.sh | 14 | ||||
| -rwxr-xr-x | statuspage/lib/common.sh | 8 | ||||
| -rwxr-xr-x | statuspage/render.sh | 2 |
5 files changed, 74 insertions, 1 deletions
diff --git a/statuspage/README.md b/statuspage/README.md index 3b83a81..e77991a 100644 --- a/statuspage/README.md +++ b/statuspage/README.md @@ -36,7 +36,7 @@ Each JSON object has exactly these fields: | `section` | groups rows under a heading: `hardware`, `host services`, `jails` (or a new section name - unrecognized sections are rendered after the known ones, in the order first seen) | | `label` | display name for the row | | `value` | display value; use `""` for a plain up/down check with no value | -| `status` | one of `ok`, `warn`, `down` - maps to a green/yellow/red square | +| `status` | one of `ok`, `warn`, `down` (green/yellow/red), or `info` (gray) for a row that isn't a health signal at all - e.g. `pf.sh` lists loaded rules as `info` rather than implying each rule is itself being checked | Example (`checks/wireguard.sh`): diff --git a/statuspage/checks/pf.sh b/statuspage/checks/pf.sh new file mode 100755 index 0000000..47b2acd --- /dev/null +++ b/statuspage/checks/pf.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# checks/pf.sh +# pf health summary (enabled, state table usage, rule count), plus the +# actual active filter and nat/rdr rules listed as rows below. The rule +# rows use status "info" (a neutral gray square) rather than "ok" - +# they're informational, not a health signal, and a green square there +# would wrongly imply each individual rule was itself being health- +# checked. +set -eu + +DIR=$(dirname "$0") +. "$DIR/../lib/common.sh" + +INFO=$(pfctl -si 2>/dev/null) || INFO="" + +ENABLED=$(printf '%s\n' "$INFO" | awk -F'[ :]+' '/^Status:/{print $2; exit}') +if [ "$ENABLED" = "Enabled" ]; then + json_line "pf" "pf" "" "ok" +else + json_line "pf" "pf" "${ENABLED:-unknown}" "down" +fi + +CURRENT=$(printf '%s\n' "$INFO" | awk '/current entries/{print $NF; exit}') +LIMIT=$(pfctl -sm 2>/dev/null | awk '/^states/{print $NF; exit}') + +if [ -n "$CURRENT" ] && [ -n "$LIMIT" ] && [ "$LIMIT" -gt 0 ] 2>/dev/null; then + PCT=$((CURRENT * 100 / LIMIT)) + if [ "$PCT" -ge 90 ]; then + SSTATUS=down + elif [ "$PCT" -ge 75 ]; then + SSTATUS=warn + else + SSTATUS=ok + fi + json_line "pf" "state table" "${CURRENT}/${LIMIT} (${PCT}%)" "$SSTATUS" +fi + +RULE_COUNT=$(pfctl -sr 2>/dev/null | grep -c .) || RULE_COUNT=0 +json_line "pf" "filter rules loaded" "$RULE_COUNT" "ok" + +pfctl -sr 2>/dev/null | while IFS= read -r rule; do + [ -n "$rule" ] || continue + json_line "pf" " $rule" "" "info" +done + +pfctl -sn 2>/dev/null | while IFS= read -r rule; do + [ -n "$rule" ] || continue + json_line "pf" " nat: $rule" "" "info" +done diff --git a/statuspage/checks/wg-watcher.sh b/statuspage/checks/wg-watcher.sh new file mode 100755 index 0000000..9351afd --- /dev/null +++ b/statuspage/checks/wg-watcher.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# checks/wg-watcher.sh +# wg-quick's background route monitor (spawned by `wg-quick up wg0` to +# react to WAN interface/address changes) isn't rc.d-managed, so there's +# no `service ... status` for it. If it dies, wg0 itself stays up - the +# kernel interface doesn't depend on it - but the box stops reacting to +# WAN IP changes (e.g. a DHCP lease renewal) until wg-quick is restarted. +set -eu + +DIR=$(dirname "$0") +. "$DIR/../lib/common.sh" + +STATUS=$(proc_running "route -n monitor") +json_line "host services" "wg-quick watcher" "" "$STATUS" diff --git a/statuspage/lib/common.sh b/statuspage/lib/common.sh index d063e07..dcc26f5 100755 --- a/statuspage/lib/common.sh +++ b/statuspage/lib/common.sh @@ -47,3 +47,11 @@ port_check() { jail_status() { jls -j "$1" >/dev/null 2>&1 && echo "ok" || echo "down" } + +# proc_running PATTERN +# Prints "ok" or "down" depending on whether any process's command line +# matches PATTERN (pgrep -f). For ad-hoc background processes that +# aren't rc.d-managed, so there's no `service ... status` for them. +proc_running() { + pgrep -f "$1" >/dev/null 2>&1 && echo "ok" || echo "down" +} diff --git a/statuspage/render.sh b/statuspage/render.sh index 22df5e7..a5602f0 100755 --- a/statuspage/render.sh +++ b/statuspage/render.sh @@ -85,6 +85,7 @@ function htmlesc(s) { function sqclass(status) { if (status == "ok") return "green" if (status == "warn") return "yellow" + if (status == "info") return "gray" return "red" } @@ -128,6 +129,7 @@ END { print ".green { background:#3c3; }" print ".yellow { background:#cc3; }" print ".red { background:#c33; }" + print ".gray { background:#666; }" print ".dim { color:#888; font-size: 0.85em; }" print "</style>" print "</head>" |
