#!/usr/bin/env bash

PORT="22"
PROTO="tcp"

while [[ $# -gt 0 ]]; do
  case "$1" in
    --port|-p)
      PORT="$2"
      shift 2
      ;;
    --proto)
      PROTO="$2"
      shift 2
      ;;
    *)
      echo "Tham số không hợp lệ: $1"
      echo "Cách dùng:"
      echo "  bash Check-RuleLinux.sh --port 22"
      echo "  bash Check-RuleLinux.sh --port 53 --proto udp"
      exit 1
      ;;
  esac
done

HOSTNAME_NOW="$(hostname 2>/dev/null)"
TIME_NOW="$(date '+%F %T %Z' 2>/dev/null)"

UFW_INSTALLED="NO"
UFW_ACTIVE="NO"
UFW_RULE_FOUND="NO"

FIREWALLD_INSTALLED="NO"
FIREWALLD_ACTIVE="NO"
FIREWALLD_RULE_FOUND="NO"

IPTABLES_INSTALLED="NO"
IPTABLES_RULE_FOUND="NO"

NFT_INSTALLED="NO"
NFT_RULE_FOUND="NO"

LISTEN_FOUND="NO"
SSH_SERVICE_ACTIVE="UNKNOWN"

print_sep() {
  echo "=================================================="
}

section() {
  echo
  echo "===== $1 ====="
}

safe_cmd() {
  "$@" 2>/dev/null
}

print_sep
echo "CHECK RULE LINUX"
echo "Host : ${HOSTNAME_NOW:-unknown}"
echo "Time : ${TIME_NOW:-unknown}"
echo "Port : ${PORT}"
echo "Proto: ${PROTO}"
print_sep

section "UFW"
if command -v ufw >/dev/null 2>&1; then
  UFW_INSTALLED="YES"

  UFW_STATUS_OUTPUT="$(safe_cmd ufw status verbose)"
  if echo "$UFW_STATUS_OUTPUT" | grep -q "^Status: active"; then
    UFW_ACTIVE="YES"
  fi

  if [[ -n "$UFW_STATUS_OUTPUT" ]]; then
    echo "$UFW_STATUS_OUTPUT" | grep -Ei "^Status:|^${PORT}/${PROTO}\b|^${PORT}\b" || echo "$UFW_STATUS_OUTPUT"
  else
    echo "Không đọc được trạng thái UFW"
  fi

  if echo "$UFW_STATUS_OUTPUT" | grep -Eiq "^${PORT}/${PROTO}\b|^${PORT}\b"; then
    UFW_RULE_FOUND="YES"
  fi
else
  echo "UFW not installed"
fi

section "FIREWALLD"
if command -v firewall-cmd >/dev/null 2>&1; then
  FIREWALLD_INSTALLED="YES"

  if command -v systemctl >/dev/null 2>&1 && systemctl is-active firewalld >/dev/null 2>&1; then
    FIREWALLD_ACTIVE="YES"
    echo "firewalld: active"

    FW_ALL="$(safe_cmd firewall-cmd --list-all)"
    FW_PORTS="$(safe_cmd firewall-cmd --list-ports)"
    FW_SERVICES="$(safe_cmd firewall-cmd --list-services)"

    [[ -n "$FW_ALL" ]] && echo "$FW_ALL"

    if echo "$FW_PORTS" | grep -Eq "(^|[[:space:]])${PORT}/${PROTO}([[:space:]]|$)"; then
      FIREWALLD_RULE_FOUND="YES"
    fi

    if [[ "$PORT" == "22" && "$PROTO" == "tcp" ]]; then
      if echo "$FW_SERVICES" | grep -Eq "(^|[[:space:]])ssh([[:space:]]|$)"; then
        FIREWALLD_RULE_FOUND="YES"
      fi
    fi
  else
    echo "firewalld not running"
  fi
else
  echo "firewalld not installed"
fi

section "IPTABLES"
if command -v iptables >/dev/null 2>&1; then
  IPTABLES_INSTALLED="YES"

  IPT_MATCHES=""

  IPT_S="$(safe_cmd iptables -S)"
  if [[ -n "$IPT_S" ]]; then
    IPT_MATCHES="$(echo "$IPT_S" | grep -E -- "(-p ${PROTO}\b.*--dport ${PORT}\b|--dport ${PORT}\b.*-p ${PROTO}\b|dpt:${PORT}\b)")"
  fi

  if [[ -z "$IPT_MATCHES" ]] && command -v iptables-save >/dev/null 2>&1; then
    IPT_SAVE="$(safe_cmd iptables-save)"
    if [[ -n "$IPT_SAVE" ]]; then
      IPT_MATCHES="$(echo "$IPT_SAVE" | grep -E -- "(-p ${PROTO}\b.*--dport ${PORT}\b|--dport ${PORT}\b.*-p ${PROTO}\b)")"
    fi
  fi

  if [[ -z "$IPT_MATCHES" ]]; then
    IPT_L="$(safe_cmd iptables -L -n -v)"
    if [[ -n "$IPT_L" ]]; then
      IPT_MATCHES="$(echo "$IPT_L" | grep -E -- "\b${PROTO}\b.*dpt:${PORT}\b|dpt:${PORT}\b")"
    fi
  fi

  if [[ -n "$IPT_MATCHES" ]]; then
    echo "$IPT_MATCHES"
    IPTABLES_RULE_FOUND="YES"
  else
    echo "Không thấy rule iptables khớp port ${PORT}/${PROTO}"
  fi
