#!/usr/bin/env bash
# =============================================================================
# audit-netboot.sh
# -----------------------------------------------------------------------------
# READ-ONLY audit of the reference node "pfv-netboot".
#
# Purpose: gather enough information to replicate its Pi-hole, Technitium DNS,
# and NTP services onto pfv-netinfra-01 and pfv-netinfra-02.
#
# Guarantees:
#   * NO writes, NO installs, NO service restarts, NO network changes.
#   * Every command below is read-only (status, cat, ls, ss, ps, sqlite3 SELECT).
#
# Intended to be run as the "localuser" account on pfv-netboot:
#
#     ssh localuser@pfv-netboot 'bash -s' < audit-netboot.sh > netboot-audit.txt
#
# or, if sudo is needed for a few reads, the script will try `sudo -n` for
# specific files that are normally root-readable only. It will NEVER use sudo
# to write or modify anything.
# =============================================================================

set -u
AUDIT_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"

# Helper: print a clearly delimited section header.
section() {
    printf '\n========================================================================\n'
    printf 'SECTION: %s\n' "$1"
    printf '========================================================================\n'
}

# Helper: read a file with sudo if needed, silently skip if missing.
read_file() {
    local path="$1"
    if [ -r "$path" ]; then
        printf '--- %s (uid-readable) ---\n' "$path"
        cat "$path" 2>/dev/null
    elif sudo -n true 2>/dev/null; then
        if sudo -n test -e "$path"; then
            printf '--- %s (via sudo -n) ---\n' "$path"
            sudo -n cat "$path" 2>/dev/null
        else
            printf '--- %s : NOT FOUND ---\n' "$path"
        fi
    else
        printf '--- %s : NOT READABLE (no passwordless sudo) ---\n' "$path"
    fi
    printf '\n'
}

list_dir() {
    local path="$1"
    printf '--- ls -la %s ---\n' "$path"
    ls -la "$path" 2>/dev/null || sudo -n ls -la "$path" 2>/dev/null || printf '(cannot list %s)\n' "$path"
    printf '\n'
}

printf '##### AUDIT START %s #####\n' "$AUDIT_DATE"
printf 'Audit host: %s\n' "$(hostname -f 2>/dev/null || hostname)"
printf 'Audit user: %s\n' "$(id -un 2>/dev/null)"
printf 'Script:     audit-netboot.sh (READ-ONLY)\n'

# -----------------------------------------------------------------------------
# 1. System basics
# -----------------------------------------------------------------------------
section "1. SYSTEM BASICS"
echo "-- uname --"; uname -a
echo "-- /etc/os-release --"; cat /etc/os-release 2>/dev/null
echo "-- uptime --"; uptime
echo "-- timezone --"; timedatectl 2>/dev/null || cat /etc/timezone 2>/dev/null || date
echo "-- arch --"; dpkg --print-architecture 2>/dev/null || uname -m
echo "-- memory --"; free -h 2>/dev/null
echo "-- disk --"; df -h / 2>/dev/null
echo "-- cpu count --"; nproc 2>/dev/null

