diff --git a/awg-ctrl/package.json b/awg-ctrl/package.json index 9fc6cc0..bae8a83 100644 --- a/awg-ctrl/package.json +++ b/awg-ctrl/package.json @@ -1,6 +1,6 @@ { "name": "awg-control", - "version": "0.1.4", + "version": "0.1.4+1", "description": "", "main": "dist/index.js", "scripts": { diff --git a/awg-ui/package.json b/awg-ui/package.json index 4628989..7822f52 100644 --- a/awg-ui/package.json +++ b/awg-ui/package.json @@ -1,6 +1,6 @@ { "name": "awg-ui", - "version": "0.1.4", + "version": "0.1.4+1", "private": true, "scripts": { "dev": "vite", diff --git a/awg-ui/src/App.tsx b/awg-ui/src/App.tsx index 4558083..482786d 100644 --- a/awg-ui/src/App.tsx +++ b/awg-ui/src/App.tsx @@ -214,7 +214,7 @@ export default function App() { >
Forgetting - Alpha 0.1.4 + Alpha 0.1.4.1

{TABS.map(t => ( diff --git a/cli/package.json b/cli/package.json index 23bfe96..2cd4955 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "awg-cli", - "version": "0.1.4", + "version": "0.1.4+1", "private": true, "dependencies": { "tsx": "^4.7.0", diff --git a/cli/src/index.ts b/cli/src/index.ts index cb02996..11602b8 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -287,7 +287,7 @@ async function interactiveMenu() { const printMenu = () => { console.clear(); - console.log(`\n${bold(`${C.blue}── Forgetting Alpha 0.1.4 ──${C.reset}`)}\n`); + console.log(`\n${bold(`${C.blue}── Forgetting Alpha 0.1.4.1 ──${C.reset}`)}\n`); for (const name of ALL) { const running = isRunning(name); diff --git a/install.sh b/install.sh index 43546bb..296e38c 100644 --- a/install.sh +++ b/install.sh @@ -19,7 +19,7 @@ trap 'rc=$?; echo -e "\n ${RED}✗ НЕОЖИДАННАЯ ОШИБКА${NC} с [[ $EUID -ne 0 ]] && fail "Запусти от root: sudo bash install.sh" [[ -z "${BASH_VERSION:-}" ]] && fail "Нужен bash: bash install.sh" -VERSION="0.1.4" +VERSION="0.1.4.1" GH_REPO="maeneko/forgetting" BASE_URL="https://github.com/${GH_REPO}/releases/download/v${VERSION}" PROJECT="/opt/awg-control" @@ -469,18 +469,48 @@ kernel_lt_5_5() { [[ "$maj" -lt 5 || ( "$maj" -eq 5 && "$min" -lt 5 ) ]] } -MOD_VER=$(modinfo -F version amneziawg 2>/dev/null || echo "") +# 🛑 Версий у модуля две, и путать их нельзя: +# modinfo — что лежит на диске (после apt/DKMS); +# /sys/module/amneziawg/version — что реально загружено в ядро. +# `apt --only-upgrade` пересобирает модуль, но НЕ переставляет уже загруженный. +# Ориентироваться на modinfo — значит написать 3.1-конфиг, который старый +# загруженный модуль отвергнет: `awg setconf` вернёт «Unable to modify +# interface: Invalid argument», и awg-quick up упадёт. Решает перезагрузка модуля. +disk_mod_ver() { modinfo -F version amneziawg 2>/dev/null || echo ""; } +loaded_mod_ver() { cat /sys/module/amneziawg/version 2>/dev/null || echo ""; } + +MOD_VER=$(disk_mod_ver) if [[ "${MOD_VER%%.*}" != "3" ]]; then warn "Модуль amneziawg версии '${MOD_VER:-неизвестно}' — для AmneziaWG 3.1 нужна 3.x. Пробуем обновить." apt-get update >/dev/null 2>&1 || true DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a \ apt-get install -y --only-upgrade amneziawg amneziawg-dkms amneziawg-tools >/dev/null 2>&1 || true - MOD_VER=$(modinfo -F version amneziawg 2>/dev/null || echo "") + MOD_VER=$(disk_mod_ver) fi +# Загруженный отстал от дискового — перезагружаем. Интерфейс держит модуль, +# поэтому сначала опускаем его; awg1 на этом шаге ещё не нужен. +LOADED_VER=$(loaded_mod_ver) +if [[ -n "$LOADED_VER" && "$LOADED_VER" != "$MOD_VER" ]]; then + warn "В ядре загружен модуль $LOADED_VER, на диске $MOD_VER — перезагружаем модуль." + awg-quick down "$IFACE" 2>/dev/null || true + ip link delete dev "$IFACE" 2>/dev/null || true + if modprobe -r amneziawg 2>/dev/null && modprobe amneziawg 2>/dev/null; then + LOADED_VER=$(loaded_mod_ver) + ok "Модуль перезагружен: в ядре теперь $LOADED_VER" + else + warn "Не удалось перезагрузить модуль (занят?). Нужна перезагрузка сервера." + fi +fi + +# Дальше решает ТОЛЬКО загруженная версия — именно она обслуживает интерфейс. +[[ -n "$LOADED_VER" ]] && MOD_VER="$LOADED_VER" + if [[ "${MOD_VER%%.*}" != "3" ]]; then AWG3="n" - warn "Модуль остался на версии '${MOD_VER:-неизвестно}' — ставим сервер на AmneziaWG 2.0." + warn "В ядре модуль версии '${MOD_VER:-неизвестно}' — ставим сервер на AmneziaWG 2.0." + [[ "$(disk_mod_ver)" == 3.* ]] && \ + warn "На диске уже 3.x — после перезагрузки сервера можно переустановить и получить 3.1." elif kernel_lt_5_5; then AWG3="n" warn "Ядро $KERNEL старше 5.5 — header protection не соберётся (upstream issue #210)." @@ -637,7 +667,41 @@ if awg show "$IFACE" &>/dev/null; then awg-quick down "$IFACE" 2>/dev/null || true fi -awg-quick up "$IFACE" || fail "awg-quick up $IFACE завершился с ошибкой" +# Подъём интерфейса — единственная настоящая проверка, что ядро приняло +# 3.1-параметры. Модуль на отказ отвечает лишь «Invalid argument», причину +# печатает только в dmesg и только при включённом dynamic debug. Поэтому: +# упали → включаем debug, пробуем ещё раз, показываем причину, и если и это не +# помогло — снимаем 3.x-ключи и поднимаемся на 2.0, а не валим установку. +AWG3_KEY_RE='^(HeaderProtectionKey|ContentPaddingAddition|RekeyAfterTime|RekeyTimeout|RejectAfterTime|KeepaliveTimeout|MaxHandshakeAttempts|RandomTrailers|DisableCookies) *=' + +if ! awg-quick up "$IFACE"; then + ip link delete dev "$IFACE" 2>/dev/null || true + + if [[ "$AWG3" != "y" ]]; then + fail "awg-quick up $IFACE завершился с ошибкой" + fi + + warn "Ядро отвергло конфиг AmneziaWG 3.1. Выясняем причину." + echo "module amneziawg +p" > /sys/kernel/debug/dynamic_debug/control 2>/dev/null || true + + if awg-quick up "$IFACE"; then + ok "Со второй попытки интерфейс поднялся" + else + ip link delete dev "$IFACE" 2>/dev/null || true + echo " ── dmesg (последние 15 строк) ─────────────────" + dmesg 2>/dev/null | grep -i amneziawg | tail -n 15 | sed 's/^/ /' || true + echo " ───────────────────────────────────────────────" + + cp "$AWG_CONF" "${AWG_CONF}.awg31" + sed -i -E "/$AWG3_KEY_RE/d" "$AWG_CONF" + AWG3="n"; NEW_GEN="2.0" + warn "Откатываемся на AmneziaWG 2.0. Конфиг 3.1 сохранён: ${AWG_CONF}.awg31" + + awg-quick up "$IFACE" \ + || fail "awg-quick up $IFACE не работает даже на 2.0 — смотри dmesg выше" + ok "Интерфейс поднят на AmneziaWG 2.0" + fi +fi # awg-quick не всегда применяет приватный ключ из [Interface]/PostUp # (наблюдалось: awg show public-key = none сразу после up). Если ключ не @@ -655,6 +719,23 @@ else fail "Ключ на $IFACE не совпал: ${RUNNING_PUB:-none} ≠ $PUB_KEY" fi +# UFW. PostUp делает `iptables -A FORWARD` — правило ДОПИСЫВАЕТСЯ в конец +# цепочки, а UFW вставляет свои переходы в начало, поэтому до нашего ACCEPT +# дело не доходит и трафик клиентов наружу режется: в dmesg сыплется +# «[UFW BLOCK] IN=awg1 OUT=eth0». Симптом — «VPN подключается, интернета нет». +# Лечится штатным `ufw route allow`, менять DEFAULT_FORWARD_POLICY не нужно. +if command -v ufw &>/dev/null && ufw status 2>/dev/null | grep -qi '^Status: active'; then + echo " → UFW активен, открываем маршрут и порты" + ufw route allow in on "$IFACE" out on "$NET_IFACE" >/dev/null 2>&1 \ + || warn "ufw route allow не сработал — трафик клиентов может резаться" + ufw allow "${AWG_PORT}/udp" >/dev/null 2>&1 || warn "не удалось открыть ${AWG_PORT}/udp" + ufw allow "${UI_PORT}/tcp" >/dev/null 2>&1 || warn "не удалось открыть ${UI_PORT}/tcp" + ufw reload >/dev/null 2>&1 || true + ok "UFW: форвардинг $IFACE → $NET_IFACE, порты ${AWG_PORT}/udp и ${UI_PORT}/tcp" +else + echo " → UFW не активен, правила фаервола не трогаем" +fi + step "6/7 npm install" npm_install_all