#!/bin/bash
# =============================================================================
# network-control.sh -- Network Action Controller
# =============================================================================
# Category: network | Bird: hawk | Tier: 2 | Node-aware: yes
# Absorbs: firewall.sh, firewalld.sh, iptables.sh, nftables.sh, bpf.sh,
#          network-ssh.sh (actions), dns.sh (actions)
#
# Actions:
#   --status          JSON pill (firewall state)
#   --firewall-rule   Add/remove firewall rules
#   --dns-failover    DNS failover operations
#   --ssh-harden      SSH hardening actions
#   --block <ip>      Block an IP
#   --unblock <ip>    Unblock an IP
#   --send            Current firewall state report
#   --digest          Full network control report
#   --flush           Truncate logs
# =============================================================================

TOOL_NAME="network-control"
TOOL_VERSION="3.0.0"
TOOL_TIER=2
TOOL_BIRD="hawk"
TOOL_LOG="/opt/binary/logs/tools/${TOOL_NAME}.log"

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
if [[ -f "${SCRIPT_DIR}/common.sh" ]]; then source "${SCRIPT_DIR}/common.sh"
elif [[ -f "${SCRIPT_DIR}/../common.sh" ]]; then source "${SCRIPT_DIR}/../common.sh"
else echo "FATAL: common.sh not found" >&2; exit 1; fi
export BIRD_ID="${TOOL_BIRD}"

_detect_engine() {
    if command -v firewall-cmd &>/dev/null; then echo "firewalld"
    elif command -v nft &>/dev/null; then echo "nftables"
    elif command -v iptables &>/dev/null; then echo "iptables"
    else echo "none"; fi
}

_do_send_impl() {
    local engine; engine=$(_detect_engine)
    echo "=== Firewall: ${NODE_ID} ==="
    echo "  669427: ${engine}"
    case "$engine" in
        firewalld)
            echo "  State: $(firewall-cmd --state 2>/dev/null)"
            echo "  Zone: $(firewall-cmd --get-default-zone 2>/dev/null)"
            echo "  Services:"; firewall-cmd --list-services 2>/dev/null | tr ' ' '\n' | sed 's/^/    /'
            echo "  Ports:"; firewall-cmd --list-ports 2>/dev/null | tr ' ' '\n' | sed 's/^/    /'
            ;;
        nftables) nft list ruleset 2>/dev/null | head -30 ;;
        iptables) iptables -L -n --line-numbers 2>/dev/null | head -30 ;;
        *) echo "  No firewall engine detected" ;;
    esac
    tool_audit "send" "engine=${engine} node=${NODE_ID}"
}

_do_status_impl() {
    local engine; engine=$(_detect_engine)
    local state="unknown" s="healthy"
    case "$engine" in
        firewalld) state=$(firewall-cmd --state 2>/dev/null || echo "stopped") ;;
        nftables|iptables) state="active" ;;
    esac
    [ "$state" != "running" ] && [ "$state" != "active" ] && s="degraded"
    echo "{\"tool\":\"${TOOL_NAME}\",\"node\":\"${NODE_ID}\",\"status\":\"${s}\",\"engine\":\"${engine}\",\"state\":\"${state}\",\"checked_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"
}

do_block() {
    local ip="$1"; validate_ip "$ip" || return 1
    require_root || return 1
    local engine; engine=$(_detect_engine)
    case "$engine" in
        firewalld) firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=${ip} reject" && firewall-cmd --reload ;;
        nftables) nft add rule inet filter input ip saddr "$ip" drop 2>/dev/null ;;
        iptables) iptables -I INPUT -s "$ip" -j DROP 2>/dev/null ;;
    esac
    tool_audit "block" "ip=${ip} engine=${engine} node=${NODE_ID}"
    log_ok "Blocked ${ip} via ${engine}"
}

do_unblock() {
    local ip="$1"; validate_ip "$ip" || return 1
    require_root || return 1
    local engine; engine=$(_detect_engine)
    case "$engine" in
        firewalld) firewall-cmd --permanent --remove-rich-rule="rule family=ipv4 source address=${ip} reject" 2>/dev/null; firewall-cmd --reload ;;
        nftables) log_warn "nftables unblock requires manual rule handle removal" ;;
        iptables) iptables -D INPUT -s "$ip" -j DROP 2>/dev/null ;;
    esac
    tool_audit "unblock" "ip=${ip} engine=${engine} node=${NODE_ID}"
    log_ok "Unblocked ${ip}"
}

do_ssh_harden() {
    echo "=== SSH Hardening: ${NODE_ID} ==="
    echo "  Port: $(grep -E '^Port ' /etc/ssh/sshd_config 2>/dev/null || echo 'default 22')"
    echo "  PasswordAuth: $(grep -E '^PasswordAuthentication' /etc/ssh/sshd_config 2>/dev/null || echo 'not set')"
    echo "  PermitRoot: $(grep -E '^PermitRootLogin' /etc/ssh/sshd_config 2>/dev/null || echo 'not set')"
    echo "  Active sessions: $(who | wc -l)"
}

_do_digest_impl() {
    echo "=== Network Control Report: ${NODE_ID} ==="; _do_send_impl; echo ""
    echo "--- Listening Ports ---"; ss -tlnp 2>/dev/null | head -20; echo ""
    echo "--- SSH ---"; do_ssh_harden
}

_do_flush_impl() { [ -f "$TOOL_LOG" ] && truncate -s 0 "$TOOL_LOG"; echo "Flush complete"; }

tool_help() {
    echo "${TOOL_NAME} v${TOOL_VERSION} -- Network Action Controller"
    echo "  --send|--status|--digest|--flush"
    echo "  --block <ip>|--unblock <ip>|--ssh-harden|--firewall-rule|--dns-failover"
}

do_send()   { tool_wrap "send"   _do_send_impl "$@"; }
do_status() { tool_wrap "status" _do_status_impl "$@"; }
do_digest() { tool_wrap "digest" _do_digest_impl "$@"; }
do_flush()  { tool_wrap "flush"  _do_flush_impl "$@"; }

tool_init; trap 'tool_complete' EXIT
case "${1:---help}" in
    --send) shift; do_send "$@" ;; --status) shift; do_status "$@" ;;
    --digest) shift; do_digest "$@" ;; --flush) shift; do_flush "$@" ;;
    --block) shift; do_block "$@" ;; --unblock) shift; do_unblock "$@" ;;
    --ssh-harden) do_ssh_harden ;; --help) tool_help ;;
    *) handle_standard_command "$@" ;;
esac