# -----------------------------------------------------------------------------
# 2. Network configuration
# -----------------------------------------------------------------------------
section "2. NETWORK"
echo "-- hostname --"; hostname; hostname -f 2>/dev/null; hostname -I 2>/dev/null
echo "-- ip addr --"; ip -br addr 2>/dev/null; echo; ip addr 2>/dev/null
echo "-- default route --"; ip route 2>/dev/null
echo "-- /etc/resolv.conf --"; cat /etc/resolv.conf 2>/dev/null
echo "-- /etc/hosts --"; cat /etc/hosts 2>/dev/null
echo "-- listening TCP/UDP sockets --"
ss -tlnup 2>/dev/null || sudo -n ss -tlnup 2>/dev/null
echo "-- /etc/network/interfaces --"; cat /etc/network/interfaces 2>/dev/null
echo "-- netplan --"; ls -la /etc/netplan/ 2>/dev/null; for f in /etc/netplan/*.yaml; do [ -e "$f" ] && { echo "--- $f ---"; cat "$f"; }; done 2>/dev/null
echo "-- systemd-networkd --"; ls -la /etc/systemd/network/ 2>/dev/null; networkctl status 2>/dev/null | head -40

# -----------------------------------------------------------------------------
# 3. DNS / DHCP / NTP related systemd units
# -----------------------------------------------------------------------------
section "3. RELEVANT SYSTEMD UNITS"
echo "-- all units matching dns|pihole|dnsmasq|technitium|ftl|ntp|chrony|timesync --"
systemctl list-units --type=service --all --no-pager 2>/dev/null \
    | grep -Ei 'pihole|dnsmasq|ftl|technitium|dns|ntp|chrony|timesync|resolv|resolved' || true
echo "-- unit files (enabled state) --"
systemctl list-unit-files --no-pager 2>/dev/null \
    | grep -Ei 'pihole|dnsmasq|ftl|technitium|dns|ntp|chrony|timesync|resolv|resolved' || true
echo "-- installed packages of interest --"
dpkg -l 2>/dev/null | grep -Ei 'pihole|dnsmasq|ftl|technitium|ntp|chrony|timesync|unbound|resolved|resolvconf' || true

# -----------------------------------------------------------------------------
# 4. NTP service details
# -----------------------------------------------------------------------------
section "4. NTP"
echo "-- chrony --"
systemctl status chrony --no-pager 2>/dev/null | head -15 || echo "(no chrony unit)"
read_file /etc/chrony/chrony.conf
echo "-- chronyc sources/stats (if available) --"
chronyc -n sources 2>/dev/null || sudo -n chronyc -n sources 2>/dev/null || true
chronyc -n tracking 2>/dev/null || sudo -n chronyc -n tracking 2>/dev/null || true

echo "-- ntpsec / ntp classic --"
systemctl status ntp --no-pager 2>/dev/null | head -15 || echo "(no ntp unit)"
systemctl status ntpsec --no-pager 2>/dev/null | head -15 || true
read_file /etc/ntp.conf
read_file /etc/ntpsec/ntp.conf

echo "-- systemd-timesyncd --"
systemctl status systemd-timesyncd --no-pager 2>/dev/null | head -15 || echo "(no timesyncd)"
read_file /etc/systemd/timesyncd.conf

echo "-- openntpd --"
systemctl status openntpd --no-pager 2>/dev/null | head -15 || true
read_file /etc/openntpd/ntpd.conf

# -----------------------------------------------------------------------------
# 5. Docker (Pi-hole and/or Technitium may be containerized)
# -----------------------------------------------------------------------------
section "5. DOCKER"
if command -v docker >/dev/null 2>&1; then
    echo "-- docker version --"; docker version 2>/dev/null || sudo -n docker version 2>/dev/null || true
    echo "-- containers (running) --"; docker ps 2>/dev/null || sudo -n docker ps 2>/dev/null || true
    echo "-- containers (all) --"; docker ps -a 2>/dev/null || sudo -n docker ps -a 2>/dev/null || true
    echo "-- images --"; docker images 2>/dev/null || sudo -n docker images 2>/dev/null || true
    echo "-- volumes --"; docker volume ls 2>/dev/null || sudo -n docker volume ls 2>/dev/null || true
    echo "-- networks --"; docker network ls 2>/dev/null || sudo -n docker network ls 2>/dev/null || true
else
    echo "(docker not installed / not on PATH)"
fi
echo "-- compose files in common locations --"
for d in /etc/docker-compose /opt/docker-compose /root/docker-compose /home/localuser/docker-compose /srv/docker-compose /opt/pihole /opt/technitium /opt; do
    if sudo -n test -d "$d" 2>/dev/null || [ -d "$d" ]; then
        echo "### $d ###"
        sudo -n ls -la "$d" 2>/dev/null || ls -la "$d" 2>/dev/null || true
        for f in docker-compose.yml docker-compose.yaml compose.yml compose.yaml; do
            if sudo -n test -f "$d/$f" 2>/dev/null; then
                read_file "$d/$f"
            elif [ -f "$d/$f" ]; then
                read_file "$d/$f"
            fi
        done
    fi
done

# -----------------------------------------------------------------------------
# 6. Pi-hole
# -----------------------------------------------------------------------------
section "6. PI-HOLE"
if command -v pihole >/dev/null 2>&1; then
    echo "-- pihole version --"; pihole -v 2>/dev/null || sudo -n pihole -v 2>/dev/null || true
    echo "-- pihole status --"; pihole status 2>/dev/null || sudo -n pihole status 2>/dev/null || true
else
    echo "(pihole command not on PATH)"
fi

echo "-- /etc/pihole listing --"
list_dir /etc/pihole

# Key Pi-hole config files
for f in \
    /etc/pihole/setupVars.conf \
    /etc/pihole/pihole-FTL.conf \
    /etc/pihole/adlists.list \
    /etc/pihole/whitelist.txt \
    /etc/pihole/blacklist.txt \
    /etc/pihole/regex.list \
    /etc/pihole/custom.list \
    /etc/pihole/local.list \
    /etc/pihole/hostnameMappings.txt \
    /etc/pihole/dhcp.leases \
    /etc/pihole/static_ip.conf \
    /etc/pihole/GitHubVersions \
    /etc/pihole/macvendor.db ; do
    read_file "$f"
done

echo "-- /etc/pihole/*.conf (all) --"
for f in /etc/pihole/*.conf; do [ -e "$f" ] && read_file "$f"; done 2>/dev/null

echo "-- /etc/dnsmasq.d listing --"
list_dir /etc/dnsmasq.d
for f in /etc/dnsmasq.d/*; do [ -e "$f" ] && read_file "$f"; done 2>/dev/null

echo "-- /etc/dnsmasq.conf (if present) --"
read_file /etc/dnsmasq.conf

echo "-- gravity.db schema + row counts (Pi-hole v5+) --"
GRAVITY=""
for g in /etc/pihole/gravity.db /etc/pihole/gravity.db.*; do
    if [ -e "$g" ]; then GRAVITY="$g"; break; fi
done
if [ -n "${GRAVITY:-}" ]; then
    echo "gravity.db = $GRAVITY"
    if command -v sqlite3 >/dev/null 2>&1; then
        sqlite3 -readonly "$GRAVITY" ".tables" 2>/dev/null || sudo -n sqlite3 -readonly "$GRAVITY" ".tables" 2>/dev/null || true
        for tbl in adlist adlist_by_group domainlist domainlist_by_group client client_by_group group info; do
            cnt=$(sqlite3 -readonly "$GRAVITY" "SELECT COUNT(*) FROM $tbl;" 2>/dev/null || sudo -n sqlite3 -readonly "$GRAVITY" "SELECT COUNT(*) FROM $tbl;" 2>/dev/null || echo "n/a")
            printf 'gravity.%s count = %s\n' "$tbl" "$cnt"
        done
        echo "-- adlist entries (url, enabled, comment) --"
        sqlite3 -readonly "$GRAVITY" "SELECT id,address,enabled,comment FROM adlist;" 2>/dev/null \
            || sudo -n sqlite3 -readonly "$GRAVITY" "SELECT id,address,enabled,comment FROM adlist;" 2>/dev/null || true
        echo "-- domainlist sample (first 50) --"
        sqlite3 -readonly "$GRAVITY" "SELECT id,type,domain,enabled,comment FROM domainlist LIMIT 50;" 2>/dev/null \
            || sudo -n sqlite3 -readonly "$GRAVITY" "SELECT id,type,domain,enabled,comment FROM domainlist LIMIT 50;" 2>/dev/null || true
        echo "-- client list --"
        sqlite3 -readonly "$GRAVITY" "SELECT id,ip,comment FROM client;" 2>/dev/null \
            || sudo -n sqlite3 -readonly "$GRAVITY" "SELECT id,ip,comment FROM client;" 2>/dev/null || true
        echo "-- group list --"
        sqlite3 -readonly "$GRAVITY" "SELECT id,name,enabled,comment FROM 'group';" 2>/dev/null \
            || sudo -n sqlite3 -readonly "$GRAVITY" "SELECT id,name,enabled,comment FROM 'group';" 2>/dev/null || true
        echo "-- info table --"
        sqlite3 -readonly "$GRAVITY" "SELECT * FROM info;" 2>/dev/null \
            || sudo -n sqlite3 -readonly "$GRAVITY" "SELECT * FROM info;" 2>/dev/null || true
    else
        echo "(sqlite3 not installed; gravity.db present at $GRAVITY)"
    fi
else
    echo "(no gravity.db found)"
fi

echo "-- lighttpd / pihole web admin --"
systemctl status lighttpd --no-pager 2>/dev/null | head -15 || true
read_file /etc/lighttpd/lighttpd.conf
for f in /etc/lighttpd/conf-enabled/*; do [ -e "$f" ] && read_file "$f"; done 2>/dev/null

echo "-- pihole-FTL service --"
systemctl status pihole-FTL --no-pager 2>/dev/null | head -20 || true

# -----------------------------------------------------------------------------
# 7. Technitium DNS
# -----------------------------------------------------------------------------
section "7. TECHNITIUM DNS"
echo "-- technitium systemd unit --"
systemctl status technitium-dns --no-pager 2>/dev/null | head -20 || echo "(no technitium-dns unit)"
echo "-- any unit containing technitium --"
systemctl list-units --all --no-pager 2>/dev/null | grep -i technitium || true
echo "-- unit file path --"
sudo -n systemctl cat technitium-dns 2>/dev/null || systemctl cat technitium-dns 2>/dev/null || true

# Technitium common install locations
for d in /etc/technitium /etc/technitium/dns /opt/technitium /opt/technitium/dns /var/lib/technitium /usr/local/technitium; do
    echo "### checking $d ###"
    if sudo -n test -d "$d" 2>/dev/null || [ -d "$d" ]; then
        list_dir "$d"
        # recurse one level for config files
        for sub in "$d" "$d"/*; do
            [ -e "$sub" ] || continue
            if [ -f "$sub" ] && echo "$sub" | grep -Eq '\.(xml|json|conf|config|txt)$'; then
                read_file "$sub"
            fi
        done
    fi
done

echo "-- technitium config.xml / dnsServer.conf (search) --"
sudo -n find /etc/technitium /opt/technitium /var/lib/technitium -maxdepth 4 \
    \( -name 'config.xml' -o -name '*.config' -o -name 'dnsServer.conf' -o -name 'blockList.txt' \) \
    -print 2>/dev/null || true

# -----------------------------------------------------------------------------
# 8. Firewall / SELinux / misc
# -----------------------------------------------------------------------------
section "8. FIREWALL & MISC"
echo "-- nftables --"; sudo -n nft list ruleset 2>/dev/null | head -80 || true
echo "-- iptables --"; sudo -n iptables -S 2>/dev/null | head -40 || true
echo "-- ufw --"; sudo -n ufw status verbose 2>/dev/null || true
echo "-- firewalld --"; systemctl status firewalld --no-pager 2>/dev/null | head -8 || true
echo "-- selinux/apparmor --"; getenforce 2>/dev/null || echo "(SELinux not present)"; aa-status 2>/dev/null | head -5 || true

# -----------------------------------------------------------------------------
# 9. Cron / timers that maintain these services
# -----------------------------------------------------------------------------
section "9. CRON & TIMERS"
echo "-- root crontab --"; sudo -n crontab -l 2>/dev/null || echo "(n/a)"
echo "-- localuser crontab --"; crontab -l 2>/dev/null || echo "(none)"
echo "-- /etc/cron.d --"; ls -la /etc/cron.d 2>/dev/null
for f in /etc/cron.d/*pihole* /etc/cron.d/*technitium* /etc/cron.d/*gravity*; do
    [ -e "$f" ] && read_file "$f"
done 2>/dev/null
echo "-- pihole timer --"; systemctl list-timers --all --no-pager 2>/dev/null | grep -Ei 'pihole|gravity|technitium' || true

printf '\n##### AUDIT END %s #####\n' "$AUDIT_DATE"
