#!/usr/bin/env bash set -euo pipefail HOST_IP="${HOST_IP:-192.168.178.58}" FRITZBOX_URL="${FRITZBOX_URL:-http://192.168.178.1:49000/tr64desc.xml}" BORG_DB="${BORG_DB:-/mnt/user/appdata/borg-ui/data/borg.db}" REPO_ROOT="${REPO_ROOT:-/mnt/user/services/homelab-infra}" section() { printf '\n## %s\n\n' "$1" } section "FRITZBox" if fritz_xml="$(curl -fsS --max-time 5 "$FRITZBOX_URL")"; then printf '%s\n' "$fritz_xml" | grep -E '||' | sed -E 's/^[[:space:]]+//' else echo "FRITZBox TR-064 descriptor not reachable at $FRITZBOX_URL" fi if ipv6_fw="$( curl -fsS --max-time 5 \ -H 'Content-Type: text/xml; charset="utf-8"' \ -H 'SOAPACTION: "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1#GetFirewallStatus"' \ --data '' \ http://192.168.178.1:49000/igd2upnp/control/WANIPv6Firewall1 )"; then firewall_enabled="$(printf '%s\n' "$ipv6_fw" | sed -n 's:.*\(.*\).*:\1:p')" pinhole_allowed="$(printf '%s\n' "$ipv6_fw" | sed -n 's:.*\(.*\).*:\1:p')" echo "IPv6 FirewallEnabled: ${firewall_enabled:-unknown}" echo "IPv6 InboundPinholeAllowed: ${pinhole_allowed:-unknown}" else echo "FRITZBox IPv6 firewall status not reachable via TR-064." fi section "Host IPv6" global_ipv6="$( ip -6 addr show scope global \ | awk '/inet6 / {print $2}' \ | grep -Ev '^(fd|fe80:)' || true )" if [[ -n "$global_ipv6" ]]; then echo "Provider/global IPv6 addresses present:" printf '%s\n' "$global_ipv6" else echo "No provider/global IPv6 address on host; only ULA/link-local/Tailscale may be present." fi tailscale ip -4 2>/dev/null | sed 's/^/Tailscale IPv4: /' || true tailscale ip -6 2>/dev/null | sed 's/^/Tailscale IPv6: /' || true section "DNS" for name in \ kaleschke.info \ vault.kaleschke.info \ git.kaleschke.info \ cloud.kaleschke.info \ traefik.kaleschke.info; do echo "$name" dig +short @1.1.1.1 "$name" A | sed 's/^/ public A /' || true dig +short @1.1.1.1 "$name" AAAA | sed 's/^/ public AAAA /' || true done section "Host Listeners" ss -ltnp | awk ' /:(80|443|222|53|8082|8181)[[:space:]]/ || /100\.80\.98\.33:8082/ || /127\.0\.0\.1:8181/ {print} ' | sort -k4 section "External Port Smoke" public_ipv4="$(curl -4 -fsS --max-time 5 https://ifconfig.co 2>/dev/null || true)" if [[ -z "$public_ipv4" ]]; then public_ipv4="$(dig +short @1.1.1.1 kaleschke.info A | tail -n 1)" fi for check in \ "$public_ipv4 443 expected-open" \ "$public_ipv4 80 expected-closed" \ "$public_ipv4 222 expected-closed"; do set -- $check target="$1" port="$2" expected="$3" if timeout 5 bash -c "cat < /dev/null > /dev/tcp/$target/$port" 2>/dev/null; then result="open" else result="closed" fi printf '%s:%s %s (%s)\n' "$target" "$port" "$result" "$expected" done section "Borg UI Repository" if [[ -f "$BORG_DB" ]]; then sqlite3 -header -csv "$BORG_DB" \ "select name,repository_type,path,remote_path,last_backup,last_check,borg_version,custom_flags from repositories order by id;" sqlite3 -header -csv "$BORG_DB" \ "select id,repository,status,archive_name,started_at,completed_at,nfiles from backup_jobs order by id desc limit 3;" else echo "Borg UI database not found: $BORG_DB" fi section "Restore Freshness" if [[ -x "$REPO_ROOT/ops/restore-tests/run-restore-checks.sh" ]]; then "$REPO_ROOT/ops/restore-tests/run-restore-checks.sh" freshness else echo "Restore freshness script not executable: $REPO_ROOT/ops/restore-tests/run-restore-checks.sh" fi