140 lines
No EOL
5.2 KiB
Bash
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
|
|
} |