#!/usr/bin/env bash
#=============================================================================
# Sentinela ? Intelligent Linux Security Framework
# backup/restore.sh ? Sistema de backup y restauración
#=============================================================================
#
# Gestiona backups completos del estado de Sentinela:
# - Reglas de iptables (snapshot)
# - Ipsets
# - Configuración
# - Dashboard (SQLite DB)
# - Logs recientes
#=============================================================================
# shellcheck source=lib/common.sh
source "${SENTINELA_DIR}/lib/common.sh"
#=============================================================================
# Crear backup completo
#=============================================================================
backup_create() {
local backup_name="${1:-sentinela-$(date '+%Y%m%d_%H%M%S')}"
local backup_path="${BACKUP_DIR}/${backup_name}"
require_root
mkdir -p "${backup_path}"
log_info "Creando backup en: ${backup_path}"
# 1. Snapshot de iptables
log_info " ? Respaldando reglas iptables..."
${IPTABLES_SAVE} > "${backup_path}/iptables.txt" 2>/dev/null || log_warn " No se pudo respaldar iptables"
# 2. Ipsets
log_info " ? Respaldando ipsets..."
${IPSET} save > "${backup_path}/ipsets.txt" 2>/dev/null || log_warn " No se pudo respaldar ipsets"
# 3. Configuración
log_info " ? Respaldando configuración..."
cp "${SENTINELA_CONFIG}" "${backup_path}/config.conf" 2>/dev/null || log_warn " No se pudo respaldar configuración"
# 4. Dashboard SQLite
if [[ -f "${DASHBOARD_DIR}/sentinela.db" ]]; then
log_info " ? Respaldando base de datos..."
cp "${DASHBOARD_DIR}/sentinela.db" "${backup_path}/sentinela.db" 2>/dev/null || log_warn " No se pudo respaldar base de datos"
fi
# 5. Logs recientes (últimas 1000 líneas)
log_info " ? Respaldando logs..."
for logfile in sentinela.log attacks.log banned.log; do
if [[ -f "${LOG_DIR}/${logfile}" ]]; then
tail -1000 "${LOG_DIR}/${logfile}" > "${backup_path}/${logfile}" 2>/dev/null || true
fi
done
# 6. Dashboard JSON
if [[ -f "${LOG_DIR}/dashboard.json" ]]; then
cp "${LOG_DIR}/dashboard.json" "${backup_path}/dashboard.json" 2>/dev/null || true
fi
# 7. Metadata
{
echo "version=${SENTINELA_VERSION}"
echo "date=$(date '+%Y-%m-%d %H:%M:%S')"
echo "hostname=$(hostname)"
echo "kernel=$(uname -r)"
} > "${backup_path}/META.txt"
# Comprimir
log_info " ? Comprimiendo backup..."
tar czf "${backup_path}.tar.gz" -C "${BACKUP_DIR}" "${backup_name}" 2>/dev/null || {
log_error "Fallo al comprimir backup"
rm -rf "${backup_path}"
return 1
}
# Limpiar directorio temporal
rm -rf "${backup_path}"
local backup_size
backup_size=$(du -h "${backup_path}.tar.gz" | awk '{print $1}')
log_info "Backup creado: ${backup_path}.tar.gz (${backup_size})"
# Limpiar backups antiguos
backup_cleanup
echo "${backup_path}.tar.gz"
return 0
}
#=============================================================================
# Restaurar backup
#=============================================================================
backup_restore() {
local backup_file="$1"
if [[ -z "${backup_file}" ]]; then
# Listar backups disponibles y pedir selección
echo "Backups disponibles:"
echo "?????????????????????????????????????????????"
local i=1
while IFS= read -r backup; do
echo " ${i}) $(basename "${backup}") ($(du -h "${backup}" | awk '{print $1}'))"
i=$((i + 1))
done < <(ls -1t "${BACKUP_DIR}"/*.tar.gz 2>/dev/null || echo " (no hay backups)")
if [[ ! -f "${BACKUP_DIR}/"*.tar.gz ]]; then
log_info "No hay backups disponibles en ${BACKUP_DIR}"
return 1
fi
echo
read -r -p "Seleccione backup (número): " selection
backup_file=$(ls -1t "${BACKUP_DIR}"/*.tar.gz 2>/dev/null | sed -n "${selection}p")
if [[ -z "${backup_file}" ]]; then
log_error "Selección inválida"
return 1
fi
fi
if [[ ! -f "${backup_file}" ]]; then
log_error "Archivo de backup no encontrado: ${backup_file}"
return 1
fi
require_root
local restore_dir="${BACKUP_DIR}/.restore_tmp"
mkdir -p "${restore_dir}"
log_info "Restaurando backup: ${backup_file}"
# Extraer backup
tar xzf "${backup_file}" -C "${restore_dir}" 2>/dev/null || {
log_error "Fallo al extraer backup"
rm -rf "${restore_dir}"
return 1
}
local extract_dir
extract_dir=$(ls -1 "${restore_dir}" | head -1)
# Restaurar iptables (con precaución)
if [[ -f "${restore_dir}/${extract_dir}/iptables.txt" ]]; then
log_info " ? Restaurando reglas iptables..."
# No restaurar automáticamente, preguntar
echo "Se encontraron reglas iptables en el backup."
read -r -p "¿Restaurar reglas de iptables? (s/N): " confirm
if [[ "${confirm,,}" == "s" ]]; then
${IPTABLES_RESTORE} < "${restore_dir}/${extract_dir}/iptables.txt" 2>/dev/null && \
log_info " Reglas iptables restauradas" || \
log_warn " Fallo al restaurar reglas iptables"
fi
fi
# Restaurar ipsets
if [[ -f "${restore_dir}/${extract_dir}/ipsets.txt" ]]; then
log_info " ? Restaurando ipsets..."
echo "Se encontraron ipsets en el backup."
read -r -p "¿Restaurar ipsets? (s/N): " confirm
if [[ "${confirm,,}" == "s" ]]; then
# Destruir ipsets existentes primero
source "${SENTINELA_DIR}/ipset/manager.sh"
ipset_destroy_all
ipset_create_all
# Cargar entries adicionales
${IPSET} restore < "${restore_dir}/${extract_dir}/ipsets.txt" 2>/dev/null || \
log_warn " Fallo al restaurar algunos ipsets (pueden existir ya)"
log_info " Ipsets restaurados"
fi
fi
# Restaurar configuración
if [[ -f "${restore_dir}/${extract_dir}/config.conf" ]]; then
log_info " ? Restaurando configuración..."
cp "${restore_dir}/${extract_dir}/config.conf" "${SENTINELA_CONFIG}.restored" 2>/dev/null
log_info " Configuración restaurada como: ${SENTINELA_CONFIG}.restored"
log_warn " Revise y mueva manualmente: cp ${SENTINELA_CONFIG}.restored ${SENTINELA_CONFIG}"
fi
# Restaurar base de datos dashboard
if [[ -f "${restore_dir}/${extract_dir}/sentinela.db" ]]; then
log_info " ? Restaurando base de datos..."
cp "${restore_dir}/${extract_dir}/sentinela.db" "${DASHBOARD_DIR}/sentinela.db.restored" 2>/dev/null
log_info " BD restaurada como: ${DASHBOARD_DIR}/sentinela.db.restored"
fi
# Restaurar dashboard JSON
if [[ -f "${restore_dir}/${extract_dir}/dashboard.json" ]]; then
cp "${restore_dir}/${extract_dir}/dashboard.json" "${LOG_DIR}/dashboard.json" 2>/dev/null || true
fi
# Limpiar
rm -rf "${restore_dir}"
log_info "Backup restaurado exitosamente"
return 0
}
#=============================================================================
# Listar backups
#=============================================================================
backup_list() {
local backups
backups=$(ls -1t "${BACKUP_DIR}"/*.tar.gz 2>/dev/null)
if [[ -z "${backups}" ]]; then
log_info "No hay backups disponibles en ${BACKUP_DIR}"
return 0
fi
echo "Backups disponibles:"
echo "??????????????????????????????????????????????????????????"
printf " %-25s %-10s %s\n" "NOMBRE" "TAMAÑO" "FECHA"
echo "??????????????????????????????????????????????????????????"
while IFS= read -r backup; do
local name size date
name=$(basename "${backup}" .tar.gz)
size=$(du -h "${backup}" | awk '{print $1}')
date=$(stat -c '%y' "${backup}" | cut -d'.' -f1)
printf " %-25s %-10s %s\n" "${name}" "${size}" "${date}"
done <<< "${backups}"
}
#=============================================================================
# Limpiar backups antiguos
#=============================================================================
backup_cleanup() {
local retention="${1:-${BACKUP_RETENTION}}"
log_info "Limpiando backups con más de ${retention} días"
find "${BACKUP_DIR}" -name "*.tar.gz" -type f -mtime "+${retention}" -delete 2>/dev/null || true
local remaining
remaining=$(ls -1 "${BACKUP_DIR}"/*.tar.gz 2>/dev/null | wc -l)
log_debug "Backups restantes: ${remaining}"
}
|