sp-hydra-veil-core/lib/steps/wrapper.sh

140 lines
No EOL
5.2 KiB
Bash

#!/bin/bash
# lib/steps/wrapper.sh — generar wrapper de privilegios para sing-box
step_wrapper() {
print_section "Security Wrapper"
log_step "Installing hydraveil-singbox wrapper" 5 $TOTAL_STEPS
[ -f "$SINGBOX_WRAPPER" ] && sudo rm -f "$SINGBOX_WRAPPER" && log_ok "Wrapper anterior eliminado"
sudo tee "$SINGBOX_WRAPPER" > /dev/null << WRAPPER
#!/bin/bash
# hydraveil-singbox — wrapper de privilegios para sing-box
# Generado por el installer. NO editar manualmente.
# Solo este binario tiene NOPASSWD en sudoers.
#
# Uso:
# sudo hydraveil-singbox <config.json> start
# sudo hydraveil-singbox "" stop
# sudo hydraveil-singbox "" log
set -euo pipefail
CONFIG="\${1:-}"
ACTION="\${2:-}"
# ── Paths fijos (rutas XDG correctas — INSTALL_DIR=\$HOME) ────────────────────
SINGBOX_BIN="${SINGBOX_BIN}"
PID_FILE="${SINGBOX_PID_FILE}"
LOG_FILE="${SINGBOX_LOG_FILE}"
CONFIG_DIR="${SINGBOX_CONFIG_DIR}"
STOP_TIMEOUT=8
# ── Validar acción ────────────────────────────────────────────────────────────
if [[ "\$ACTION" != "start" && "\$ACTION" != "stop" && "\$ACTION" != "log" ]]; then
echo "Error: acción inválida '\$ACTION'. Uso: start|stop|log" >&2
exit 1
fi
# ── Helpers ───────────────────────────────────────────────────────────────────
_pid_running() {
local pid="\$1"
[[ "\$pid" =~ ^[0-9]+$ ]] && kill -0 "\$pid" 2>/dev/null
}
_delete_tun() {
if ip link show tun0 &>/dev/null 2>&1; then
ip link delete tun0 2>/dev/null || true
echo "[wrapper] tun0 eliminada" >> "\$LOG_FILE" 2>/dev/null || true
fi
}
_kill_by_pidfile() {
[ -f "\$PID_FILE" ] || return 0
local pid
pid=\$(cat "\$PID_FILE" 2>/dev/null || echo "")
if ! _pid_running "\$pid"; then
rm -f "\$PID_FILE"
return 0
fi
kill -TERM "\$pid" 2>/dev/null || true
echo "[wrapper] SIGTERM → PID \$pid" >> "\$LOG_FILE" 2>/dev/null || true
local elapsed=0
while _pid_running "\$pid" && (( elapsed < STOP_TIMEOUT * 2 )); do
sleep 0.5
(( elapsed++ )) || true
done
if _pid_running "\$pid"; then
kill -KILL "\$pid" 2>/dev/null || true
echo "[wrapper] SIGKILL → PID \$pid" >> "\$LOG_FILE" 2>/dev/null || true
sleep 0.3
fi
rm -f "\$PID_FILE"
}
# ── log ───────────────────────────────────────────────────────────────────────
if [[ "\$ACTION" == "log" ]]; then
[ -f "\$LOG_FILE" ] && tail -80 "\$LOG_FILE" || echo "Sin logs disponibles"
exit 0
fi
# ── stop ──────────────────────────────────────────────────────────────────────
if [[ "\$ACTION" == "stop" ]]; then
_kill_by_pidfile
_delete_tun
echo "[wrapper] sing-box detenido — \$(date '+%Y-%m-%d %H:%M:%S')" >> "\$LOG_FILE" 2>/dev/null || true
exit 0
fi
# ── start ─────────────────────────────────────────────────────────────────────
[[ -z "\$CONFIG" ]] && { echo "Error: config requerido para start" >&2; exit 1; }
[[ ! -f "\$CONFIG" ]] && { echo "Error: config no encontrado: \$CONFIG" >&2; exit 1; }
[[ ! -r "\$CONFIG" ]] && { echo "Error: config no legible: \$CONFIG" >&2; exit 1; }
_real_config=\$(realpath "\$CONFIG")
_real_config_dir=\$(realpath "\$CONFIG_DIR")
if [[ "\$_real_config" != "\$_real_config_dir"/* ]]; then
echo "Error: config fuera del directorio permitido" >&2
echo " Config: \$_real_config" >&2
echo " Permitido: \$_real_config_dir" >&2
exit 1
fi
if ! python3 -c "import json,sys; json.load(open(sys.argv[1]))" "\$CONFIG" 2>/dev/null; then
echo "Error: JSON inválido: \$CONFIG" >&2
exit 1
fi
[[ ! -x "\$SINGBOX_BIN" ]] && { echo "Error: sing-box no encontrado: \$SINGBOX_BIN" >&2; exit 1; }
_kill_by_pidfile
_delete_tun
mkdir -p "\$(dirname "\$PID_FILE")" && chmod 700 "\$(dirname "\$PID_FILE")"
mkdir -p "\$(dirname "\$LOG_FILE")" && chmod 700 "\$(dirname "\$LOG_FILE")"
"\$SINGBOX_BIN" run -c "\$CONFIG" >> "\$LOG_FILE" 2>&1 &
_new_pid=\$!
sleep 0.3
if ! _pid_running "\$_new_pid"; then
echo "Error: sing-box terminó inmediatamente. Ver: \$LOG_FILE" >&2
exit 1
fi
echo "\$_new_pid" > "\$PID_FILE"
chmod 600 "\$PID_FILE"
echo "[wrapper] sing-box iniciado — PID \$_new_pid — \$(date '+%Y-%m-%d %H:%M:%S')" >> "\$LOG_FILE"
echo "[wrapper] config: \$_real_config" >> "\$LOG_FILE"
exit 0
WRAPPER
sudo chmod 755 "$SINGBOX_WRAPPER"
log_ok "Wrapper instalado → ${SINGBOX_WRAPPER}"
# Verificar que el wrapper funciona
if sudo "$SINGBOX_WRAPPER" "" stop &>/dev/null; then
log_ok "Wrapper verificado (stop OK)"
else
log_warn "Wrapper instalado pero verificación falló — revisar manualmente"
fi
}