else
  echo "iptables not installed"
fi

section "NFTABLES"
if command -v nft >/dev/null 2>&1; then
  NFT_INSTALLED="YES"

  NFT_RULESET="$(safe_cmd nft list ruleset)"
  NFT_MATCHES="$(echo "$NFT_RULESET" | grep -E -- "(${PROTO}[[:space:]]+dport[[:space:]]+${PORT}\b|dport[[:space:]]+${PORT}\b)")"

  if [[ -n "$NFT_MATCHES" ]]; then
    echo "$NFT_MATCHES"
    NFT_RULE_FOUND="YES"
  else
    echo "Không thấy rule nftables khớp port ${PORT}/${PROTO}"
  fi
else
  echo "nft not installed"
fi

section "LISTEN PORT"
if command -v ss >/dev/null 2>&1; then
  if [[ "$PROTO" == "tcp" ]]; then
    LISTEN_OUTPUT="$(safe_cmd ss -lntup | grep -E "[:.]${PORT}\b|:${PORT}[[:space:]]")"
  else
    LISTEN_OUTPUT="$(safe_cmd ss -lnuap | grep -E "[:.]${PORT}\b|:${PORT}[[:space:]]")"
  fi

  if [[ -n "$LISTEN_OUTPUT" ]]; then
    echo "$LISTEN_OUTPUT"
    LISTEN_FOUND="YES"
  else
    echo "Không thấy service nào đang LISTEN port ${PORT}/${PROTO}"
  fi
else
  echo "ss not installed"
fi

section "SSH SERVICE"
if [[ "$PORT" == "22" && "$PROTO" == "tcp" ]]; then
  if command -v systemctl >/dev/null 2>&1; then
    if systemctl is-active ssh >/dev/null 2>&1; then
      echo "ssh service: active"
      SSH_SERVICE_ACTIVE="YES"
    elif systemctl is-active sshd >/dev/null 2>&1; then
      echo "sshd service: active"
      SSH_SERVICE_ACTIVE="YES"
    else
      echo "ssh/sshd service: inactive or not found"
      SSH_SERVICE_ACTIVE="NO"
    fi
  else
    echo "systemctl not available"
  fi
else
  echo "Bỏ qua vì đây không phải cổng SSH mặc định"
fi

section "SUMMARY"
echo "UFW installed        : $UFW_INSTALLED"
echo "UFW active           : $UFW_ACTIVE"
echo "UFW rule found       : $UFW_RULE_FOUND"
echo
echo "firewalld installed  : $FIREWALLD_INSTALLED"
echo "firewalld active     : $FIREWALLD_ACTIVE"
echo "firewalld rule found : $FIREWALLD_RULE_FOUND"
echo
echo "iptables installed   : $IPTABLES_INSTALLED"
echo "iptables rule found  : $IPTABLES_RULE_FOUND"
echo
echo "nft installed        : $NFT_INSTALLED"
echo "nft rule found       : $NFT_RULE_FOUND"
echo
echo "service listening    : $LISTEN_FOUND"
echo "ssh service active   : $SSH_SERVICE_ACTIVE"

section "FINAL RESULT"

FINAL_OPEN="NO"

if [[ "$LISTEN_FOUND" == "YES" ]]; then
  if [[ "$UFW_ACTIVE" == "YES" && "$UFW_RULE_FOUND" == "YES" ]]; then
    FINAL_OPEN="YES"
  elif [[ "$FIREWALLD_ACTIVE" == "YES" && "$FIREWALLD_RULE_FOUND" == "YES" ]]; then
    FINAL_OPEN="YES"
  elif [[ "$IPTABLES_RULE_FOUND" == "YES" || "$NFT_RULE_FOUND" == "YES" ]]; then
    FINAL_OPEN="YES"
  elif [[ "$UFW_ACTIVE" == "NO" && "$FIREWALLD_ACTIVE" == "NO" && "$IPTABLES_INSTALLED" == "NO" && "$NFT_INSTALLED" == "NO" ]]; then
    FINAL_OPEN="UNKNOWN"
  fi
fi

if [[ "$FINAL_OPEN" == "YES" ]]; then
  echo "Kết luận: Port ${PORT}/${PROTO} đang được mở và có service lắng nghe."
elif [[ "$LISTEN_FOUND" == "NO" ]]; then
  echo "Kết luận: Chưa thấy service nào lắng nghe trên port ${PORT}/${PROTO}."
else
  echo "Kết luận: Có service lắng nghe nhưng chưa xác nhận rõ rule firewall cho port ${PORT}/${PROTO}."
fi

echo
echo "===== DONE ====="