#!/usr/bin/env bash
###############################################################################
# firewall_proxy.sh — Proxy (244939) · 10.69.69.3
# 3 WG tunnels · firewalld · default zone: drop
# Web-facing: 80/tcp, 443/tcp on public
# Idempotent — safe to re-run at any time.
###############################################################################
set -euo pipefail

readonly SCRIPT_NAME="firewall_proxy"
readonly LOG_TAG="[${SCRIPT_NAME}]"
readonly TIMESTAMP_FMT="+%Y-%m-%dT%H:%M:%S%z"

# ── Logging helpers ─────────────────────────────────────────────────────────
log()  { printf '%s %s %s\n' "$(date "${TIMESTAMP_FMT}")" "${LOG_TAG}" "$*"; }
warn() { log "WARN: $*" >&2; }
die()  { log "FATAL: $*" >&2; exit 1; }
trap 'die "Unexpected error on line ${LINENO}"' ERR

# ── Pre-flight checks ──────────────────────────────────────────────────────
[[ $(id -u) -eq 0 ]] || die "Must run as root"
command -v firewall-cmd >/dev/null 2>&1 || die "firewalld not installed"
systemctl is-active --quiet firewalld    || die "firewalld is not running"

log "Starting Proxy firewall configuration"

# ── Helpers ─────────────────────────────────────────────────────────────────
ensure_zone() {
    local zone="$1"
    if ! firewall-cmd --permanent --get-zones | grep -qw "${zone}"; then
        log "Creating zone: ${zone}"
        firewall-cmd --permanent --new-zone="${zone}"
    else
        log "Zone already exists: ${zone}"
    fi
}

ensure_port() {
    local zone="$1" port="$2"
    if ! firewall-cmd --permanent --zone="${zone}" --query-port="${port}" 2>/dev/null; then
        log "Adding port ${port} to zone ${zone}"
        firewall-cmd --permanent --zone="${zone}" --add-port="${port}"
    else
        log "Port ${port} already in zone ${zone}"
    fi
}

ensure_source() {
    local zone="$1" src="$2"
    if ! firewall-cmd --permanent --zone="${zone}" --query-source="${src}" 2>/dev/null; then
        log "Adding source ${src} to zone ${zone}"
        firewall-cmd --permanent --zone="${zone}" --add-source="${src}"
    else
        log "Source ${src} already in zone ${zone}"
    fi
}

ensure_interface() {
    local zone="$1" iface="$2"
    if ! firewall-cmd --permanent --zone="${zone}" --query-interface="${iface}" 2>/dev/null; then
        log "Binding interface ${iface} to zone ${zone}"
        firewall-cmd --permanent --zone="${zone}" --add-interface="${iface}"
    else
        log "Interface ${iface} already bound to zone ${zone}"
    fi
}

remove_port() {
    local zone="$1" port="$2"
    if firewall-cmd --permanent --zone="${zone}" --query-port="${port}" 2>/dev/null; then
        log "Removing stale port ${port} from zone ${zone}"
        firewall-cmd --permanent --zone="${zone}" --remove-port="${port}"
    fi
}

remove_rich_rule_matching() {
    local zone="$1" pattern="$2"
    firewall-cmd --permanent --zone="${zone}" --list-rich-rules 2>/dev/null | while IFS= read -r rule; do
        if echo "${rule}" | grep -q "${pattern}"; then
            log "Removing stale rich rule from ${zone}: ${rule}"
            firewall-cmd --permanent --zone="${zone}" --remove-rich-rule="${rule}" || true
        fi
    done
}

###############################################################################
# 1. Default zone → drop
###############################################################################
log "Setting default zone to drop"
firewall-cmd --set-default-zone=drop

###############################################################################
# 2. Remove stale ports and rules
###############################################################################
log "Cleaning stale ports from public zone"
remove_port "public" "30222/tcp"
remove_port "public" "33022/tcp"
remove_port "public" "39847/udp"
remove_port "public" "40153/udp"
remove_port "public" "49616/udp"

log "Cleaning stale 33022 rich rules from all zones"
for z in $(firewall-cmd --get-zones); do
    remove_rich_rule_matching "${z}" "33022"
done

###############################################################################
# 3. Public zone — web traffic + tunnel establishment
###############################################################################
log "Configuring public zone for web + tunnel traffic"
ensure_port "public" "443/tcp"
ensure_port "public" "80/tcp"

PROXY_PUBLIC_UDP=(44634 42783 47417)
for port in "${PROXY_PUBLIC_UDP[@]}"; do
    ensure_port "public" "${port}/udp"
done

###############################################################################
# 4. zone-mesh (wg7) — WireGuard mesh: SSH 9922/tcp
###############################################################################
ensure_zone "zone-mesh"
ensure_interface "zone-mesh" "wg7"
ensure_source "zone-mesh" "10.69.69.0/24"
ensure_port "zone-mesh" "9922/tcp"

###############################################################################
# 5. zone-comp (compass) — compass overlay
###############################################################################
ensure_zone "zone-comp"
ensure_interface "zone-comp" "compass"
ensure_source "zone-comp" "172.28.47.0/28"

###############################################################################
# 6. zone-shale (shale) — 80/tcp
###############################################################################
ensure_zone "zone-shale"
ensure_interface "zone-shale" "shale"
ensure_source "zone-shale" "255.17.69.0/30"
ensure_port "zone-shale" "80/tcp"

###############################################################################
# 7. Reload & verify
###############################################################################
log "Reloading firewalld"
firewall-cmd --reload

log "═══════════════════════════════════════════════════════════"
log "Proxy firewall configuration complete"
log "Default zone: $(firewall-cmd --get-default-zone)"
log "═══════════════════════════════════════════════════════════"

log "Active zones:"
firewall-cmd --get-active-zones

for z in zone-mesh zone-comp zone-shale public; do
    log "--- Zone: ${z} ---"
    firewall-cmd --zone="${z}" --list-all 2>/dev/null || log "  (zone ${z} not active)"
done

log "Proxy firewall script finished successfully"
