#!/usr/bin/env bash
#=============================================================================
# Sentinela ? Intelligent Linux Security Framework
# lib/ssh-session.sh ? Detección y protección de sesión SSH
#=============================================================================
#
# Este módulo garantiza que la sesión SSH actual NUNCA sea bloqueada.
#
# Estrategia:
# 1. Detecta IP de la sesión SSH activa (múltiples métodos)
# 2. La agrega a ipset TRUSTED (timeout 86400s = 24h)
# 3. La IP TRUSTED siempre está exenta de bloqueos en las reglas
# 4. Cada vez que se aplican reglas, se re-detecta y re-agrega
#=============================================================================
# shellcheck source=lib/common.sh
source "${SENTINELA_DIR}/lib/common.sh"
#=============================================================================
# Variables
#=============================================================================
TRUSTED_IPSET="SENTINELA_TRUSTED"
SSH_SESSION_IP=""
#=============================================================================
# Detectar IP de la sesión SSH actual
# Usa múltiples métodos de respaldo
#=============================================================================
ssh_detect_session_ip() {
local ip=""
# Método 1: who -m (who am i)
ip=$(who -m 2>/dev/null | awk '{print $NF}' | tr -d '()')
if [[ -n "${ip}" ]] && is_valid_ip "${ip}"; then
SSH_SESSION_IP="${ip}"
log_debug "Sesión SSH detectada (who -m): ${ip}"
echo "${ip}"
return 0
fi
# Método 2: who am i
ip=$(who am i 2>/dev/null | awk '{print $NF}' | tr -d '()')
if [[ -n "${ip}" ]] && is_valid_ip "${ip}"; then
SSH_SESSION_IP="${ip}"
log_debug "Sesión SSH detectada (who am i): ${ip}"
echo "${ip}"
return 0
fi
# Método 3: SSH_CLIENT
local ssh_client="${SSH_CLIENT:-}"
if [[ -n "${ssh_client}" ]]; then
ip="${ssh_client%% *}"
if is_valid_ip "${ip}"; then
SSH_SESSION_IP="${ip}"
log_debug "Sesión SSH detectada (SSH_CLIENT): ${ip}"
echo "${ip}"
return 0
fi
fi
# Método 4: SSH_CONNECTION
local ssh_connection="${SSH_CONNECTION:-}"
if [[ -n "${ssh_connection}" ]]; then
ip="${ssh_connection%% *}"
if is_valid_ip "${ip}"; then
SSH_SESSION_IP="${ip}"
log_debug "Sesión SSH detectada (SSH_CONNECTION): ${ip}"
echo "${ip}"
return 0
fi
fi
# Método 5: ss (último recurso)
ip=$(ss -tnp state established 2>/dev/null | grep ":${PORT_SSH}" | awk '{print $5}' | cut -d: -f1 | head -1)
if [[ -n "${ip}" ]] && is_valid_ip "${ip}"; then
SSH_SESSION_IP="${ip}"
log_debug "Sesión SSH detectada (ss): ${ip}"
echo "${ip}"
return 0
fi
log_warn "No se pudo detectar IP de sesión SSH"
return 1
}
#=============================================================================
# Crear ipset TRUSTED si no existe
#=============================================================================
ssh_ensure_trusted_ipset() {
if ! ${IPSET} list "${TRUSTED_IPSET}" &>/dev/null; then
log_info "Creando ipset ${TRUSTED_IPSET}"
${IPSET} create "${TRUSTED_IPSET}" hash:ip timeout 86400 2>/dev/null || {
${IPSET} destroy "${TRUSTED_IPSET}" 2>/dev/null || true
${IPSET} create "${TRUSTED_IPSET}" hash:ip timeout 86400
}
log_info "Ipset ${TRUSTED_IPSET} creado"
fi
}
#=============================================================================
# Agregar IP actual a TRUSTED
# Esta función se llama SIEMPRE antes de aplicar reglas
#=============================================================================
ssh_protect_current_session() {
require_root
# Asegurar que el ipset existe
ssh_ensure_trusted_ipset
# Detectar IP (podría fallar en systemd/boot ? no es crítico)
local ip
ip=$(ssh_detect_session_ip) || {
log_warn "No se pudo proteger la sesión SSH (IP no detectada, continuando de todas formas)"
return 0
}
# Agregar al ipset TRUSTED (timeout 86400s = 24h)
if ${IPSET} add "${TRUSTED_IPSET}" "${ip}" timeout 86400 2>/dev/null; then
log_info "Sesión SSH protegida: ${ip} agregada a ${TRUSTED_IPSET} (24h)"
else
log_warn "IP ${ip} ya está en ${TRUSTED_IPSET} o no se pudo agregar"
fi
return 0
}
#=============================================================================
# Agregar IP manualmente a TRUSTED
#=============================================================================
ssh_trust_ip() {
local ip="$1"
if ! is_valid_ip "${ip}"; then
log_error "IP inválida: ${ip}"
return 1
fi
require_root
ssh_ensure_trusted_ipset
if ${IPSET} add "${TRUSTED_IPSET}" "${ip}" timeout 0 2>/dev/null; then
log_info "IP ${ip} agregada permanentemente a ${TRUSTED_IPSET}"
return 0
else
log_error "No se pudo agregar IP ${ip} a ${TRUSTED_IPSET}"
return 1
fi
}
#=============================================================================
# Quitar IP de TRUSTED
#=============================================================================
ssh_untrust_ip() {
local ip="$1"
if ! is_valid_ip "${ip}"; then
log_error "IP inválida: ${ip}"
return 1
fi
require_root
if ${IPSET} del "${TRUSTED_IPSET}" "${ip}" 2>/dev/null; then
log_info "IP ${ip} removida de ${TRUSTED_IPSET}"
return 0
else
log_warn "IP ${ip} no está en ${TRUSTED_IPSET} o no se pudo remover"
return 1
fi
}
#=============================================================================
# Listar IPs en TRUSTED
#=============================================================================
ssh_list_trusted() {
require_root
if ! ${IPSET} list "${TRUSTED_IPSET}" &>/dev/null; then
log_info "No hay IPs en TRUSTED"
return 0
fi
echo "IPs confiables (TRUSTED):"
echo "??????????????????????????????????????"
${IPSET} list "${TRUSTED_IPSET}" | grep -E '^[0-9]' | sort -t' ' -k2
}
|