PHP Classes

File: lib/common.sh

Recommend this page to a friend!
  Packages of Moises Espindola   Sentinela   lib/common.sh   Download  
File: lib/common.sh
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Sentinela
Linux protection tools with Web dashboard panel
Author: By
Last change:
Date: 6 days ago
Size: 13,068 bytes
 

Contents

Class file image Download
#!/usr/bin/env bash #============================================================================= # Sentinela ? Intelligent Linux Security Framework # lib/common.sh ? Funciones comunes y utilidades #============================================================================= set -Eeuo pipefail #============================================================================= # Constantes #============================================================================= SENTINELA_VERSION="1.0.0" SENTINELA_NAME="Sentinela" SENTINELA_DESC="Intelligent Linux Security Framework" SENTINELA_DIR="/root/sentinela" SENTINELA_CONFIG="${SENTINELA_DIR}/config.conf" SENTINELA_LIB="${SENTINELA_DIR}/lib" SENTINELA_FIREWALL="${SENTINELA_DIR}/firewall" SENTINELA_IDS="${SENTINELA_DIR}/ids" SENTINELA_IPSET="${SENTINELA_DIR}/ipset" SENTINELA_TELEGRAM="${SENTINELA_DIR}/telegram" SENTINELA_BACKUP="${SENTINELA_DIR}/backup" SENTINELA_CRON="${SENTINELA_DIR}/cron" SENTINELA_GEOIP="${SENTINELA_DIR}/geoip" SENTINELA_LOGS="${SENTINELA_DIR}/logs" SENTINELA_DASHBOARD="${SENTINELA_DIR}/dashboard" SENTINELA_API="${SENTINELA_DIR}/api" SENTINELA_SYSTEMD="${SENTINELA_DIR}/systemd" SENTINELA_CLI="${SENTINELA_DIR}/cli" #============================================================================= # Cargar configuración #============================================================================= load_config() { # Defaults antes de cargar config (para evitar unbound vars) LOG_DIR="${LOG_DIR:-/var/log/sentinela}" BACKUP_DIR="${BACKUP_DIR:-/var/backups/sentinela}" DASHBOARD_DIR="${DASHBOARD_DIR:-/var/www/sentinela}" TELEGRAM_ENABLE="${TELEGRAM_ENABLE:-no}" ROLLBACK_ENABLE="${ROLLBACK_ENABLE:-yes}" ROLLBACK_TIMEOUT="${ROLLBACK_TIMEOUT:-90}" IDS_APACHE_LOG="${IDS_APACHE_LOG:-/var/log/apache2/access.log}" IDS_SSH_LOG="${IDS_SSH_LOG:-/var/log/auth.log}" REPUTATION_ENABLE="${REPUTATION_ENABLE:-no}" BAN_TIME="${BAN_TIME:-600}" DDOS_BAN_TIME="${DDOS_BAN_TIME:-600}" PORT_SSH="${PORT_SSH:-7890}" PORT_HTTP="${PORT_HTTP:-80}" PORT_HTTPS="${PORT_HTTPS:-443}" PORT_MYSQL="${PORT_MYSQL:-3306}" SSH_RATE_LIMIT="${SSH_RATE_LIMIT:-5}" HTTP_RATE_LIMIT="${HTTP_RATE_LIMIT:-60}" HTTPS_RATE_LIMIT="${HTTPS_RATE_LIMIT:-60}" SSH_CONNLIMIT="${SSH_CONNLIMIT:-3}" HTTP_CONNLIMIT="${HTTP_CONNLIMIT:-30}" HTTPS_CONNLIMIT="${HTTPS_CONNLIMIT:-30}" LOG_LEVEL="${LOG_LEVEL:-info}" BACKUP_RETENTION="${BACKUP_RETENTION:-7}" ENABLE_SSH="${ENABLE_SSH:-yes}" ENABLE_HTTP="${ENABLE_HTTP:-yes}" ENABLE_HTTPS="${ENABLE_HTTPS:-yes}" ENABLE_MYSQL="${ENABLE_MYSQL:-yes}" # Preservar LOG_SYSTEM del entorno (permite override temporal) local env_log_system="${LOG_SYSTEM:-}" if [[ -f "${SENTINELA_CONFIG}" ]]; then # shellcheck source=config.conf source "${SENTINELA_CONFIG}" fi # Restaurar override del entorno si existe if [[ -n "${env_log_system}" ]]; then LOG_SYSTEM="${env_log_system}" else LOG_SYSTEM="${LOG_SYSTEM:-rsyslog}" fi # Si no se definió IFACE, detectarla IFACE="${IFACE:-$(ip route get 1 2>/dev/null | awk '{print $5; exit}')}" # Asegurar directorios de log mkdir -p "${LOG_DIR}" "${BACKUP_DIR}" "${DASHBOARD_DIR}" 2>/dev/null || true } #============================================================================= # Logging #============================================================================= log_info() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $*" | tee -a "${LOG_DIR}/sentinela.log" >&2; } log_warn() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] $*" | tee -a "${LOG_DIR}/sentinela.log" >&2; } log_error() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" | tee -a "${LOG_DIR}/sentinela.log" >&2; } log_fatal() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [FATAL] $*" | tee -a "${LOG_DIR}/sentinela.log" >&2; exit 1; } log_debug() { if [[ "${LOG_LEVEL:-info}" == "debug" ]]; then echo "[$(date '+%Y-%m-%d %H:%M:%S')] [DEBUG] $*" | tee -a "${LOG_DIR}/sentinela.log" >&2; fi; } log_attack() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ATTACK] $*" | tee -a "${LOG_DIR}/attacks.log" >&2; } log_ban() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [BAN] $*" | tee -a "${LOG_DIR}/banned.log" >&2; } #============================================================================= # Verificar ejecución como root #============================================================================= require_root() { if [[ $EUID -ne 0 ]]; then log_fatal "Este comando debe ejecutarse como root" fi } #============================================================================= # Verificar binarios requeridos #============================================================================= require_binary() { local cmd="$1" if ! command -v "$cmd" &>/dev/null; then log_fatal "Binario requerido no encontrado: ${cmd}. Instálelo con: apt-get install -y ${cmd}" fi } #============================================================================= # Detectar IP de sesión SSH actual #============================================================================= get_ssh_ip() { local ssh_ip ssh_ip=$(who -m 2>/dev/null | awk '{print $NF}' | tr -d '()') if [[ -z "${ssh_ip}" ]] || [[ "${ssh_ip}" == "("?*")" ]]; then ssh_ip=$(who am i 2>/dev/null | awk '{print $NF}' | tr -d '()') fi if [[ -z "${ssh_ip}" ]] || [[ "${ssh_ip}" == "("?*")" ]]; then local sc="${SSH_CLIENT:-}" ssh_ip="${sc%% *}" fi if [[ -z "${ssh_ip}" ]]; then local sc="${SSH_CONNECTION:-}" ssh_ip="${sc%% *}" fi echo "${ssh_ip}" } #============================================================================= # Verificar si una IP es válida #============================================================================= is_valid_ip() { local ip="$1" if [[ "${ip}" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then local IFS='.' read -r -a octets <<< "${ip}" for octet in "${octets[@]}"; do if ((octet < 0 || octet > 255)); then return 1 fi done return 0 fi return 1 } #============================================================================= # Ejecutar comando con validación #============================================================================= safe_exec() { local cmd="$1" local msg="${2:-}" if [[ -n "${msg}" ]]; then log_debug "${msg}" fi if ! eval "${cmd}"; then log_error "Fallo al ejecutar: ${cmd}" return 1 fi } #============================================================================= # Confirmación con timeout (rollback) #============================================================================= confirm_with_timeout() { local timeout="${1:-${ROLLBACK_TIMEOUT}}" local message="${2:-Firewall aplicado. ¿Todo funciona? [SI/s/N]: }" local response log_info "Esperando confirmación... (timeout: ${timeout}s)" read -r -t "${timeout}" -p "${message}" response || true if [[ "${response,,}" == "si" ]] || [[ "${response,,}" == "s" ]]; then return 0 else return 1 fi } #============================================================================= # Mostrar banner #============================================================================= show_banner() { cat << 'EOF' ??????????????????????????????????????????????????????? ? ? ? ???????????????????? ??????????????????? ??? ? ? ????????????????????? ???????????????????? ??? ? ? ?????????????? ?????? ??? ??? ????????? ??? ? ? ?????????????? ?????????? ??? ????????????? ? ? ??????????????????? ?????? ??? ?????? ?????? ? ? ??????????????????? ????? ??? ?????? ????? ? ? ? ? Intelligent Linux Security Framework ? ? Versión 1.0.0 ? ??????????????????????????????????????????????????????? EOF } #============================================================================= # Sistema de logging del SO (rsyslog | journald) # # LOG_SYSTEM define cómo se leen los logs del sistema: # rsyslog ? archivos tradicionales (/var/log/auth.log, etc.) # journald ? systemd-journald via journalctl # # Identificadores de log: # apache_access ? IDS_APACHE_LOG (rsyslog) / journalctl -u apache2.service # ssh_auth ? IDS_SSH_LOG (rsyslog) / journalctl _COMM=sshd #============================================================================= # Obtener filtro de journalctl según identificador _journalctl_filter() { local identifier="$1" case "${identifier}" in apache_access) echo "-u apache2.service" ;; ssh_auth) echo "_COMM=sshd" ;; *) return 1 ;; esac } # Verificar si una fuente de log está disponible log_check_exists() { local identifier="$1" case "${LOG_SYSTEM}" in journald) local filter filter=$(_journalctl_filter "${identifier}") || return 1 journalctl ${filter} -n 1 --no-pager &>/dev/null ;; *) # rsyslog local logfile="" case "${identifier}" in apache_access) logfile="${IDS_APACHE_LOG}" ;; ssh_auth) logfile="${IDS_SSH_LOG}" ;; *) return 1 ;; esac [[ -f "${logfile}" ]] ;; esac } # Leer nuevas líneas desde la última posición registrada # Uso: log_read_new_lines <identifier> # Exit: 0 si hay contenido nuevo (imprime en stdout), 1 si no hay nada log_read_new_lines() { local identifier="$1" case "${LOG_SYSTEM}" in journald) local filter filter=$(_journalctl_filter "${identifier}") || return 1 local state_file="${SENTINELA_DIR}/logs/.${identifier}_cursor" local cursor="" if [[ -f "${state_file}" ]]; then cursor=$(cat "${state_file}") fi local output="" if [[ -n "${cursor}" ]]; then output=$(journalctl ${filter} --after-cursor "${cursor}" --no-pager 2>/dev/null) || return 1 else output=$(journalctl ${filter} -n 1000 --no-pager 2>/dev/null) || return 1 fi if [[ -z "${output}" ]] || [[ "${output}" == "-- No entries --"* ]]; then return 1 fi # Guardar cursor de la última línea leída journalctl ${filter} -n 1 --output=export --no-pager 2>/dev/null | \ strings | grep '^__CURSOR=' | cut -d= -f2- > "${state_file}" || true echo "${output}" ;; *) # rsyslog local logfile="" local state_file="" case "${identifier}" in apache_access) logfile="${IDS_APACHE_LOG}"; state_file="${SENTINELA_DIR}/logs/.${identifier}_pos" ;; ssh_auth) logfile="${IDS_SSH_LOG}"; state_file="${SENTINELA_DIR}/logs/.${identifier}_pos" ;; *) return 1 ;; esac if [[ ! -f "${logfile}" ]]; then return 1 fi local last_pos=0 if [[ -f "${state_file}" ]]; then last_pos=$(cat "${state_file}") fi local current_size current_size=$(stat -c%s "${logfile}" 2>/dev/null || echo 0) if [[ "${current_size}" -lt "${last_pos}" ]]; then last_pos=0 fi if [[ "${current_size}" -eq "${last_pos}" ]] || [[ "${current_size}" -eq 0 ]]; then return 1 fi local new_bytes=$((current_size - last_pos)) tail -c "${new_bytes}" "${logfile}" 2>/dev/null || return 1 echo "${current_size}" > "${state_file}" ;; esac } #============================================================================= # Inicialización #============================================================================= init() { load_config }