fix(awg): support AmneziaWG 2.0/3.0/3.1, fix WARP generator safety & update release 1.3.20
This commit is contained in:
@@ -593,6 +593,15 @@ const dictionary = {
|
|||||||
|
|
||||||
// WARP / AmneziaWG
|
// WARP / AmneziaWG
|
||||||
"AmneziaWG Generator": "Генератор AmneziaWG",
|
"AmneziaWG Generator": "Генератор AmneziaWG",
|
||||||
|
"AmneziaWG Version": "Версия AmneziaWG",
|
||||||
|
"AmneziaWG 2.0": "AmneziaWG 2.0",
|
||||||
|
"AmneziaWG 3.0": "AmneziaWG 3.0",
|
||||||
|
"AmneziaWG 3.1": "AmneziaWG 3.1",
|
||||||
|
"Protocol version: 2.0 (standard headers, WARP compatible), 3.0 (header protection key, padding ranges), or 3.1 (header protection key, padding ranges, advanced timers)": "Версия протокола: 2.0 (стандартные заголовки, совместимо с WARP), 3.0 (ключ защиты заголовков, диапазоны паддинга), или 3.1 (ключ защиты заголовков, диапазоны паддинга, расширенные таймеры)",
|
||||||
|
"AmneziaWG %s configuration generated and loaded successfully!": "Конфигурация AmneziaWG %s успешно сгенерирована и загружена!",
|
||||||
|
"Notice: Cloudflare WARP edge servers only support AmneziaWG 2.0 (standard headers). For Cloudflare WARP, select version 2.0. Versions 3.0 and 3.1 are intended for dedicated AmneziaWG servers.": "Обратите внимание: серверы Cloudflare WARP поддерживают только AmneziaWG 2.0 (стандартные заголовки). Для Cloudflare WARP выберите версию 2.0. Версии 3.0 и 3.1 предназначены для выделенных серверов AmneziaWG.",
|
||||||
|
"AmneziaWG 3.0 / 3.1 header protection key": "Ключ защиты заголовков AmneziaWG 3.0 / 3.1",
|
||||||
|
"AmneziaWG 3.0 / 3.1 content padding range, e.g. 38-104": "Диапазон дополнительного паддинга контента AmneziaWG 3.0 / 3.1, например 38-104",
|
||||||
"Import AmneziaWG settings from .conf file": "Импортировать настройки AmneziaWG из файла .conf",
|
"Import AmneziaWG settings from .conf file": "Импортировать настройки AmneziaWG из файла .conf",
|
||||||
"Load .conf": "Загрузить .conf",
|
"Load .conf": "Загрузить .conf",
|
||||||
"Load .conf config": "Загрузить конфигурацию .conf",
|
"Load .conf config": "Загрузить конфигурацию .conf",
|
||||||
@@ -1335,6 +1344,7 @@ const dictionary = {
|
|||||||
"CleanBrowsing Security": "CleanBrowsing (Безопасность)",
|
"CleanBrowsing Security": "CleanBrowsing (Безопасность)",
|
||||||
"CleanBrowsing Family": "CleanBrowsing (Семейный)",
|
"CleanBrowsing Family": "CleanBrowsing (Семейный)",
|
||||||
"Yandex Safe": "Yandex (Безопасный)",
|
"Yandex Safe": "Yandex (Безопасный)",
|
||||||
|
"Hide versions": "Скрыть версии",
|
||||||
};
|
};
|
||||||
|
|
||||||
function escapePoString(str) {
|
function escapePoString(str) {
|
||||||
|
|||||||
+2520
-1901
File diff suppressed because it is too large
Load Diff
+2287
-1917
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TACHYON\n"
|
"Project-Id-Version: TACHYON\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-09-01 21:58+0300\n"
|
"POT-Creation-Date: 2026-09-05 10:59+0300\n"
|
||||||
"PO-Revision-Date: 2026-09-01 21:58+0300\n"
|
"PO-Revision-Date: 2026-09-05 10:59+0300\n"
|
||||||
"Last-Translator: Dushnilin\n"
|
"Last-Translator: Dushnilin\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
@@ -41,9 +41,15 @@ msgstr "+ Добавить стратегию"
|
|||||||
msgid "+ Add URLTest"
|
msgid "+ Add URLTest"
|
||||||
msgstr "+ Добавить URLTest"
|
msgstr "+ Добавить URLTest"
|
||||||
|
|
||||||
|
msgid "⏳ Stopping..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "⚠️ Benchmark completed. No working bypass found for this target."
|
msgid "⚠️ Benchmark completed. No working bypass found for this target."
|
||||||
msgstr "⚠️ Бенчмарк завершен. Не найдено рабочих стратегий для данной цели."
|
msgstr "⚠️ Бенчмарк завершен. Не найдено рабочих стратегий для данной цели."
|
||||||
|
|
||||||
|
msgid "⚠️ Benchmark stopped"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "⚠️ If all Bootstrap DNS fail 3 times, queries will be sent to your ISP's DNS in plaintext. Only use as a last resort to prevent complete internet loss."
|
msgid "⚠️ If all Bootstrap DNS fail 3 times, queries will be sent to your ISP's DNS in plaintext. Only use as a last resort to prevent complete internet loss."
|
||||||
msgstr "⚠️ Если все Bootstrap DNS завершатся с ошибкой 3 раза, запросы будут отправлены в DNS вашего провайдера в открытом виде. Используйте только в крайнем случае для предотвращения полной потери интернета."
|
msgstr "⚠️ Если все Bootstrap DNS завершатся с ошибкой 3 раза, запросы будут отправлены в DNS вашего провайдера в открытом виде. Используйте только в крайнем случае для предотвращения полной потери интернета."
|
||||||
|
|
||||||
@@ -59,8 +65,8 @@ msgstr "⚡ Быстрые (>1 МБ/с)"
|
|||||||
msgid "⚡ QUIC / HTTP/3 (UDP 443)"
|
msgid "⚡ QUIC / HTTP/3 (UDP 443)"
|
||||||
msgstr "⚡ QUIC / HTTP/3 (UDP 443)"
|
msgstr "⚡ QUIC / HTTP/3 (UDP 443)"
|
||||||
|
|
||||||
msgid "⚡ Quick Benchmark (Presets ~12-14)"
|
msgid "⚡ Quick Benchmark (Presets ~30+)"
|
||||||
msgstr "⚡ Быстрый бенчмарк (Пресеты ~12-14)"
|
msgstr ""
|
||||||
|
|
||||||
msgid "⚡ Strategy Fuzzer & Auto-Tuner"
|
msgid "⚡ Strategy Fuzzer & Auto-Tuner"
|
||||||
msgstr "⚡ Подборщик стратегий и авто-тюнер"
|
msgstr "⚡ Подборщик стратегий и авто-тюнер"
|
||||||
@@ -92,8 +98,8 @@ msgstr "✘ Остановлено"
|
|||||||
msgid "🌐 Custom Target URL..."
|
msgid "🌐 Custom Target URL..."
|
||||||
msgstr "🌐 Пользовательский URL цели..."
|
msgstr "🌐 Пользовательский URL цели..."
|
||||||
|
|
||||||
msgid "🎬 YouTube Suite (Web + 4K Stream)"
|
msgid "🎬 YouTube Full Suite (Web + 4K Stream + CDN)"
|
||||||
msgstr "🎬 YouTube Suite (Web + 4K Stream)"
|
msgstr ""
|
||||||
|
|
||||||
msgid "🏆 Apply Best Match"
|
msgid "🏆 Apply Best Match"
|
||||||
msgstr "🏆 Применить наилучшую"
|
msgstr "🏆 Применить наилучшую"
|
||||||
@@ -101,8 +107,11 @@ msgstr "🏆 Применить наилучшую"
|
|||||||
msgid "🏴☠️ RuTracker Suite"
|
msgid "🏴☠️ RuTracker Suite"
|
||||||
msgstr "🏴☠️ RuTracker Suite"
|
msgstr "🏴☠️ RuTracker Suite"
|
||||||
|
|
||||||
msgid "💬 Discord Suite (API + WSS + CDN)"
|
msgid "🐦 X / Twitter Suite (API + Media CDN)"
|
||||||
msgstr "💬 Discord Suite (API + WSS + CDN)"
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "💬 Discord Suite (Gateway + Voice + CDN)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "💾 Save Custom Patterns"
|
msgid "💾 Save Custom Patterns"
|
||||||
msgstr "💾 Сохранить пользовательские паттерны"
|
msgstr "💾 Сохранить пользовательские паттерны"
|
||||||
@@ -116,12 +125,15 @@ msgstr "🔄 Обновить"
|
|||||||
msgid "🔄 Reset to Factory Defaults"
|
msgid "🔄 Reset to Factory Defaults"
|
||||||
msgstr "🔄 Сбросить к заводским настройкам"
|
msgstr "🔄 Сбросить к заводским настройкам"
|
||||||
|
|
||||||
msgid "🔍 Combinatorial Deep Fuzzing (~40-80+)"
|
msgid "🔍 Combinatorial Deep Fuzzing (~150-300+)"
|
||||||
msgstr "🔍 Комбинаторный глубокий фаззинг (~40-80+)"
|
msgstr ""
|
||||||
|
|
||||||
msgid "🗑️ Clear History"
|
msgid "🗑️ Clear History"
|
||||||
msgstr "🗑️ Очистить историю"
|
msgstr "🗑️ Очистить историю"
|
||||||
|
|
||||||
|
msgid "🤖 ChatGPT / OpenAI Suite"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "🧠 Synthesize with AI"
|
msgid "🧠 Synthesize with AI"
|
||||||
msgstr "🧠 Сгенерировать через ИИ"
|
msgstr "🧠 Сгенерировать через ИИ"
|
||||||
|
|
||||||
@@ -134,12 +146,18 @@ msgstr "🚀 Инициализация бенчмарка в песочнице
|
|||||||
msgid "🚀 Start Benchmark"
|
msgid "🚀 Start Benchmark"
|
||||||
msgstr "🚀 Начать бенчмарк"
|
msgstr "🚀 Начать бенчмарк"
|
||||||
|
|
||||||
|
msgid "🛑 Benchmark stopped"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "🛑 Stop Benchmark"
|
msgid "🛑 Stop Benchmark"
|
||||||
msgstr "🛑 Остановить бенчмарк"
|
msgstr "🛑 Остановить бенчмарк"
|
||||||
|
|
||||||
msgid "🛠️ My Custom Strategies Only"
|
msgid "🛠️ My Custom Strategies Only"
|
||||||
msgstr "🛠️ Только мои стратегии"
|
msgstr "🛠️ Только мои стратегии"
|
||||||
|
|
||||||
|
msgid "🟣 Twitch Suite (Live Stream + HLS CDN)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Accept external proxy connections and route them with sing-box."
|
msgid "Accept external proxy connections and route them with sing-box."
|
||||||
msgstr "Принимать внешние прокси-подключения и маршрутизировать их через sing-box."
|
msgstr "Принимать внешние прокси-подключения и маршрутизировать их через sing-box."
|
||||||
|
|
||||||
@@ -398,12 +416,36 @@ msgstr "Всегда блокировать эти домены для всех
|
|||||||
msgid "Always visible"
|
msgid "Always visible"
|
||||||
msgstr "Всегда включено"
|
msgstr "Всегда включено"
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 content padding range, e.g. 38-104"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 header protection key"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 keepalive timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 max handshake attempts"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 reject after time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 rekey after time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 rekey timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "AmneziaWG config loaded successfully!"
|
msgid "AmneziaWG config loaded successfully!"
|
||||||
msgstr "Конфигурация AmneziaWG успешно загружена!"
|
msgstr "Конфигурация AmneziaWG успешно загружена!"
|
||||||
|
|
||||||
msgid "AmneziaWG Generator"
|
msgid "AmneziaWG Generator"
|
||||||
msgstr "Генератор AmneziaWG"
|
msgstr "Генератор AmneziaWG"
|
||||||
|
|
||||||
|
msgid "AmneziaWG Version"
|
||||||
|
msgstr "Версия AmneziaWG"
|
||||||
|
|
||||||
msgid "Anonymized support report copied to clipboard"
|
msgid "Anonymized support report copied to clipboard"
|
||||||
msgstr "Анонимизированный отчет скопирован в буфер обмена"
|
msgstr "Анонимизированный отчет скопирован в буфер обмена"
|
||||||
|
|
||||||
@@ -425,6 +467,9 @@ msgstr "Применено"
|
|||||||
msgid "Apply"
|
msgid "Apply"
|
||||||
msgstr "Применить"
|
msgstr "Применить"
|
||||||
|
|
||||||
|
msgid "Apply Recommended DNS"
|
||||||
|
msgstr "Применить рекомендованный DNS"
|
||||||
|
|
||||||
msgid "Apply rules of this section only to selected protocols."
|
msgid "Apply rules of this section only to selected protocols."
|
||||||
msgstr "Применять правила этой секции только к выбранным протоколам."
|
msgstr "Применять правила этой секции только к выбранным протоколам."
|
||||||
|
|
||||||
@@ -500,6 +545,9 @@ msgstr "Авто-генерация HWID"
|
|||||||
msgid "Auto-Heal Network Stack"
|
msgid "Auto-Heal Network Stack"
|
||||||
msgstr "Автолечение сетевого стека"
|
msgstr "Автолечение сетевого стека"
|
||||||
|
|
||||||
|
msgid "Auto-Tune & Benchmark DNS"
|
||||||
|
msgstr "Подобрать и протестировать DNS"
|
||||||
|
|
||||||
msgid "Auto-update Hosts Lists"
|
msgid "Auto-update Hosts Lists"
|
||||||
msgstr "Автообновление списков Hosts"
|
msgstr "Автообновление списков Hosts"
|
||||||
|
|
||||||
@@ -518,6 +566,9 @@ msgstr "Автоматический выбор User-Agent"
|
|||||||
msgid "Automatically add text to the name of each server from this subscription for convenient filtering."
|
msgid "Automatically add text to the name of each server from this subscription for convenient filtering."
|
||||||
msgstr "Автоматически добавлять текст к имени каждого сервера из этой подписки для удобной фильтрации."
|
msgstr "Автоматически добавлять текст к имени каждого сервера из этой подписки для удобной фильтрации."
|
||||||
|
|
||||||
|
msgid "Automatically benchmark latency, packet loss, and anti-censorship reliability of major DNS servers (UDP/DoH) from this router to find and apply the optimal configuration."
|
||||||
|
msgstr "Автоматически замерить задержку, потери пакетов и защиту от цензуры основных DNS серверов (UDP/DoH) прямо с роутера, чтобы найти и применить оптимальную конфигурацию."
|
||||||
|
|
||||||
msgid "Automatically check installed components for new versions"
|
msgid "Automatically check installed components for new versions"
|
||||||
msgstr "Автоматически проверять установленные компоненты на наличие новых версий"
|
msgstr "Автоматически проверять установленные компоненты на наличие новых версий"
|
||||||
|
|
||||||
@@ -563,9 +614,15 @@ msgstr "Беларусь (by)"
|
|||||||
msgid "Benchmark & Test"
|
msgid "Benchmark & Test"
|
||||||
msgstr "Бенчмарк и тестирование"
|
msgstr "Бенчмарк и тестирование"
|
||||||
|
|
||||||
|
msgid "Benchmark completed successfully"
|
||||||
|
msgstr "Бенчмарк успешно завершён"
|
||||||
|
|
||||||
msgid "Benchmark History"
|
msgid "Benchmark History"
|
||||||
msgstr "История бенчмарков"
|
msgstr "История бенчмарков"
|
||||||
|
|
||||||
|
msgid "Benchmark measures actual latency and resolution reliability of major DNS servers (UDP 53 and encrypted DoH) directly from your router to find the fastest, unblocked upstream for your ISP."
|
||||||
|
msgstr "Бенчмарк замеряет реальную задержку и надёжность резолва основных DNS серверов (UDP 53 и шифрованный DoH) напрямую с роутера, чтобы найти самый быстрый и незаблокированный апстрим у вашего провайдера."
|
||||||
|
|
||||||
msgid "Benchmark stopped"
|
msgid "Benchmark stopped"
|
||||||
msgstr "Бенчмарк остановлен"
|
msgstr "Бенчмарк остановлен"
|
||||||
|
|
||||||
@@ -899,6 +956,9 @@ msgstr "Строка аргументов командной строки..."
|
|||||||
msgid "Community Lists"
|
msgid "Community Lists"
|
||||||
msgstr "Community-списки"
|
msgstr "Community-списки"
|
||||||
|
|
||||||
|
msgid "Component action timed out"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Component update available"
|
msgid "Component update available"
|
||||||
msgstr "Доступно обновление компонента"
|
msgstr "Доступно обновление компонента"
|
||||||
|
|
||||||
@@ -929,6 +989,9 @@ msgstr "Путь к файлу конфигурации"
|
|||||||
msgid "Config Snapshots"
|
msgid "Config Snapshots"
|
||||||
msgstr "Снапшоты конфигурации"
|
msgstr "Снапшоты конфигурации"
|
||||||
|
|
||||||
|
msgid "Configuration applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Configuration for Tachyon service"
|
msgid "Configuration for Tachyon service"
|
||||||
msgstr "Конфигурация сервиса Tachyon"
|
msgstr "Конфигурация сервиса Tachyon"
|
||||||
|
|
||||||
@@ -962,6 +1025,9 @@ msgstr "Консультируюсь с базой знаний DPI и ИИ..."
|
|||||||
msgid "Content Mode"
|
msgid "Content Mode"
|
||||||
msgstr "Режим контента"
|
msgstr "Режим контента"
|
||||||
|
|
||||||
|
msgid "Content Padding Addition"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Cookie packet junk size (S3)"
|
msgid "Cookie packet junk size (S3)"
|
||||||
msgstr "Размер мусора в пакете cookie (S3)"
|
msgstr "Размер мусора в пакете cookie (S3)"
|
||||||
|
|
||||||
@@ -1163,6 +1229,9 @@ msgstr "Отображаемое имя"
|
|||||||
msgid "DNS"
|
msgid "DNS"
|
||||||
msgstr "DNS"
|
msgstr "DNS"
|
||||||
|
|
||||||
|
msgid "DNS Auto-Tuner & Benchmark"
|
||||||
|
msgstr "Автоподбор и бенчмарк DNS"
|
||||||
|
|
||||||
msgid "DNS Check Interval"
|
msgid "DNS Check Interval"
|
||||||
msgstr "Интервал проверки DNS"
|
msgstr "Интервал проверки DNS"
|
||||||
|
|
||||||
@@ -1187,6 +1256,9 @@ msgstr "DNS через TLS (DoT)"
|
|||||||
msgid "DNS protocol"
|
msgid "DNS protocol"
|
||||||
msgstr "Протокол DNS"
|
msgstr "Протокол DNS"
|
||||||
|
|
||||||
|
msgid "DNS Protocol"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "DNS Protocol Type"
|
msgid "DNS Protocol Type"
|
||||||
msgstr "Тип протокола DNS"
|
msgstr "Тип протокола DNS"
|
||||||
|
|
||||||
@@ -1535,6 +1607,9 @@ msgstr "Ошибка обновления списков:"
|
|||||||
msgid "Every day"
|
msgid "Every day"
|
||||||
msgstr "Каждый день"
|
msgstr "Каждый день"
|
||||||
|
|
||||||
|
msgid "EXCELLENT"
|
||||||
|
msgstr "ОТЛИЧНО"
|
||||||
|
|
||||||
msgid "Exclude by proxy parameters"
|
msgid "Exclude by proxy parameters"
|
||||||
msgstr "Исключить по параметрам прокси"
|
msgstr "Исключить по параметрам прокси"
|
||||||
|
|
||||||
@@ -1577,6 +1652,9 @@ msgstr "Истекает"
|
|||||||
msgid "Expose this section as a local HTTP+SOCKS proxy"
|
msgid "Expose this section as a local HTTP+SOCKS proxy"
|
||||||
msgstr "Предоставить эту секцию как локальный HTTP+SOCKS прокси"
|
msgstr "Предоставить эту секцию как локальный HTTP+SOCKS прокси"
|
||||||
|
|
||||||
|
msgid "extended"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "External inbound proxy servers"
|
msgid "External inbound proxy servers"
|
||||||
msgstr "Внешние входящие прокси-серверы"
|
msgstr "Внешние входящие прокси-серверы"
|
||||||
|
|
||||||
@@ -1586,6 +1664,15 @@ msgstr "Внешние файлы конфигурации nfqws обходят
|
|||||||
msgid "External nfqws2 config files bypass Tachyon queue management and explicit validation."
|
msgid "External nfqws2 config files bypass Tachyon queue management and explicit validation."
|
||||||
msgstr "Внешние файлы конфигурации nfqws2 обходят управление очередями Tachyon и явную проверку."
|
msgstr "Внешние файлы конфигурации nfqws2 обходят управление очередями Tachyon и явную проверку."
|
||||||
|
|
||||||
|
msgid "FAILED"
|
||||||
|
msgstr "СБОЙ"
|
||||||
|
|
||||||
|
msgid "Failed to apply DNS configuration"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Failed to apply DNS settings"
|
||||||
|
msgstr "Не удалось применить настройки DNS"
|
||||||
|
|
||||||
msgid "Failed to apply fix"
|
msgid "Failed to apply fix"
|
||||||
msgstr "Не удалось применить исправление"
|
msgstr "Не удалось применить исправление"
|
||||||
|
|
||||||
@@ -1622,12 +1709,18 @@ msgstr "Не удалось определить тип DPI"
|
|||||||
msgid "Failed to execute"
|
msgid "Failed to execute"
|
||||||
msgstr "Не удалось выполнить"
|
msgstr "Не удалось выполнить"
|
||||||
|
|
||||||
|
msgid "Failed to fetch releases"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to generate bug report"
|
msgid "Failed to generate bug report"
|
||||||
msgstr "Не удалось создать отчёт об ошибке"
|
msgstr "Не удалось создать отчёт об ошибке"
|
||||||
|
|
||||||
msgid "Failed to generate WARP config:"
|
msgid "Failed to generate WARP config:"
|
||||||
msgstr "Не удалось сгенерировать конфигурацию WARP:"
|
msgstr "Не удалось сгенерировать конфигурацию WARP:"
|
||||||
|
|
||||||
|
msgid "Failed to get DNS benchmark status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to get fuzzer history"
|
msgid "Failed to get fuzzer history"
|
||||||
msgstr "Не удалось получить историю фаззера"
|
msgstr "Не удалось получить историю фаззера"
|
||||||
|
|
||||||
@@ -1640,12 +1733,18 @@ msgstr "Не удалось получить статус фаззера"
|
|||||||
msgid "Failed to get fuzzer strategies"
|
msgid "Failed to get fuzzer strategies"
|
||||||
msgstr "Не удалось получить стратегии фаззера"
|
msgstr "Не удалось получить стратегии фаззера"
|
||||||
|
|
||||||
|
msgid "Failed to install version"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to load history"
|
msgid "Failed to load history"
|
||||||
msgstr "Не удалось загрузить историю"
|
msgstr "Не удалось загрузить историю"
|
||||||
|
|
||||||
msgid "Failed to load snapshots"
|
msgid "Failed to load snapshots"
|
||||||
msgstr "Не удалось загрузить снапшоты"
|
msgstr "Не удалось загрузить снапшоты"
|
||||||
|
|
||||||
|
msgid "Failed to load versions"
|
||||||
|
msgstr "Не удалось загрузить версии"
|
||||||
|
|
||||||
msgid "Failed to parse file:"
|
msgid "Failed to parse file:"
|
||||||
msgstr "Ошибка разбора файла:"
|
msgstr "Ошибка разбора файла:"
|
||||||
|
|
||||||
@@ -1691,6 +1790,9 @@ msgstr "Не удалось запустить бенчмарк"
|
|||||||
msgid "Failed to start bot"
|
msgid "Failed to start bot"
|
||||||
msgstr "Не удалось запустить бота"
|
msgstr "Не удалось запустить бота"
|
||||||
|
|
||||||
|
msgid "Failed to start DNS benchmark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to start fuzzer"
|
msgid "Failed to start fuzzer"
|
||||||
msgstr "Не удалось запустить фаззер"
|
msgstr "Не удалось запустить фаззер"
|
||||||
|
|
||||||
@@ -1703,6 +1805,9 @@ msgstr "Не удалось запустить watchdog"
|
|||||||
msgid "Failed to stop bot"
|
msgid "Failed to stop bot"
|
||||||
msgstr "Не удалось остановить бота"
|
msgstr "Не удалось остановить бота"
|
||||||
|
|
||||||
|
msgid "Failed to stop DNS benchmark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to stop fuzzer"
|
msgid "Failed to stop fuzzer"
|
||||||
msgstr "Не удалось остановить фаззер"
|
msgstr "Не удалось остановить фаззер"
|
||||||
|
|
||||||
@@ -1724,6 +1829,9 @@ msgstr "Не удалось обновить подписки"
|
|||||||
msgid "Failover failure threshold"
|
msgid "Failover failure threshold"
|
||||||
msgstr "Порог срабатывания failover"
|
msgstr "Порог срабатывания failover"
|
||||||
|
|
||||||
|
msgid "FAIR"
|
||||||
|
msgstr "СРЕДНЕ"
|
||||||
|
|
||||||
msgid "FakeIP and control checks use different public IPs"
|
msgid "FakeIP and control checks use different public IPs"
|
||||||
msgstr "FakeIP и контрольная проверка используют разные публичные IP"
|
msgstr "FakeIP и контрольная проверка используют разные публичные IP"
|
||||||
|
|
||||||
@@ -1736,6 +1844,9 @@ msgstr "FakeIP работает; сравнение публичных IP не
|
|||||||
msgid "FakeTLS host"
|
msgid "FakeTLS host"
|
||||||
msgstr "FakeTLS host"
|
msgstr "FakeTLS host"
|
||||||
|
|
||||||
|
msgid "Fallback DNS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Fallback DNS Servers"
|
msgid "Fallback DNS Servers"
|
||||||
msgstr "Резервные DNS серверы"
|
msgstr "Резервные DNS серверы"
|
||||||
|
|
||||||
@@ -1748,75 +1859,6 @@ msgstr "Резервные DNS серверы должны быть обычны
|
|||||||
msgid "Fallback on unknown DC"
|
msgid "Fallback on unknown DC"
|
||||||
msgstr "Fallback при неизвестном DC"
|
msgstr "Fallback при неизвестном DC"
|
||||||
|
|
||||||
msgid "DNS Auto-Tuner & Benchmark"
|
|
||||||
msgstr "Автоподбор и бенчмарк DNS"
|
|
||||||
|
|
||||||
msgid "Auto-Tune & Benchmark DNS"
|
|
||||||
msgstr "Подобрать и протестировать DNS"
|
|
||||||
|
|
||||||
msgid "Automatically benchmark latency, packet loss, and anti-censorship reliability of major DNS servers (UDP/DoH) from this router to find and apply the optimal configuration."
|
|
||||||
msgstr "Автоматически замерить задержку, потери пакетов и защиту от цензуры основных DNS серверов (UDP/DoH) прямо с роутера, чтобы найти и применить оптимальную конфигурацию."
|
|
||||||
|
|
||||||
msgid "Tachyon DNS Benchmark & Auto-Tuning"
|
|
||||||
msgstr "Tachyon: Бенчмарк и автоподбор DNS"
|
|
||||||
|
|
||||||
msgid "Ready to benchmark DNS providers"
|
|
||||||
msgstr "Готов к тестированию DNS провайдеров"
|
|
||||||
|
|
||||||
msgid "Benchmark measures actual latency and resolution reliability of major DNS servers (UDP 53 and encrypted DoH) directly from your router to find the fastest, unblocked upstream for your ISP."
|
|
||||||
msgstr "Бенчмарк замеряет реальную задержку и надёжность резолва основных DNS серверов (UDP 53 и шифрованный DoH) напрямую с роутера, чтобы найти самый быстрый и незаблокированный апстрим у вашего провайдера."
|
|
||||||
|
|
||||||
msgid "Start Benchmark"
|
|
||||||
msgstr "Начать тест"
|
|
||||||
|
|
||||||
msgid "Starting DNS benchmark..."
|
|
||||||
msgstr "Запуск бенчмарка DNS..."
|
|
||||||
|
|
||||||
msgid "Benchmark completed successfully"
|
|
||||||
msgstr "Бенчмарк успешно завершён"
|
|
||||||
|
|
||||||
msgid "Apply Recommended DNS"
|
|
||||||
msgstr "Применить рекомендованный DNS"
|
|
||||||
|
|
||||||
msgid "Recommended DNS Configuration"
|
|
||||||
msgstr "Рекомендованная конфигурация DNS"
|
|
||||||
|
|
||||||
msgid "Recommended DNS settings applied successfully and service restarted!"
|
|
||||||
msgstr "Рекомендованные настройки DNS успешно применены, сервис перезапущен!"
|
|
||||||
|
|
||||||
msgid "Failed to start benchmark"
|
|
||||||
msgstr "Не удалось запустить бенчмарк"
|
|
||||||
|
|
||||||
msgid "Failed to apply DNS settings"
|
|
||||||
msgstr "Не удалось применить настройки DNS"
|
|
||||||
|
|
||||||
msgid "No benchmark data yet. Click \"Start Benchmark\" to begin."
|
|
||||||
msgstr "Нет данных бенчмарка. Нажмите «Начать тест», чтобы запустить проверку."
|
|
||||||
|
|
||||||
msgid "EXCELLENT"
|
|
||||||
msgstr "ОТЛИЧНО"
|
|
||||||
|
|
||||||
msgid "GOOD"
|
|
||||||
msgstr "ХОРОШО"
|
|
||||||
|
|
||||||
msgid "FAIR"
|
|
||||||
msgstr "СРЕДНЕ"
|
|
||||||
|
|
||||||
msgid "SLOW"
|
|
||||||
msgstr "МЕДЛЕННО"
|
|
||||||
|
|
||||||
msgid "FAILED"
|
|
||||||
msgstr "СБОЙ"
|
|
||||||
|
|
||||||
msgid "Protocol"
|
|
||||||
msgstr "Протокол"
|
|
||||||
|
|
||||||
msgid "Rating"
|
|
||||||
msgstr "Оценка"
|
|
||||||
|
|
||||||
msgid "Loss"
|
|
||||||
msgstr "Потери"
|
|
||||||
|
|
||||||
msgid "Family (🏠)"
|
msgid "Family (🏠)"
|
||||||
msgstr "Семья (🏠)"
|
msgstr "Семья (🏠)"
|
||||||
|
|
||||||
@@ -1847,6 +1889,9 @@ msgstr "Фильтровать серверы, отображаемые на д
|
|||||||
msgid "Filter:"
|
msgid "Filter:"
|
||||||
msgstr "Фильтр:"
|
msgstr "Фильтр:"
|
||||||
|
|
||||||
|
msgid "Finished with code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Finland (fi)"
|
msgid "Finland (fi)"
|
||||||
msgstr "Финляндия (fi)"
|
msgstr "Финляндия (fi)"
|
||||||
|
|
||||||
@@ -1886,6 +1931,9 @@ msgstr "Принудительно включает безопасный пои
|
|||||||
msgid "Forces sing-box to tunnel DNS requests via DoQ with Encrypted Client Hello (ECH) for SNI hiding."
|
msgid "Forces sing-box to tunnel DNS requests via DoQ with Encrypted Client Hello (ECH) for SNI hiding."
|
||||||
msgstr "Принудительно направлять DNS-запросы через DoQ с Encrypted Client Hello (ECH) для скрытия SNI."
|
msgstr "Принудительно направлять DNS-запросы через DoQ с Encrypted Client Hello (ECH) для скрытия SNI."
|
||||||
|
|
||||||
|
msgid "Found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "France (fr)"
|
msgid "France (fr)"
|
||||||
msgstr "Франция (fr)"
|
msgstr "Франция (fr)"
|
||||||
|
|
||||||
@@ -1973,6 +2021,9 @@ msgstr "Не удалось выполнить глобальную провер
|
|||||||
msgid "Global Default"
|
msgid "Global Default"
|
||||||
msgstr "Глобально по умолчанию"
|
msgstr "Глобально по умолчанию"
|
||||||
|
|
||||||
|
msgid "GOOD"
|
||||||
|
msgstr "ХОРОШО"
|
||||||
|
|
||||||
msgid "Group devices into family profiles to manage content filtering, SafeSearch, and screen time limits in one place."
|
msgid "Group devices into family profiles to manage content filtering, SafeSearch, and screen time limits in one place."
|
||||||
msgstr "Группируйте устройства в семейные профили для централизованного управления фильтрацией сайтов, безопасным поиском и лимитами экранного времени."
|
msgstr "Группируйте устройства в семейные профили для централизованного управления фильтрацией сайтов, безопасным поиском и лимитами экранного времени."
|
||||||
|
|
||||||
@@ -1982,6 +2033,9 @@ msgstr "Сервис gRPC"
|
|||||||
msgid "Handshake timeout"
|
msgid "Handshake timeout"
|
||||||
msgstr "Таймаут рукопожатия"
|
msgstr "Таймаут рукопожатия"
|
||||||
|
|
||||||
|
msgid "Header Protection Key"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Hello! I am Tachyon AI Assistant. How can I help you today? Ask me about domain blocks, diagnostics, or router settings."
|
msgid "Hello! I am Tachyon AI Assistant. How can I help you today? Ask me about domain blocks, diagnostics, or router settings."
|
||||||
msgstr "Привет! Я ИИ-ассистент Tachyon. Чем могу помочь? Задайте вопрос о блокировках, диагностике или настройках роутера."
|
msgstr "Привет! Я ИИ-ассистент Tachyon. Чем могу помочь? Задайте вопрос о блокировках, диагностике или настройках роутера."
|
||||||
|
|
||||||
@@ -2033,6 +2087,9 @@ msgstr "Скрыть узлы групп URLTest"
|
|||||||
msgid "Hide values"
|
msgid "Hide values"
|
||||||
msgstr "Скрывать значения"
|
msgstr "Скрывать значения"
|
||||||
|
|
||||||
|
msgid "Hide versions"
|
||||||
|
msgstr "Скрыть версии"
|
||||||
|
|
||||||
msgid "Higher-level check interval"
|
msgid "Higher-level check interval"
|
||||||
msgstr "Интервал проверки высших уровней"
|
msgstr "Интервал проверки высших уровней"
|
||||||
|
|
||||||
@@ -2534,6 +2591,9 @@ msgstr "Сохранять предыдущую рабочую версию ко
|
|||||||
msgid "Keep URLTest before latency-sorted servers"
|
msgid "Keep URLTest before latency-sorted servers"
|
||||||
msgstr "Сохранять URLTest перед серверами, отсортированными по задержке"
|
msgstr "Сохранять URLTest перед серверами, отсортированными по задержке"
|
||||||
|
|
||||||
|
msgid "Keepalive Timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Keeps FakeIP cache persistent across reboots and pre-resolves popular blocked domains on startup so first-visit latency is 0 ms."
|
msgid "Keeps FakeIP cache persistent across reboots and pre-resolves popular blocked domains on startup so first-visit latency is 0 ms."
|
||||||
msgstr "Сохраняет FakeIP-кэш между перезагрузками и заранее резолвит популярные заблокированные домены при старте — задержка при первом визите 0 мс."
|
msgstr "Сохраняет FakeIP-кэш между перезагрузками и заранее резолвит популярные заблокированные домены при старте — задержка при первом визите 0 мс."
|
||||||
|
|
||||||
@@ -2555,6 +2615,9 @@ msgstr "Язык ответов диагностики ИИ-доктора"
|
|||||||
msgid "Laptop / PC (💻)"
|
msgid "Laptop / PC (💻)"
|
||||||
msgstr "Ноутбук / ПК (💻)"
|
msgstr "Ноутбук / ПК (💻)"
|
||||||
|
|
||||||
|
msgid "Latency"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Latency test failed"
|
msgid "Latency test failed"
|
||||||
msgstr "Проверка задержки не удалась"
|
msgstr "Проверка задержки не удалась"
|
||||||
|
|
||||||
@@ -2627,6 +2690,9 @@ msgstr "Загрузка подключений"
|
|||||||
msgid "Loading service list..."
|
msgid "Loading service list..."
|
||||||
msgstr "Получение списка сервисов..."
|
msgstr "Получение списка сервисов..."
|
||||||
|
|
||||||
|
msgid "Loading versions..."
|
||||||
|
msgstr "Загрузка версий..."
|
||||||
|
|
||||||
msgid "Loading..."
|
msgid "Loading..."
|
||||||
msgstr "Загрузка..."
|
msgstr "Загрузка..."
|
||||||
|
|
||||||
@@ -2636,6 +2702,9 @@ msgstr "Локальный адрес"
|
|||||||
msgid "Log Level"
|
msgid "Log Level"
|
||||||
msgstr "Уровень логирования"
|
msgstr "Уровень логирования"
|
||||||
|
|
||||||
|
msgid "Loss"
|
||||||
|
msgstr "Потери"
|
||||||
|
|
||||||
msgid "LuCI Web UI"
|
msgid "LuCI Web UI"
|
||||||
msgstr "Веб-интерфейс LuCI"
|
msgstr "Веб-интерфейс LuCI"
|
||||||
|
|
||||||
@@ -2681,6 +2750,9 @@ msgstr "Совпадение найдено"
|
|||||||
msgid "Match traffic by packet DSCP mark (assigned in Windows via Policy-Based QoS). Examples: 46 (EF), 0x2e, 34 (AF41)"
|
msgid "Match traffic by packet DSCP mark (assigned in Windows via Policy-Based QoS). Examples: 46 (EF), 0x2e, 34 (AF41)"
|
||||||
msgstr "Сопоставлять трафик по DSCP-метке пакета (назначается в Windows через Policy-Based QoS). Примеры: 46 (EF), 0x2e, 34 (AF41)"
|
msgstr "Сопоставлять трафик по DSCP-метке пакета (назначается в Windows через Policy-Based QoS). Примеры: 46 (EF), 0x2e, 34 (AF41)"
|
||||||
|
|
||||||
|
msgid "Max Handshake Attempts"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Max reconnects per hour before alert (default 10)."
|
msgid "Max reconnects per hour before alert (default 10)."
|
||||||
msgstr "Макс. переподключений в час до оповещения (по умолчанию 10)."
|
msgstr "Макс. переподключений в час до оповещения (по умолчанию 10)."
|
||||||
|
|
||||||
@@ -2828,6 +2900,9 @@ msgstr "Активные устройства в локальной сети н
|
|||||||
msgid "No active routing sections found."
|
msgid "No active routing sections found."
|
||||||
msgstr "Активные секции маршрутизации не найдены."
|
msgstr "Активные секции маршрутизации не найдены."
|
||||||
|
|
||||||
|
msgid "No benchmark data yet. Click \"Start Benchmark\" to begin."
|
||||||
|
msgstr "Нет данных бенчмарка. Нажмите «Начать тест», чтобы запустить проверку."
|
||||||
|
|
||||||
msgid "No benchmark history yet. Run a benchmark to see results here."
|
msgid "No benchmark history yet. Run a benchmark to see results here."
|
||||||
msgstr "История бенчмарков пуста. Запустите бенчмарк, чтобы увидеть результаты здесь."
|
msgstr "История бенчмарков пуста. Запустите бенчмарк, чтобы увидеть результаты здесь."
|
||||||
|
|
||||||
@@ -2900,6 +2975,12 @@ msgstr "Снапшотов пока нет"
|
|||||||
msgid "No strategies match the active filter."
|
msgid "No strategies match the active filter."
|
||||||
msgstr "Нет стратегий, соответствующих выбранному фильтру."
|
msgstr "Нет стратегий, соответствующих выбранному фильтру."
|
||||||
|
|
||||||
|
msgid "No versions found"
|
||||||
|
msgstr "Версии не найдены"
|
||||||
|
|
||||||
|
msgid "No working strategy to apply"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Node list is empty"
|
msgid "Node list is empty"
|
||||||
msgstr "Список узлов пуст"
|
msgstr "Список узлов пуст"
|
||||||
|
|
||||||
@@ -3239,6 +3320,9 @@ msgstr "Предварительно собранный индекс фрагм
|
|||||||
msgid "Pre-download all preset lists"
|
msgid "Pre-download all preset lists"
|
||||||
msgstr "Предзагрузить все предустановленные списки"
|
msgstr "Предзагрузить все предустановленные списки"
|
||||||
|
|
||||||
|
msgid "pre-release"
|
||||||
|
msgstr "пре-релиз"
|
||||||
|
|
||||||
msgid "Pre-shared key"
|
msgid "Pre-shared key"
|
||||||
msgstr "Предварительный общий ключ"
|
msgstr "Предварительный общий ключ"
|
||||||
|
|
||||||
@@ -3266,6 +3350,9 @@ msgstr "Предварительный общий ключ"
|
|||||||
msgid "Prevents multiple reload_firewall calls within 120 seconds to avoid connection drops."
|
msgid "Prevents multiple reload_firewall calls within 120 seconds to avoid connection drops."
|
||||||
msgstr "Предотвращает множественные вызовы reload_firewall в течение 120 секунд для избежания разрыва соединений."
|
msgstr "Предотвращает множественные вызовы reload_firewall в течение 120 секунд для избежания разрыва соединений."
|
||||||
|
|
||||||
|
msgid "Primary DNS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Priority"
|
msgid "Priority"
|
||||||
msgstr "Приоритет"
|
msgstr "Приоритет"
|
||||||
|
|
||||||
@@ -3308,6 +3395,12 @@ msgstr "Защита"
|
|||||||
msgid "Protocol"
|
msgid "Protocol"
|
||||||
msgstr "Протокол"
|
msgstr "Протокол"
|
||||||
|
|
||||||
|
msgid "Protocol version: 2.0 (standard integer headers) or 3.1 (header protection key, padding ranges, advanced timers)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Provider"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Provider Global Default"
|
msgid "Provider Global Default"
|
||||||
msgstr "Глобальные настройки провайдера"
|
msgstr "Глобальные настройки провайдера"
|
||||||
|
|
||||||
@@ -3350,12 +3443,18 @@ msgstr "QUIC (HTTP/3)"
|
|||||||
msgid "RAG Knowledge Base + Live ISP Probe Context"
|
msgid "RAG Knowledge Base + Live ISP Probe Context"
|
||||||
msgstr "База знаний RAG + результаты живого зондирования провайдера"
|
msgstr "База знаний RAG + результаты живого зондирования провайдера"
|
||||||
|
|
||||||
|
msgid "Rating"
|
||||||
|
msgstr "Оценка"
|
||||||
|
|
||||||
msgid "RDP"
|
msgid "RDP"
|
||||||
msgstr "RDP"
|
msgstr "RDP"
|
||||||
|
|
||||||
msgid "Read error"
|
msgid "Read error"
|
||||||
msgstr "Ошибка чтения"
|
msgstr "Ошибка чтения"
|
||||||
|
|
||||||
|
msgid "Ready to benchmark DNS providers"
|
||||||
|
msgstr "Готов к тестированию DNS провайдеров"
|
||||||
|
|
||||||
msgid "Reality fake site"
|
msgid "Reality fake site"
|
||||||
msgstr "Фейковый сайт Reality"
|
msgstr "Фейковый сайт Reality"
|
||||||
|
|
||||||
@@ -3386,6 +3485,12 @@ msgstr "Пересобранный релиз"
|
|||||||
msgid "Recommended"
|
msgid "Recommended"
|
||||||
msgstr "Рекомендовано"
|
msgstr "Рекомендовано"
|
||||||
|
|
||||||
|
msgid "Recommended DNS Configuration"
|
||||||
|
msgstr "Рекомендованная конфигурация DNS"
|
||||||
|
|
||||||
|
msgid "Recommended DNS settings applied successfully and service restarted!"
|
||||||
|
msgstr "Рекомендованные настройки DNS успешно применены, сервис перезапущен!"
|
||||||
|
|
||||||
msgid "Recommended Quick Fixes:"
|
msgid "Recommended Quick Fixes:"
|
||||||
msgstr "Рекомендуемые исправления:"
|
msgstr "Рекомендуемые исправления:"
|
||||||
|
|
||||||
@@ -3419,6 +3524,15 @@ msgstr "Регулярное выражение не должно содержа
|
|||||||
msgid "Reinstall"
|
msgid "Reinstall"
|
||||||
msgstr "Переустановить"
|
msgstr "Переустановить"
|
||||||
|
|
||||||
|
msgid "Reject After Time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Rekey After Time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Rekey Timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Reload now"
|
msgid "Reload now"
|
||||||
msgstr "Перезагрузить сейчас"
|
msgstr "Перезагрузить сейчас"
|
||||||
|
|
||||||
@@ -3938,9 +4052,6 @@ msgstr "Сервисы и доступ"
|
|||||||
msgid "Services are online and ready! Reloading page..."
|
msgid "Services are online and ready! Reloading page..."
|
||||||
msgstr "Службы запущены и готовы к работе! Перезагрузка страницы..."
|
msgstr "Службы запущены и готовы к работе! Перезагрузка страницы..."
|
||||||
|
|
||||||
msgid "Services are online, waiting for full initialization..."
|
|
||||||
msgstr "Сервисы запущены, ожидание полной инициализации..."
|
|
||||||
|
|
||||||
msgid "Services info"
|
msgid "Services info"
|
||||||
msgstr "Информация о сервисах"
|
msgstr "Информация о сервисах"
|
||||||
|
|
||||||
@@ -4037,6 +4148,9 @@ msgstr "Пропущены комментарии/невалидные:"
|
|||||||
msgid "Skipped loopback:"
|
msgid "Skipped loopback:"
|
||||||
msgstr "Пропущены loopback:"
|
msgstr "Пропущены loopback:"
|
||||||
|
|
||||||
|
msgid "SLOW"
|
||||||
|
msgstr "МЕДЛЕННО"
|
||||||
|
|
||||||
msgid "Snapshot name"
|
msgid "Snapshot name"
|
||||||
msgstr "Имя снапшота"
|
msgstr "Имя снапшота"
|
||||||
|
|
||||||
@@ -4136,6 +4250,9 @@ msgstr "Стандартный"
|
|||||||
msgid "Start"
|
msgid "Start"
|
||||||
msgstr "Старт"
|
msgstr "Старт"
|
||||||
|
|
||||||
|
msgid "Start Benchmark"
|
||||||
|
msgstr "Начать тест"
|
||||||
|
|
||||||
msgid "Start bot"
|
msgid "Start bot"
|
||||||
msgstr "Запустить бота"
|
msgstr "Запустить бота"
|
||||||
|
|
||||||
@@ -4151,6 +4268,9 @@ msgstr "Время начала (ЧЧ:ММ)"
|
|||||||
msgid "Start watchdog"
|
msgid "Start watchdog"
|
||||||
msgstr "Запустить watchdog"
|
msgstr "Запустить watchdog"
|
||||||
|
|
||||||
|
msgid "Starting DNS benchmark..."
|
||||||
|
msgstr "Запуск бенчмарка DNS..."
|
||||||
|
|
||||||
msgid "Starting…"
|
msgid "Starting…"
|
||||||
msgstr "Запуск…"
|
msgstr "Запуск…"
|
||||||
|
|
||||||
@@ -4235,6 +4355,9 @@ msgstr "Успех"
|
|||||||
msgid "Successfully imported %d DNS record(s)"
|
msgid "Successfully imported %d DNS record(s)"
|
||||||
msgstr "Успешно импортировано %d DNS-записей"
|
msgstr "Успешно импортировано %d DNS-записей"
|
||||||
|
|
||||||
|
msgid "Successfully updated %d hosts entries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Sun"
|
msgid "Sun"
|
||||||
msgstr "Вс"
|
msgstr "Вс"
|
||||||
|
|
||||||
@@ -4268,9 +4391,15 @@ msgstr "Порядок и видимость вкладок"
|
|||||||
msgid "Table exist"
|
msgid "Table exist"
|
||||||
msgstr "Таблица существует"
|
msgstr "Таблица существует"
|
||||||
|
|
||||||
|
msgid "Tachyon"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Tachyon Core"
|
msgid "Tachyon Core"
|
||||||
msgstr "Ядро Tachyon"
|
msgstr "Ядро Tachyon"
|
||||||
|
|
||||||
|
msgid "Tachyon DNS Benchmark & Auto-Tuning"
|
||||||
|
msgstr "Tachyon: Бенчмарк и автоподбор DNS"
|
||||||
|
|
||||||
msgid "Tachyon Error"
|
msgid "Tachyon Error"
|
||||||
msgstr "Ошибка Tachyon"
|
msgstr "Ошибка Tachyon"
|
||||||
|
|
||||||
@@ -4409,6 +4538,9 @@ msgstr "Тестировать серверы, чьи имена соответ
|
|||||||
msgid "Test Telegram Connection"
|
msgid "Test Telegram Connection"
|
||||||
msgstr "Проверить подключение к Telegram"
|
msgstr "Проверить подключение к Telegram"
|
||||||
|
|
||||||
|
msgid "Testing"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Testing bypass strategies in isolated sandbox..."
|
msgid "Testing bypass strategies in isolated sandbox..."
|
||||||
msgstr "Тестирование стратегий обхода в изолированной песочнице..."
|
msgstr "Тестирование стратегий обхода в изолированной песочнице..."
|
||||||
|
|
||||||
@@ -4502,6 +4634,9 @@ msgstr "Время суток для запуска планового обно
|
|||||||
msgid "Time skew tolerance"
|
msgid "Time skew tolerance"
|
||||||
msgstr "Допуск отклонения времени"
|
msgstr "Допуск отклонения времени"
|
||||||
|
|
||||||
|
msgid "Timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "tiny"
|
msgid "tiny"
|
||||||
msgstr "tiny"
|
msgstr "tiny"
|
||||||
|
|
||||||
@@ -4727,6 +4862,9 @@ msgstr "Хранится до 10 снапшотов; самые старые у
|
|||||||
msgid "Update"
|
msgid "Update"
|
||||||
msgstr "Обновить"
|
msgstr "Обновить"
|
||||||
|
|
||||||
|
msgid "Update failed:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Update is available"
|
msgid "Update is available"
|
||||||
msgstr "Доступно обновление"
|
msgstr "Доступно обновление"
|
||||||
|
|
||||||
@@ -4739,6 +4877,9 @@ msgstr "Доступна новая версия:"
|
|||||||
msgid "Update lists now"
|
msgid "Update lists now"
|
||||||
msgstr "Обновить списки сейчас"
|
msgstr "Обновить списки сейчас"
|
||||||
|
|
||||||
|
msgid "Update Lists Now"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Update subscriptions"
|
msgid "Update subscriptions"
|
||||||
msgstr "Обновить подписки"
|
msgstr "Обновить подписки"
|
||||||
|
|
||||||
@@ -4760,6 +4901,9 @@ msgstr "Обновление режима маршрутизации устро
|
|||||||
msgid "Updating lists..."
|
msgid "Updating lists..."
|
||||||
msgstr "Обновление списков..."
|
msgstr "Обновление списков..."
|
||||||
|
|
||||||
|
msgid "Updating…"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Uplink"
|
msgid "Uplink"
|
||||||
msgstr "Исходящий"
|
msgstr "Исходящий"
|
||||||
|
|
||||||
@@ -4889,6 +5033,9 @@ msgstr "Значение не должно содержать символы у
|
|||||||
msgid "Verifying router and service readiness..."
|
msgid "Verifying router and service readiness..."
|
||||||
msgstr "Проверка готовности роутера и служб..."
|
msgstr "Проверка готовности роутера и служб..."
|
||||||
|
|
||||||
|
msgid "Versions"
|
||||||
|
msgstr "Версии"
|
||||||
|
|
||||||
msgid "Via country.is"
|
msgid "Via country.is"
|
||||||
msgstr "Через country.is"
|
msgstr "Через country.is"
|
||||||
|
|
||||||
@@ -4925,9 +5072,6 @@ msgstr "Токен доступа WARP"
|
|||||||
msgid "WARP Account ID"
|
msgid "WARP Account ID"
|
||||||
msgstr "ID аккаунта WARP"
|
msgstr "ID аккаунта WARP"
|
||||||
|
|
||||||
msgid "WARP Configuration generated and loaded successfully!"
|
|
||||||
msgstr "Конфигурация WARP успешно сгенерирована и загружена!"
|
|
||||||
|
|
||||||
msgid "WARP Generator Proxy Section"
|
msgid "WARP Generator Proxy Section"
|
||||||
msgstr "Секция прокси для генератора WARP"
|
msgstr "Секция прокси для генератора WARP"
|
||||||
|
|
||||||
@@ -4973,6 +5117,9 @@ msgstr "Приватный ключ WireGuard из вашего аккаунта
|
|||||||
msgid "Working"
|
msgid "Working"
|
||||||
msgstr "Рабочих"
|
msgstr "Рабочих"
|
||||||
|
|
||||||
|
msgid "working strategies"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "XHTTP mode"
|
msgid "XHTTP mode"
|
||||||
msgstr "Режим XHTTP"
|
msgstr "Режим XHTTP"
|
||||||
|
|
||||||
@@ -5039,6 +5186,24 @@ msgstr "sing-box outbound для Zapret2 настроен"
|
|||||||
msgid "Zapret2 sing-box outbound is not configured"
|
msgid "Zapret2 sing-box outbound is not configured"
|
||||||
msgstr "sing-box outbound для Zapret2 не настроен"
|
msgstr "sing-box outbound для Zapret2 не настроен"
|
||||||
|
|
||||||
|
msgid "⚡ Quick Benchmark (Presets ~12-14)"
|
||||||
|
msgstr "⚡ Быстрый бенчмарк (Пресеты ~12-14)"
|
||||||
|
|
||||||
|
msgid "🎬 YouTube Suite (Web + 4K Stream)"
|
||||||
|
msgstr "🎬 YouTube Suite (Web + 4K Stream)"
|
||||||
|
|
||||||
|
msgid "💬 Discord Suite (API + WSS + CDN)"
|
||||||
|
msgstr "💬 Discord Suite (API + WSS + CDN)"
|
||||||
|
|
||||||
|
msgid "🔍 Combinatorial Deep Fuzzing (~40-80+)"
|
||||||
|
msgstr "🔍 Комбинаторный глубокий фаззинг (~40-80+)"
|
||||||
|
|
||||||
|
msgid "Services are online, waiting for full initialization..."
|
||||||
|
msgstr "Сервисы запущены, ожидание полной инициализации..."
|
||||||
|
|
||||||
|
msgid "WARP Configuration generated and loaded successfully!"
|
||||||
|
msgstr "Конфигурация WARP успешно сгенерирована и загружена!"
|
||||||
|
|
||||||
msgid "⏹ Stop"
|
msgid "⏹ Stop"
|
||||||
msgstr "⏹ Стоп"
|
msgstr "⏹ Стоп"
|
||||||
|
|
||||||
@@ -5726,18 +5891,6 @@ msgstr "CleanBrowsing (Семейный)"
|
|||||||
msgid "Yandex Safe"
|
msgid "Yandex Safe"
|
||||||
msgstr "Yandex (Безопасный)"
|
msgstr "Yandex (Безопасный)"
|
||||||
|
|
||||||
msgid "Versions"
|
|
||||||
msgstr "Версии"
|
|
||||||
|
|
||||||
msgid "Loading versions..."
|
|
||||||
msgstr "Загрузка версий..."
|
|
||||||
|
|
||||||
msgid "No versions found"
|
|
||||||
msgstr "Версии не найдены"
|
|
||||||
|
|
||||||
msgid "Failed to load versions"
|
|
||||||
msgstr "Не удалось загрузить версии"
|
|
||||||
|
|
||||||
msgid "Installing "
|
msgid "Installing "
|
||||||
msgstr "Установка "
|
msgstr "Установка "
|
||||||
|
|
||||||
@@ -5750,5 +5903,26 @@ msgstr "Ошибка установки: "
|
|||||||
msgid "Installed "
|
msgid "Installed "
|
||||||
msgstr "Установлено "
|
msgstr "Установлено "
|
||||||
|
|
||||||
msgid "pre-release"
|
msgid "AmneziaWG 2.0"
|
||||||
msgstr "пре-релиз"
|
msgstr "AmneziaWG 2.0"
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.0"
|
||||||
|
msgstr "AmneziaWG 3.0"
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1"
|
||||||
|
msgstr "AmneziaWG 3.1"
|
||||||
|
|
||||||
|
msgid "Protocol version: 2.0 (standard headers, WARP compatible), 3.0 (header protection key, padding ranges), or 3.1 (header protection key, padding ranges, advanced timers)"
|
||||||
|
msgstr "Версия протокола: 2.0 (стандартные заголовки, совместимо с WARP), 3.0 (ключ защиты заголовков, диапазоны паддинга), или 3.1 (ключ защиты заголовков, диапазоны паддинга, расширенные таймеры)"
|
||||||
|
|
||||||
|
msgid "AmneziaWG %s configuration generated and loaded successfully!"
|
||||||
|
msgstr "Конфигурация AmneziaWG %s успешно сгенерирована и загружена!"
|
||||||
|
|
||||||
|
msgid "Notice: Cloudflare WARP edge servers only support AmneziaWG 2.0 (standard headers). For Cloudflare WARP, select version 2.0. Versions 3.0 and 3.1 are intended for dedicated AmneziaWG servers."
|
||||||
|
msgstr "Обратите внимание: серверы Cloudflare WARP поддерживают только AmneziaWG 2.0 (стандартные заголовки). Для Cloudflare WARP выберите версию 2.0. Версии 3.0 и 3.1 предназначены для выделенных серверов AmneziaWG."
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.0 / 3.1 header protection key"
|
||||||
|
msgstr "Ключ защиты заголовков AmneziaWG 3.0 / 3.1"
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.0 / 3.1 content padding range, e.g. 38-104"
|
||||||
|
msgstr "Диапазон дополнительного паддинга контента AmneziaWG 3.0 / 3.1, например 38-104"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export function renderDnsBenchmarkModal() {
|
|||||||
'div',
|
'div',
|
||||||
{
|
{
|
||||||
style:
|
style:
|
||||||
'font-size: 13px; font-weight: 500; margin-bottom: 10px; color: var(--text-color, #ccc);',
|
'font-size: 13px; font-weight: 500; margin-bottom: 10px; color: var(--text-color-medium, #6c757d);',
|
||||||
},
|
},
|
||||||
_('Ready to benchmark DNS providers'),
|
_('Ready to benchmark DNS providers'),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1463,19 +1463,6 @@ function renderVersionPickerDropdown(
|
|||||||
container.appendChild(
|
container.appendChild(
|
||||||
E('div', { class: 'tachyon-version-picker__error' }, versionPickerError),
|
E('div', { class: 'tachyon-version-picker__error' }, versionPickerError),
|
||||||
);
|
);
|
||||||
container.appendChild(
|
|
||||||
E(
|
|
||||||
'button',
|
|
||||||
{
|
|
||||||
class: 'cbi-button tachyon-version-picker__close',
|
|
||||||
click: () => {
|
|
||||||
activeVersionPickerComponent = null;
|
|
||||||
renderUpdatesComponents();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_('Close'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1512,20 +1499,6 @@ function renderVersionPickerDropdown(
|
|||||||
}
|
}
|
||||||
|
|
||||||
container.appendChild(list);
|
container.appendChild(list);
|
||||||
container.appendChild(
|
|
||||||
E(
|
|
||||||
'button',
|
|
||||||
{
|
|
||||||
class: 'cbi-button tachyon-version-picker__close',
|
|
||||||
click: () => {
|
|
||||||
activeVersionPickerComponent = null;
|
|
||||||
renderUpdatesComponents();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_('Close'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ export const styles = `
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
border-bottom: 1px solid var(--border-color, rgba(255,255,255,0.12));
|
border-bottom: 1px solid var(--border-color-low, #dee2e6);
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +223,8 @@ export const styles = `
|
|||||||
|
|
||||||
.tachyon-update-modal__component-name {
|
.tachyon-update-modal__component-name {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: var(--text-color-high, #fff);
|
font-weight: bold;
|
||||||
|
color: var(--text-color-high, inherit);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-update-modal__version-badge {
|
.tachyon-update-modal__version-badge {
|
||||||
@@ -231,22 +232,22 @@ export const styles = `
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: var(--background-color-low, rgba(0,0,0,0.1));
|
background: var(--background-color-low, rgba(0, 0, 0, 0.05));
|
||||||
color: var(--text-color-medium, #aaa);
|
color: var(--text-color-high, inherit);
|
||||||
border: 1px solid var(--border-color, rgba(255,255,255,0.1));
|
border: 1px solid var(--border-color-low, #dee2e6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-update-modal__timer-badge {
|
.tachyon-update-modal__timer-badge {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
color: var(--text-color-medium, #888);
|
color: var(--text-color-medium, #6c757d);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-update-modal__success-banner {
|
.tachyon-update-modal__success-banner {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
color: #2ecc71;
|
color: var(--color-green-base, #2ecc71);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +255,7 @@ export const styles = `
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
color: #e74c3c;
|
color: var(--color-red-base, #e74c3c);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +265,7 @@ export const styles = `
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
border-top: 1px solid var(--border-color, rgba(255,255,255,0.12));
|
border-top: 1px solid var(--border-color-low, #dee2e6);
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
@@ -289,6 +290,7 @@ export const styles = `
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
color: var(--text-color-high, inherit);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-update-modal__log-copy {
|
.tachyon-update-modal__log-copy {
|
||||||
@@ -306,9 +308,9 @@ export const styles = `
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: var(--text-color, #ddd);
|
color: var(--text-color-high, #212529);
|
||||||
background: rgba(0, 0, 0, 0.35);
|
background: var(--background-color-low, #f8f9fa);
|
||||||
border: 1px solid var(--border-color, rgba(255,255,255,0.12));
|
border: 1px solid var(--border-color-low, #dee2e6);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
@@ -318,20 +320,20 @@ export const styles = `
|
|||||||
.tachyon-version-picker {
|
.tachyon-version-picker {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border: 1px solid var(--border-color, rgba(255,255,255,0.12));
|
border: 1px solid var(--border-color-low, #dee2e6);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: rgba(0, 0, 0, 0.2);
|
background: var(--background-color-low, #f8f9fa);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__loading,
|
.tachyon-version-picker__loading,
|
||||||
.tachyon-version-picker__error {
|
.tachyon-version-picker__error {
|
||||||
padding: 6px 0;
|
padding: 6px 0;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--text-color, #aaa);
|
color: var(--text-color-medium, #6c757d);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__error {
|
.tachyon-version-picker__error {
|
||||||
color: var(--error-color, #e74c3c);
|
color: var(--color-red-base, #e74c3c);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__list {
|
.tachyon-version-picker__list {
|
||||||
@@ -345,7 +347,7 @@ export const styles = `
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
border-bottom: 1px solid var(--border-color, rgba(255,255,255,0.06));
|
border-bottom: 1px solid var(--border-color-low, #e9ecef);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__item:last-child {
|
.tachyon-version-picker__item:last-child {
|
||||||
@@ -355,24 +357,19 @@ export const styles = `
|
|||||||
.tachyon-version-picker__tag {
|
.tachyon-version-picker__tag {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--text-color, #ddd);
|
color: var(--text-color-high, inherit);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__date {
|
.tachyon-version-picker__date {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: var(--text-color, #aaa);
|
color: var(--text-color-medium, #6c757d);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__prerelease {
|
.tachyon-version-picker__prerelease {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
color: var(--warn-color, #f39c12);
|
color: var(--color-yellow-base, #f39c12);
|
||||||
border: 1px solid var(--warn-color, #f39c12);
|
border: 1px solid var(--color-yellow-base, #f39c12);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
padding: 1px 4px;
|
padding: 1px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__close {
|
|
||||||
margin-top: 8px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
+17
@@ -343,6 +343,7 @@ ASSUME_YES=0
|
|||||||
DRY_RUN=0
|
DRY_RUN=0
|
||||||
VERBOSE=0
|
VERBOSE=0
|
||||||
QUIET=0
|
QUIET=0
|
||||||
|
SKIP_SING_BOX=0
|
||||||
|
|
||||||
TACHYON_RELEASE_JSON=""
|
TACHYON_RELEASE_JSON=""
|
||||||
TACHYON_RELEASE_TAG=""
|
TACHYON_RELEASE_TAG=""
|
||||||
@@ -508,6 +509,7 @@ Options:
|
|||||||
download, install, remove, or modify anything on disk
|
download, install, remove, or modify anything on disk
|
||||||
-v, --verbose Print extra diagnostic detail while installing
|
-v, --verbose Print extra diagnostic detail while installing
|
||||||
-q, --quiet Suppress informational output (errors/warnings still show)
|
-q, --quiet Suppress informational output (errors/warnings still show)
|
||||||
|
--skip-sing-box Skip sing-box installation
|
||||||
--version Print the installer version and exit
|
--version Print the installer version and exit
|
||||||
-h, --help Show this help text and exit
|
-h, --help Show this help text and exit
|
||||||
|
|
||||||
@@ -538,6 +540,9 @@ parse_args() {
|
|||||||
-q|--quiet)
|
-q|--quiet)
|
||||||
QUIET=1
|
QUIET=1
|
||||||
;;
|
;;
|
||||||
|
--skip-sing-box|--no-sing-box)
|
||||||
|
SKIP_SING_BOX=1
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
fail "Unknown installer option: $1 (see --help)"
|
fail "Unknown installer option: $1 (see --help)"
|
||||||
;;
|
;;
|
||||||
@@ -2083,6 +2088,7 @@ installer_text() {
|
|||||||
sing_box_extended_compressed) printf '%s\n' "singbox extended (сжатая UPX версия)" ;;
|
sing_box_extended_compressed) printf '%s\n' "singbox extended (сжатая UPX версия)" ;;
|
||||||
sing_box_tiny) printf '%s\n' "singbox tiny (минимум функций)" ;;
|
sing_box_tiny) printf '%s\n' "singbox tiny (минимум функций)" ;;
|
||||||
sing_box_lx) printf '%s\n' "singbox Leadaxe (lx)" ;;
|
sing_box_lx) printf '%s\n' "singbox Leadaxe (lx)" ;;
|
||||||
|
sing_box_skip) printf '%s\n' "Не устанавливать sing-box (пропустить)" ;;
|
||||||
sing_box_skip_msg) printf '%s\n' "Пропускаю установку sing-box." ;;
|
sing_box_skip_msg) printf '%s\n' "Пропускаю установку sing-box." ;;
|
||||||
installing_singbox_backend) printf '%s\n' "Установка выбранного варианта sing-box..." ;;
|
installing_singbox_backend) printf '%s\n' "Установка выбранного варианта sing-box..." ;;
|
||||||
install_start) printf '%s\n' "=== Начало установки Tachyon ===" ;;
|
install_start) printf '%s\n' "=== Начало установки Tachyon ===" ;;
|
||||||
@@ -2130,6 +2136,7 @@ installer_text() {
|
|||||||
sing_box_extended_compressed) printf '%s\n' "singbox extended (UPX compressed)" ;;
|
sing_box_extended_compressed) printf '%s\n' "singbox extended (UPX compressed)" ;;
|
||||||
sing_box_tiny) printf '%s\n' "singbox tiny (minimal features)" ;;
|
sing_box_tiny) printf '%s\n' "singbox tiny (minimal features)" ;;
|
||||||
sing_box_lx) printf '%s\n' "singbox Leadaxe (lx)" ;;
|
sing_box_lx) printf '%s\n' "singbox Leadaxe (lx)" ;;
|
||||||
|
sing_box_skip) printf '%s\n' "Do not install sing-box (skip)" ;;
|
||||||
sing_box_skip_msg) printf '%s\n' "Skipping sing-box installation." ;;
|
sing_box_skip_msg) printf '%s\n' "Skipping sing-box installation." ;;
|
||||||
installing_singbox_backend) printf '%s\n' "Installing selected sing-box variant..." ;;
|
installing_singbox_backend) printf '%s\n' "Installing selected sing-box variant..." ;;
|
||||||
install_start) printf '%s\n' "=== Starting Tachyon Installation ===" ;;
|
install_start) printf '%s\n' "=== Starting Tachyon Installation ===" ;;
|
||||||
@@ -2324,6 +2331,11 @@ select_sing_box_installation() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$SKIP_SING_BOX" -eq 1 ]; then
|
||||||
|
SING_BOX_INSTALL_VARIANT=""
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$ASSUME_YES" -eq 1 ] || [ ! -t 0 ]; then
|
if [ "$ASSUME_YES" -eq 1 ] || [ ! -t 0 ]; then
|
||||||
SING_BOX_INSTALL_VARIANT="stable"
|
SING_BOX_INSTALL_VARIANT="stable"
|
||||||
msg "$(installer_text sing_box_prompt): $default_choice ($(installer_text sing_box_stable), non-interactive)"
|
msg "$(installer_text sing_box_prompt): $default_choice ($(installer_text sing_box_stable), non-interactive)"
|
||||||
@@ -2337,6 +2349,7 @@ select_sing_box_installation() {
|
|||||||
printf ' 3) %s\n' "$(installer_text sing_box_extended_compressed)"
|
printf ' 3) %s\n' "$(installer_text sing_box_extended_compressed)"
|
||||||
printf ' 4) %s\n' "$(installer_text sing_box_lx)"
|
printf ' 4) %s\n' "$(installer_text sing_box_lx)"
|
||||||
printf ' 5) %s\n' "$(installer_text sing_box_tiny)"
|
printf ' 5) %s\n' "$(installer_text sing_box_tiny)"
|
||||||
|
printf ' 6) %s\n' "$(installer_text sing_box_skip)"
|
||||||
printf '%s [%s]: ' "$(installer_text select)" "$default_choice"
|
printf '%s [%s]: ' "$(installer_text select)" "$default_choice"
|
||||||
read -r answer || return 1
|
read -r answer || return 1
|
||||||
[ -n "$answer" ] || answer="$default_choice"
|
[ -n "$answer" ] || answer="$default_choice"
|
||||||
@@ -2361,6 +2374,10 @@ select_sing_box_installation() {
|
|||||||
SING_BOX_INSTALL_VARIANT="tiny"
|
SING_BOX_INSTALL_VARIANT="tiny"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
if [ "$answer" = "6" ]; then
|
||||||
|
SING_BOX_INSTALL_VARIANT=""
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
warn "$(installer_text invalid_choice)"
|
warn "$(installer_text invalid_choice)"
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -13931,7 +13931,7 @@ function renderDnsBenchmarkModal() {
|
|||||||
const statusLabel = E(
|
const statusLabel = E(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
style: "font-size: 13px; font-weight: 500; margin-bottom: 10px; color: var(--text-color, #ccc);"
|
style: "font-size: 13px; font-weight: 500; margin-bottom: 10px; color: var(--text-color-medium, #6c757d);"
|
||||||
},
|
},
|
||||||
_("Ready to benchmark DNS providers")
|
_("Ready to benchmark DNS providers")
|
||||||
);
|
);
|
||||||
@@ -20457,19 +20457,6 @@ function renderVersionPickerDropdown(component) {
|
|||||||
container.appendChild(
|
container.appendChild(
|
||||||
E("div", { class: "tachyon-version-picker__error" }, versionPickerError)
|
E("div", { class: "tachyon-version-picker__error" }, versionPickerError)
|
||||||
);
|
);
|
||||||
container.appendChild(
|
|
||||||
E(
|
|
||||||
"button",
|
|
||||||
{
|
|
||||||
class: "cbi-button tachyon-version-picker__close",
|
|
||||||
click: () => {
|
|
||||||
activeVersionPickerComponent = null;
|
|
||||||
renderUpdatesComponents();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_("Close")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
const list = E("div", { class: "tachyon-version-picker__list" });
|
const list = E("div", { class: "tachyon-version-picker__list" });
|
||||||
@@ -20504,19 +20491,6 @@ function renderVersionPickerDropdown(component) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
container.appendChild(list);
|
container.appendChild(list);
|
||||||
container.appendChild(
|
|
||||||
E(
|
|
||||||
"button",
|
|
||||||
{
|
|
||||||
class: "cbi-button tachyon-version-picker__close",
|
|
||||||
click: () => {
|
|
||||||
activeVersionPickerComponent = null;
|
|
||||||
renderUpdatesComponents();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_("Close")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
function renderComponentCard(card) {
|
function renderComponentCard(card) {
|
||||||
@@ -21084,7 +21058,7 @@ var styles6 = `
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
border-bottom: 1px solid var(--border-color, rgba(255,255,255,0.12));
|
border-bottom: 1px solid var(--border-color-low, #dee2e6);
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21097,7 +21071,8 @@ var styles6 = `
|
|||||||
|
|
||||||
.tachyon-update-modal__component-name {
|
.tachyon-update-modal__component-name {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: var(--text-color-high, #fff);
|
font-weight: bold;
|
||||||
|
color: var(--text-color-high, inherit);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-update-modal__version-badge {
|
.tachyon-update-modal__version-badge {
|
||||||
@@ -21105,22 +21080,22 @@ var styles6 = `
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: var(--background-color-low, rgba(0,0,0,0.1));
|
background: var(--background-color-low, rgba(0, 0, 0, 0.05));
|
||||||
color: var(--text-color-medium, #aaa);
|
color: var(--text-color-high, inherit);
|
||||||
border: 1px solid var(--border-color, rgba(255,255,255,0.1));
|
border: 1px solid var(--border-color-low, #dee2e6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-update-modal__timer-badge {
|
.tachyon-update-modal__timer-badge {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
color: var(--text-color-medium, #888);
|
color: var(--text-color-medium, #6c757d);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-update-modal__success-banner {
|
.tachyon-update-modal__success-banner {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
color: #2ecc71;
|
color: var(--color-green-base, #2ecc71);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21128,7 +21103,7 @@ var styles6 = `
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
color: #e74c3c;
|
color: var(--color-red-base, #e74c3c);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21138,7 +21113,7 @@ var styles6 = `
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
border-top: 1px solid var(--border-color, rgba(255,255,255,0.12));
|
border-top: 1px solid var(--border-color-low, #dee2e6);
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
@@ -21163,6 +21138,7 @@ var styles6 = `
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
color: var(--text-color-high, inherit);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-update-modal__log-copy {
|
.tachyon-update-modal__log-copy {
|
||||||
@@ -21180,9 +21156,9 @@ var styles6 = `
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: var(--text-color, #ddd);
|
color: var(--text-color-high, #212529);
|
||||||
background: rgba(0, 0, 0, 0.35);
|
background: var(--background-color-low, #f8f9fa);
|
||||||
border: 1px solid var(--border-color, rgba(255,255,255,0.12));
|
border: 1px solid var(--border-color-low, #dee2e6);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
@@ -21192,20 +21168,20 @@ var styles6 = `
|
|||||||
.tachyon-version-picker {
|
.tachyon-version-picker {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border: 1px solid var(--border-color, rgba(255,255,255,0.12));
|
border: 1px solid var(--border-color-low, #dee2e6);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: rgba(0, 0, 0, 0.2);
|
background: var(--background-color-low, #f8f9fa);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__loading,
|
.tachyon-version-picker__loading,
|
||||||
.tachyon-version-picker__error {
|
.tachyon-version-picker__error {
|
||||||
padding: 6px 0;
|
padding: 6px 0;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--text-color, #aaa);
|
color: var(--text-color-medium, #6c757d);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__error {
|
.tachyon-version-picker__error {
|
||||||
color: var(--error-color, #e74c3c);
|
color: var(--color-red-base, #e74c3c);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__list {
|
.tachyon-version-picker__list {
|
||||||
@@ -21219,7 +21195,7 @@ var styles6 = `
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
border-bottom: 1px solid var(--border-color, rgba(255,255,255,0.06));
|
border-bottom: 1px solid var(--border-color-low, #e9ecef);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__item:last-child {
|
.tachyon-version-picker__item:last-child {
|
||||||
@@ -21229,26 +21205,21 @@ var styles6 = `
|
|||||||
.tachyon-version-picker__tag {
|
.tachyon-version-picker__tag {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--text-color, #ddd);
|
color: var(--text-color-high, inherit);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__date {
|
.tachyon-version-picker__date {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: var(--text-color, #aaa);
|
color: var(--text-color-medium, #6c757d);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__prerelease {
|
.tachyon-version-picker__prerelease {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
color: var(--warn-color, #f39c12);
|
color: var(--color-yellow-base, #f39c12);
|
||||||
border: 1px solid var(--warn-color, #f39c12);
|
border: 1px solid var(--color-yellow-base, #f39c12);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
padding: 1px 4px;
|
padding: 1px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tachyon-version-picker__close {
|
|
||||||
margin-top: 8px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// src/tachyon/tabs/updates/index.ts
|
// src/tachyon/tabs/updates/index.ts
|
||||||
|
|||||||
@@ -8412,6 +8412,25 @@ function createSectionContent(section) {
|
|||||||
: _("Use sing-box duration format like 1d, 12h or 6h");
|
: _("Use sing-box duration format like 1d, 12h or 6h");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Keep tag chains (<b 0x..>, <t>, <r..>, etc.) and plain hex intact
|
||||||
|
// Normalizes plain hex to <b 0xHEX> and auto-heals previously truncated tags
|
||||||
|
const cleanAwgPayload = (v) => {
|
||||||
|
if (typeof v !== "string") return "";
|
||||||
|
let s = v.trim();
|
||||||
|
if (!s || s === "0") return s;
|
||||||
|
// Heal previously truncated opening binary tag if missing (e.g. 729cd...><t>...)
|
||||||
|
if (/^[0-9a-fA-F]+><[^<>]+>/.test(s)) s = "<b 0x" + s;
|
||||||
|
// Heal previously truncated closing bracket if missing (e.g. ...<rd 5)
|
||||||
|
if (/<[^<>]+$/.test(s)) s += ">";
|
||||||
|
// If plain hex (classic AWG payload or stripped <b 0x..>), normalize to <b 0xHEX>
|
||||||
|
const plainHex = s.replace(/^0x/i, "");
|
||||||
|
if (/^[0-9a-fA-F]+$/.test(plainHex) && plainHex.length >= 2) {
|
||||||
|
const padded = plainHex.length % 2 !== 0 ? plainHex + "0" : plainHex;
|
||||||
|
return "<b 0x" + padded.toLowerCase() + ">";
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
o = section.taboption(
|
o = section.taboption(
|
||||||
"settings",
|
"settings",
|
||||||
form.Button,
|
form.Button,
|
||||||
@@ -8503,9 +8522,26 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
const resetAfter = (ms) => setTimeout(() => setState("", origText), ms);
|
const resetAfter = (ms) => setTimeout(() => setState("", origText), ms);
|
||||||
|
|
||||||
|
const getControlWidget = (opt) => {
|
||||||
|
const widget = document.getElementById(
|
||||||
|
`widget.cbid.${UCI_PACKAGE}.${section_id}.${opt}`,
|
||||||
|
);
|
||||||
|
if (!widget) return null;
|
||||||
|
if (/^(INPUT|SELECT|TEXTAREA)$/.test(widget.tagName)) return widget;
|
||||||
|
return widget.querySelector(
|
||||||
|
"input:not([type='hidden']), select, textarea",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const verWidget = getControlWidget("awg_version");
|
||||||
|
const currentVersion =
|
||||||
|
(verWidget ? verWidget.value : null) ||
|
||||||
|
uci.get(UCI_PACKAGE, section_id, "awg_version") ||
|
||||||
|
"2.0";
|
||||||
|
|
||||||
setState("loading", _("Generating…"));
|
setState("loading", _("Generating…"));
|
||||||
|
|
||||||
fs.exec("/usr/bin/tachyon", ["generate_warp"])
|
fs.exec("/usr/bin/tachyon", ["generate_warp", "", "2.0"])
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
if (!response || (response.code ?? 0) !== 0 || !response.stdout) {
|
if (!response || (response.code ?? 0) !== 0 || !response.stdout) {
|
||||||
setState("error", _("Error"));
|
setState("error", _("Error"));
|
||||||
@@ -8533,25 +8569,6 @@ function createSectionContent(section) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getControlWidget = (opt) => {
|
|
||||||
const widget = document.getElementById(
|
|
||||||
`widget.cbid.${UCI_PACKAGE}.${section_id}.${opt}`,
|
|
||||||
);
|
|
||||||
if (!widget) return null;
|
|
||||||
if (/^(INPUT|SELECT|TEXTAREA)$/.test(widget.tagName)) return widget;
|
|
||||||
return widget.querySelector(
|
|
||||||
"input:not([type='hidden']), select, textarea",
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const stripUciBinary = (val) => {
|
|
||||||
if (typeof val !== "string") return val;
|
|
||||||
return val
|
|
||||||
.replace(/<b 0x/g, "")
|
|
||||||
.replace(/>/g, "")
|
|
||||||
.replace(/\s/g, "");
|
|
||||||
};
|
|
||||||
|
|
||||||
const setWidgetValue = (opt, val) => {
|
const setWidgetValue = (opt, val) => {
|
||||||
const widget = getControlWidget(opt);
|
const widget = getControlWidget(opt);
|
||||||
if (widget) {
|
if (widget) {
|
||||||
@@ -8562,6 +8579,8 @@ function createSectionContent(section) {
|
|||||||
uci.set(UCI_PACKAGE, section_id, opt, val);
|
uci.set(UCI_PACKAGE, section_id, opt, val);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const genVer = data.awg_version || "2.0";
|
||||||
|
|
||||||
setWidgetValue("awg_local_address", data.local_address);
|
setWidgetValue("awg_local_address", data.local_address);
|
||||||
setWidgetValue("awg_private_key", data.private_key);
|
setWidgetValue("awg_private_key", data.private_key);
|
||||||
setWidgetValue("awg_peer_public_key", data.peer_public_key);
|
setWidgetValue("awg_peer_public_key", data.peer_public_key);
|
||||||
@@ -8578,17 +8597,39 @@ function createSectionContent(section) {
|
|||||||
setWidgetValue("awg_h4", `${data.awg_h4}`);
|
setWidgetValue("awg_h4", `${data.awg_h4}`);
|
||||||
setWidgetValue("awg_s3", `${data.awg_s3}`);
|
setWidgetValue("awg_s3", `${data.awg_s3}`);
|
||||||
setWidgetValue("awg_s4", `${data.awg_s4}`);
|
setWidgetValue("awg_s4", `${data.awg_s4}`);
|
||||||
setWidgetValue("awg_i1", stripUciBinary(data.awg_i1));
|
setWidgetValue("awg_i1", cleanAwgPayload(data.awg_i1));
|
||||||
setWidgetValue("awg_i2", stripUciBinary(data.awg_i2));
|
setWidgetValue("awg_i2", cleanAwgPayload(data.awg_i2));
|
||||||
setWidgetValue("awg_i3", stripUciBinary(data.awg_i3));
|
setWidgetValue("awg_i3", cleanAwgPayload(data.awg_i3));
|
||||||
setWidgetValue("awg_i4", stripUciBinary(data.awg_i4));
|
setWidgetValue("awg_i4", cleanAwgPayload(data.awg_i4));
|
||||||
setWidgetValue("awg_i5", stripUciBinary(data.awg_i5));
|
setWidgetValue("awg_i5", cleanAwgPayload(data.awg_i5));
|
||||||
|
|
||||||
|
setWidgetValue("awg_version", genVer);
|
||||||
|
|
||||||
|
// Clear 3.x specific options when generating WARP (Cloudflare only supports AWG 2.0)
|
||||||
|
setWidgetValue("awg_header_protection_key", "");
|
||||||
|
setWidgetValue("awg_content_padding_addition", "");
|
||||||
|
setWidgetValue("awg_rekey_after_time", "");
|
||||||
|
setWidgetValue("awg_rekey_timeout", "");
|
||||||
|
setWidgetValue("awg_reject_after_time", "");
|
||||||
|
setWidgetValue("awg_keepalive_timeout", "");
|
||||||
|
setWidgetValue("awg_max_handshake_attempts", "");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_header_protection_key");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_content_padding_addition");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_reject_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_keepalive_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_max_handshake_attempts");
|
||||||
|
|
||||||
setState("success", _("Generated!"));
|
setState("success", _("Generated!"));
|
||||||
resetAfter(2500);
|
resetAfter(2500);
|
||||||
|
let successMsg = _("AmneziaWG (Cloudflare WARP) configuration generated and loaded successfully!");
|
||||||
|
if (currentVersion !== "2.0") {
|
||||||
|
successMsg += "\n\n" + _("Notice: Cloudflare WARP edge servers only support AmneziaWG 2.0 (WireGuard). The profile has been automatically set to 2.0 so the connection works properly. Versions 3.0 and 3.1 require an AmneziaWG server via 'Import .conf'.");
|
||||||
|
}
|
||||||
showStatusModal(
|
showStatusModal(
|
||||||
_("Success"),
|
_("Success"),
|
||||||
_("WARP Configuration generated and loaded successfully!"),
|
successMsg,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -8630,15 +8671,24 @@ function createSectionContent(section) {
|
|||||||
let cur = null;
|
let cur = null;
|
||||||
for (const raw of text.split(/\r?\n/)) {
|
for (const raw of text.split(/\r?\n/)) {
|
||||||
const line = raw.trim();
|
const line = raw.trim();
|
||||||
if (!line || line.startsWith("#")) continue;
|
if (!line || line.startsWith("#") || line.startsWith(";")) continue;
|
||||||
const sm = line.match(/^\[(\w+)\]$/);
|
const sm = line.match(/^\[([^\]]+)\]$/);
|
||||||
if (sm) {
|
if (sm) {
|
||||||
cur = sm[1].toLowerCase();
|
cur = sm[1].trim().toLowerCase();
|
||||||
out[cur] = out[cur] || {};
|
out[cur] = out[cur] || {};
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const kv = line.match(/^(\w+)\s*=\s*(.+)$/);
|
const kv = line.match(/^([^=]+)\s*=\s*(.+)$/);
|
||||||
if (kv && cur) out[cur][kv[1]] = kv[2].trim();
|
if (kv && cur) {
|
||||||
|
const key = kv[1].trim();
|
||||||
|
let val = kv[2].trim();
|
||||||
|
// Strip inline comments if not inside payload tags
|
||||||
|
if (!val.startsWith("<")) {
|
||||||
|
const commentIdx = val.search(/[#;]/);
|
||||||
|
if (commentIdx >= 0) val = val.slice(0, commentIdx).trim();
|
||||||
|
}
|
||||||
|
out[cur][key] = val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
@@ -8654,22 +8704,16 @@ function createSectionContent(section) {
|
|||||||
)
|
)
|
||||||
.join(" ");
|
.join(" ");
|
||||||
|
|
||||||
// Strip UCI binary literal format: <b 0xHEX> → HEX
|
// Use shared payload cleaner for tag chains and hex normalization
|
||||||
const stripBin = (v) =>
|
const cleanPayload = cleanAwgPayload;
|
||||||
typeof v === "string"
|
|
||||||
? v
|
|
||||||
.replace(/^<b\s+0x/, "")
|
|
||||||
.replace(/>$/, "")
|
|
||||||
.trim()
|
|
||||||
: "";
|
|
||||||
|
|
||||||
// Write value into a form widget and the UCI cache
|
// Write value into a form widget and the UCI cache
|
||||||
const setVal = (opt, val) => {
|
const setVal = (opt, val) => {
|
||||||
if (val === undefined || val === null) return;
|
if (val === undefined || val === null) return;
|
||||||
const str = String(val);
|
const str = String(val);
|
||||||
const el = document.getElementById(
|
const el =
|
||||||
`widget.cbid.${UCI_PACKAGE}.${section_id}.${opt}`,
|
document.getElementById(`widget.cbid.${UCI_PACKAGE}.${section_id}.${opt}`) ||
|
||||||
);
|
document.getElementById(`cbid.${UCI_PACKAGE}.${section_id}.${opt}`);
|
||||||
const w =
|
const w =
|
||||||
el &&
|
el &&
|
||||||
(/^(INPUT|SELECT|TEXTAREA)$/.test(el.tagName)
|
(/^(INPUT|SELECT|TEXTAREA)$/.test(el.tagName)
|
||||||
@@ -8743,42 +8787,148 @@ function createSectionContent(section) {
|
|||||||
const iface = cfg.interface || {};
|
const iface = cfg.interface || {};
|
||||||
const peer = cfg.peer || {};
|
const peer = cfg.peer || {};
|
||||||
|
|
||||||
// --- [Interface] ---
|
// Case-insensitive lookup across [Interface] and [Peer]
|
||||||
if (iface.Address)
|
const getConfVal = (k) => {
|
||||||
setVal("awg_local_address", normalizeAddr(iface.Address));
|
const lk = k.toLowerCase();
|
||||||
if (iface.PrivateKey) setVal("awg_private_key", iface.PrivateKey);
|
for (const s of [iface, peer]) {
|
||||||
if (iface.MTU !== undefined) setVal("awg_mtu", iface.MTU);
|
if (!s) continue;
|
||||||
if (peer.PersistentKeepalive)
|
for (const key in s) {
|
||||||
setVal("awg_keepalive", peer.PersistentKeepalive);
|
if (key.toLowerCase() === lk) return s[key];
|
||||||
if (iface.Jc !== undefined) setVal("awg_jc", iface.Jc);
|
}
|
||||||
if (iface.Jmin !== undefined) setVal("awg_jmin", iface.Jmin);
|
}
|
||||||
if (iface.Jmax !== undefined) setVal("awg_jmax", iface.Jmax);
|
return undefined;
|
||||||
if (iface.S1 !== undefined) setVal("awg_s1", iface.S1);
|
};
|
||||||
if (iface.S2 !== undefined) setVal("awg_s2", iface.S2);
|
|
||||||
if (iface.S3 !== undefined) setVal("awg_s3", iface.S3);
|
// --- [Interface] / [Peer] ---
|
||||||
if (iface.S4 !== undefined) setVal("awg_s4", iface.S4);
|
const addr = getConfVal("Address") || getConfVal("awg_local_address");
|
||||||
if (iface.H1 !== undefined) setVal("awg_h1", iface.H1);
|
if (addr) setVal("awg_local_address", normalizeAddr(addr));
|
||||||
if (iface.H2 !== undefined) setVal("awg_h2", iface.H2);
|
|
||||||
if (iface.H3 !== undefined) setVal("awg_h3", iface.H3);
|
const priv = getConfVal("PrivateKey") || getConfVal("awg_private_key");
|
||||||
if (iface.H4 !== undefined) setVal("awg_h4", iface.H4);
|
if (priv) setVal("awg_private_key", priv);
|
||||||
if (iface.I1) setVal("awg_i1", stripBin(iface.I1));
|
|
||||||
if (iface.I2) setVal("awg_i2", stripBin(iface.I2));
|
const mtu = getConfVal("MTU");
|
||||||
if (iface.I3) setVal("awg_i3", stripBin(iface.I3));
|
if (mtu !== undefined) setVal("awg_mtu", mtu);
|
||||||
if (iface.I4) setVal("awg_i4", stripBin(iface.I4));
|
|
||||||
if (iface.I5) setVal("awg_i5", stripBin(iface.I5));
|
const keepalive = getConfVal("PersistentKeepalive") || getConfVal("Keepalive");
|
||||||
if (iface.J1) setVal("awg_j1", stripBin(iface.J1));
|
if (keepalive !== undefined) setVal("awg_keepalive", keepalive);
|
||||||
if (iface.J2) setVal("awg_j2", stripBin(iface.J2));
|
|
||||||
if (iface.J3) setVal("awg_j3", stripBin(iface.J3));
|
const jc = getConfVal("Jc");
|
||||||
if (iface.Itime !== undefined) setVal("awg_itime", iface.Itime);
|
if (jc !== undefined) setVal("awg_jc", jc);
|
||||||
|
|
||||||
|
const jmin = getConfVal("Jmin");
|
||||||
|
if (jmin !== undefined) setVal("awg_jmin", jmin);
|
||||||
|
|
||||||
|
const jmax = getConfVal("Jmax");
|
||||||
|
if (jmax !== undefined) setVal("awg_jmax", jmax);
|
||||||
|
|
||||||
|
const s1 = getConfVal("S1");
|
||||||
|
if (s1 !== undefined) setVal("awg_s1", s1);
|
||||||
|
|
||||||
|
const s2 = getConfVal("S2");
|
||||||
|
if (s2 !== undefined) setVal("awg_s2", s2);
|
||||||
|
|
||||||
|
const s3 = getConfVal("S3");
|
||||||
|
if (s3 !== undefined) setVal("awg_s3", s3);
|
||||||
|
|
||||||
|
const s4 = getConfVal("S4");
|
||||||
|
if (s4 !== undefined) setVal("awg_s4", s4);
|
||||||
|
|
||||||
|
const h1 = getConfVal("H1");
|
||||||
|
if (h1 !== undefined) setVal("awg_h1", h1);
|
||||||
|
|
||||||
|
const h2 = getConfVal("H2");
|
||||||
|
if (h2 !== undefined) setVal("awg_h2", h2);
|
||||||
|
|
||||||
|
const h3 = getConfVal("H3");
|
||||||
|
if (h3 !== undefined) setVal("awg_h3", h3);
|
||||||
|
|
||||||
|
const h4 = getConfVal("H4");
|
||||||
|
if (h4 !== undefined) setVal("awg_h4", h4);
|
||||||
|
|
||||||
|
const i1 = getConfVal("I1");
|
||||||
|
if (i1) setVal("awg_i1", cleanPayload(i1));
|
||||||
|
|
||||||
|
const i2 = getConfVal("I2");
|
||||||
|
if (i2) setVal("awg_i2", cleanPayload(i2));
|
||||||
|
|
||||||
|
const i3 = getConfVal("I3");
|
||||||
|
if (i3) setVal("awg_i3", cleanPayload(i3));
|
||||||
|
|
||||||
|
const i4 = getConfVal("I4");
|
||||||
|
if (i4) setVal("awg_i4", cleanPayload(i4));
|
||||||
|
|
||||||
|
const i5 = getConfVal("I5");
|
||||||
|
if (i5) setVal("awg_i5", cleanPayload(i5));
|
||||||
|
|
||||||
|
const j1 = getConfVal("J1");
|
||||||
|
if (j1) setVal("awg_j1", cleanPayload(j1));
|
||||||
|
|
||||||
|
const j2 = getConfVal("J2");
|
||||||
|
if (j2) setVal("awg_j2", cleanPayload(j2));
|
||||||
|
|
||||||
|
const j3 = getConfVal("J3");
|
||||||
|
if (j3) setVal("awg_j3", cleanPayload(j3));
|
||||||
|
|
||||||
|
const itime = getConfVal("Itime");
|
||||||
|
if (itime !== undefined) setVal("awg_itime", itime);
|
||||||
|
|
||||||
|
// --- AmneziaWG version detection and parameters ---
|
||||||
|
const hpk = getConfVal("HeaderProtectionKey") || "";
|
||||||
|
const cpa = getConfVal("ContentPaddingAddition") || "";
|
||||||
|
const rka = getConfVal("RekeyAfterTime") || "";
|
||||||
|
const rkt = getConfVal("RekeyTimeout") || "";
|
||||||
|
const rja = getConfVal("RejectAfterTime") || "";
|
||||||
|
const kpt = getConfVal("KeepaliveTimeout") || "";
|
||||||
|
const mha = getConfVal("MaxHandshakeAttempts") || "";
|
||||||
|
|
||||||
|
const isV31 = !!(rka || rkt || rja || kpt || mha);
|
||||||
|
const isV30 = !isV31 && !!(hpk || cpa);
|
||||||
|
const detectedVersion = isV31 ? "3.1" : (isV30 ? "3.0" : "2.0");
|
||||||
|
|
||||||
|
setVal("awg_version", detectedVersion);
|
||||||
|
|
||||||
|
if (isV31 || isV30) {
|
||||||
|
setVal("awg_header_protection_key", hpk);
|
||||||
|
setVal("awg_content_padding_addition", cpa);
|
||||||
|
} else {
|
||||||
|
setVal("awg_header_protection_key", "");
|
||||||
|
setVal("awg_content_padding_addition", "");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_header_protection_key");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_content_padding_addition");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isV31) {
|
||||||
|
setVal("awg_rekey_after_time", rka);
|
||||||
|
setVal("awg_rekey_timeout", rkt);
|
||||||
|
setVal("awg_reject_after_time", rja);
|
||||||
|
setVal("awg_keepalive_timeout", kpt);
|
||||||
|
setVal("awg_max_handshake_attempts", mha);
|
||||||
|
} else {
|
||||||
|
setVal("awg_rekey_after_time", "");
|
||||||
|
setVal("awg_rekey_timeout", "");
|
||||||
|
setVal("awg_reject_after_time", "");
|
||||||
|
setVal("awg_keepalive_timeout", "");
|
||||||
|
setVal("awg_max_handshake_attempts", "");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_reject_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_keepalive_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_max_handshake_attempts");
|
||||||
|
}
|
||||||
|
|
||||||
// --- [Peer] ---
|
// --- [Peer] ---
|
||||||
if (peer.PublicKey) setVal("awg_peer_public_key", peer.PublicKey);
|
const pub = getConfVal("PublicKey") || getConfVal("awg_peer_public_key");
|
||||||
if (peer.PresharedKey) setVal("awg_preshared_key", peer.PresharedKey);
|
if (pub) setVal("awg_peer_public_key", pub);
|
||||||
if (peer.Endpoint) {
|
|
||||||
const i = peer.Endpoint.lastIndexOf(":");
|
const psk = getConfVal("PresharedKey") || getConfVal("awg_preshared_key");
|
||||||
|
if (psk) setVal("awg_preshared_key", psk);
|
||||||
|
|
||||||
|
const ep = getConfVal("Endpoint");
|
||||||
|
if (ep) {
|
||||||
|
const i = ep.lastIndexOf(":");
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
setVal("awg_server_address", peer.Endpoint.slice(0, i));
|
setVal("awg_server_address", ep.slice(0, i));
|
||||||
setVal("awg_server_port", peer.Endpoint.slice(i + 1));
|
setVal("awg_server_port", ep.slice(i + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8889,6 +9039,40 @@ function createSectionContent(section) {
|
|||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.depends("action", "awg");
|
o.depends("action", "awg");
|
||||||
|
|
||||||
|
o = section.taboption(
|
||||||
|
"settings",
|
||||||
|
form.ListValue,
|
||||||
|
"awg_version",
|
||||||
|
_("AmneziaWG Version"),
|
||||||
|
_("Protocol version: 2.0 (standard headers, WARP compatible), 3.0 (header protection key, padding ranges), or 3.1 (header protection key, padding ranges, advanced timers)"),
|
||||||
|
);
|
||||||
|
o.modalonly = true;
|
||||||
|
o.rmempty = false;
|
||||||
|
o.default = "2.0";
|
||||||
|
o.value("2.0", "AmneziaWG 2.0");
|
||||||
|
o.value("3.0", "AmneziaWG 3.0");
|
||||||
|
o.value("3.1", "AmneziaWG 3.1");
|
||||||
|
o.depends("action", "awg");
|
||||||
|
o.write = function (section_id, formvalue) {
|
||||||
|
if (formvalue === "2.0") {
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_header_protection_key");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_content_padding_addition");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_reject_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_keepalive_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_max_handshake_attempts");
|
||||||
|
} else if (formvalue === "3.0") {
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_reject_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_keepalive_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_max_handshake_attempts");
|
||||||
|
}
|
||||||
|
return uci.set(UCI_PACKAGE, section_id, "awg_version", formvalue);
|
||||||
|
};
|
||||||
|
|
||||||
// ── AmneziaWG obfuscation parameters (NATIVE LUCI CBI STYLE) ──────────────
|
// ── AmneziaWG obfuscation parameters (NATIVE LUCI CBI STYLE) ──────────────
|
||||||
const addAwgParam = (name, title, desc, def) => {
|
const addAwgParam = (name, title, desc, def) => {
|
||||||
let opt = section.taboption("settings", form.Value, name, title, desc);
|
let opt = section.taboption("settings", form.Value, name, title, desc);
|
||||||
@@ -8910,11 +9094,55 @@ function createSectionContent(section) {
|
|||||||
addAwgParam("awg_h2", _("Underload Packet Magic Header (H2)"), "", "2");
|
addAwgParam("awg_h2", _("Underload Packet Magic Header (H2)"), "", "2");
|
||||||
addAwgParam("awg_h3", _("Underload Packet Magic Header (H3)"), "", "3");
|
addAwgParam("awg_h3", _("Underload Packet Magic Header (H3)"), "", "3");
|
||||||
addAwgParam("awg_h4", _("Underload Packet Magic Header (H4)"), "", "4");
|
addAwgParam("awg_h4", _("Underload Packet Magic Header (H4)"), "", "4");
|
||||||
addAwgParam("awg_i1", _("Init Packet Payload (I1)"), "", "0");
|
const addAwgPayloadParam = (name, title, desc, def) => {
|
||||||
addAwgParam("awg_i2", _("Init Packet Payload (I2)"), "", "0");
|
let opt = section.taboption("settings", form.Value, name, title, desc);
|
||||||
addAwgParam("awg_i3", _("Init Packet Payload (I3)"), "", "0");
|
opt.modalonly = true;
|
||||||
addAwgParam("awg_i4", _("Init Packet Payload (I4)"), "", "0");
|
opt.rmempty = false;
|
||||||
addAwgParam("awg_i5", _("Init Packet Payload (I5)"), "", "0");
|
opt.default = def;
|
||||||
|
opt.depends("action", "awg");
|
||||||
|
opt.cfgvalue = function (section_id) {
|
||||||
|
let val = uci.get(UCI_PACKAGE, section_id, name);
|
||||||
|
if (val === undefined || val === null || val === "") return def;
|
||||||
|
return cleanAwgPayload(String(val));
|
||||||
|
};
|
||||||
|
opt.write = function (section_id, formvalue) {
|
||||||
|
return uci.set(UCI_PACKAGE, section_id, name, cleanAwgPayload(formvalue));
|
||||||
|
};
|
||||||
|
return opt;
|
||||||
|
};
|
||||||
|
|
||||||
|
addAwgPayloadParam("awg_i1", _("Init Packet Payload (I1)"), "", "0");
|
||||||
|
addAwgPayloadParam("awg_i2", _("Init Packet Payload (I2)"), "", "0");
|
||||||
|
addAwgPayloadParam("awg_i3", _("Init Packet Payload (I3)"), "", "0");
|
||||||
|
addAwgPayloadParam("awg_i4", _("Init Packet Payload (I4)"), "", "0");
|
||||||
|
addAwgPayloadParam("awg_i5", _("Init Packet Payload (I5)"), "", "0");
|
||||||
|
|
||||||
|
// ── AmneziaWG 3.0 & 3.1 Advanced Parameters ───────────────────────────────
|
||||||
|
const addAwgV3Param = (name, title, desc) => {
|
||||||
|
let opt = section.taboption("settings", form.Value, name, title, desc);
|
||||||
|
opt.modalonly = true;
|
||||||
|
opt.rmempty = true;
|
||||||
|
opt.depends({ action: "awg", awg_version: "3.0" });
|
||||||
|
opt.depends({ action: "awg", awg_version: "3.1" });
|
||||||
|
return opt;
|
||||||
|
};
|
||||||
|
|
||||||
|
const addAwgV31Param = (name, title, desc) => {
|
||||||
|
let opt = section.taboption("settings", form.Value, name, title, desc);
|
||||||
|
opt.modalonly = true;
|
||||||
|
opt.rmempty = true;
|
||||||
|
opt.depends({ action: "awg", awg_version: "3.1" });
|
||||||
|
return opt;
|
||||||
|
};
|
||||||
|
|
||||||
|
addAwgV3Param("awg_header_protection_key", _("Header Protection Key"), _("AmneziaWG 3.0 / 3.1 header protection key"));
|
||||||
|
addAwgV3Param("awg_content_padding_addition", _("Content Padding Addition"), _("AmneziaWG 3.0 / 3.1 content padding range, e.g. 38-104"));
|
||||||
|
addAwgV31Param("awg_rekey_after_time", _("Rekey After Time"), _("AmneziaWG 3.1 rekey after time"));
|
||||||
|
addAwgV31Param("awg_rekey_timeout", _("Rekey Timeout"), _("AmneziaWG 3.1 rekey timeout"));
|
||||||
|
addAwgV31Param("awg_reject_after_time", _("Reject After Time"), _("AmneziaWG 3.1 reject after time"));
|
||||||
|
addAwgV31Param("awg_keepalive_timeout", _("Keepalive Timeout"), _("AmneziaWG 3.1 keepalive timeout"));
|
||||||
|
addAwgV31Param("awg_max_handshake_attempts", _("Max Handshake Attempts"), _("AmneziaWG 3.1 max handshake attempts"));
|
||||||
|
|
||||||
|
|
||||||
// ── WARP (Cloudflare WARP via sing-box-extended) ──────────────────────────
|
// ── WARP (Cloudflare WARP via sing-box-extended) ──────────────────────────
|
||||||
|
|
||||||
|
|||||||
@@ -1466,6 +1466,26 @@ function buildAwgClientConfig(sectionId) {
|
|||||||
if (j3) conf += `J3 = ${j3}\n`;
|
if (j3) conf += `J3 = ${j3}\n`;
|
||||||
if (itime) conf += `Itime = ${itime}\n`;
|
if (itime) conf += `Itime = ${itime}\n`;
|
||||||
|
|
||||||
|
const awgVer = uci.get(UCI_PACKAGE, sectionId, "awg_version") || "2.0";
|
||||||
|
if (awgVer === "3.0" || awgVer === "3.1") {
|
||||||
|
const hpk = uci.get(UCI_PACKAGE, sectionId, "awg_header_protection_key") || "";
|
||||||
|
const cpa = uci.get(UCI_PACKAGE, sectionId, "awg_content_padding_addition") || "";
|
||||||
|
if (hpk) conf += `HeaderProtectionKey = ${hpk}\n`;
|
||||||
|
if (cpa) conf += `ContentPaddingAddition = ${cpa}\n`;
|
||||||
|
}
|
||||||
|
if (awgVer === "3.1") {
|
||||||
|
const rka = uci.get(UCI_PACKAGE, sectionId, "awg_rekey_after_time") || "";
|
||||||
|
const rkt = uci.get(UCI_PACKAGE, sectionId, "awg_rekey_timeout") || "";
|
||||||
|
const rja = uci.get(UCI_PACKAGE, sectionId, "awg_reject_after_time") || "";
|
||||||
|
const kpt = uci.get(UCI_PACKAGE, sectionId, "awg_keepalive_timeout") || "";
|
||||||
|
const mha = uci.get(UCI_PACKAGE, sectionId, "awg_max_handshake_attempts") || "";
|
||||||
|
if (rka) conf += `RekeyAfterTime = ${rka}\n`;
|
||||||
|
if (rkt) conf += `RekeyTimeout = ${rkt}\n`;
|
||||||
|
if (rja) conf += `RejectAfterTime = ${rja}\n`;
|
||||||
|
if (kpt) conf += `KeepaliveTimeout = ${kpt}\n`;
|
||||||
|
if (mha) conf += `MaxHandshakeAttempts = ${mha}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
conf += `\n[Peer]\nPublicKey = ${serverPublicKey}\nEndpoint = ${host}:${port}\nAllowedIPs = 0.0.0.0/0, ::/0\nPersistentKeepalive = ${keepalive}\n`;
|
conf += `\n[Peer]\nPublicKey = ${serverPublicKey}\nEndpoint = ${host}:${port}\nAllowedIPs = 0.0.0.0/0, ::/0\nPersistentKeepalive = ${keepalive}\n`;
|
||||||
if (presharedKey) conf += `PresharedKey = ${presharedKey}\n`;
|
if (presharedKey) conf += `PresharedKey = ${presharedKey}\n`;
|
||||||
|
|
||||||
@@ -3446,6 +3466,51 @@ function createServerContent(section, options = {}) {
|
|||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.depends("protocol", "awg");
|
o.depends("protocol", "awg");
|
||||||
|
|
||||||
|
o = section.option(
|
||||||
|
form.ListValue,
|
||||||
|
"awg_version",
|
||||||
|
_("AmneziaWG Version"),
|
||||||
|
_("Protocol version: 2.0 (standard integer headers) or 3.1 (header protection key, padding ranges, advanced timers)"),
|
||||||
|
);
|
||||||
|
o.modalonly = true;
|
||||||
|
o.rmempty = false;
|
||||||
|
o.default = "2.0";
|
||||||
|
o.value("2.0", "AmneziaWG 2.0");
|
||||||
|
o.value("3.0", "AmneziaWG 3.0");
|
||||||
|
o.value("3.1", "AmneziaWG 3.1");
|
||||||
|
o.depends("protocol", "awg");
|
||||||
|
o.write = function (section_id, formvalue) {
|
||||||
|
if (formvalue === "2.0") {
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_header_protection_key");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_content_padding_addition");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_reject_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_keepalive_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_max_handshake_attempts");
|
||||||
|
} else if (formvalue === "3.0") {
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_rekey_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_reject_after_time");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_keepalive_timeout");
|
||||||
|
uci.unset(UCI_PACKAGE, section_id, "awg_max_handshake_attempts");
|
||||||
|
}
|
||||||
|
return uci.set(UCI_PACKAGE, section_id, "awg_version", formvalue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const awgV3ParamNames = [
|
||||||
|
"awg_header_protection_key",
|
||||||
|
"awg_content_padding_addition",
|
||||||
|
];
|
||||||
|
|
||||||
|
const awgV31TimerNames = [
|
||||||
|
"awg_rekey_after_time",
|
||||||
|
"awg_rekey_timeout",
|
||||||
|
"awg_reject_after_time",
|
||||||
|
"awg_keepalive_timeout",
|
||||||
|
"awg_max_handshake_attempts",
|
||||||
|
];
|
||||||
|
|
||||||
const awgParams = [
|
const awgParams = [
|
||||||
{
|
{
|
||||||
name: "awg_jc",
|
name: "awg_jc",
|
||||||
@@ -3567,6 +3632,48 @@ function createServerContent(section, options = {}) {
|
|||||||
desc: _("Init handshake timeout"),
|
desc: _("Init handshake timeout"),
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "awg_header_protection_key",
|
||||||
|
title: _("Header Protection Key"),
|
||||||
|
desc: _("AmneziaWG 3.1 header protection key"),
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "awg_content_padding_addition",
|
||||||
|
title: _("Content Padding Addition"),
|
||||||
|
desc: _("AmneziaWG 3.1 content padding range, e.g. 38-104"),
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "awg_rekey_after_time",
|
||||||
|
title: _("Rekey After Time"),
|
||||||
|
desc: _("AmneziaWG 3.1 rekey after time"),
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "awg_rekey_timeout",
|
||||||
|
title: _("Rekey Timeout"),
|
||||||
|
desc: _("AmneziaWG 3.1 rekey timeout"),
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "awg_reject_after_time",
|
||||||
|
title: _("Reject After Time"),
|
||||||
|
desc: _("AmneziaWG 3.1 reject after time"),
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "awg_keepalive_timeout",
|
||||||
|
title: _("Keepalive Timeout"),
|
||||||
|
desc: _("AmneziaWG 3.1 keepalive timeout"),
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "awg_max_handshake_attempts",
|
||||||
|
title: _("Max Handshake Attempts"),
|
||||||
|
desc: _("AmneziaWG 3.1 max handshake attempts"),
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
awgParams.forEach((param) => {
|
awgParams.forEach((param) => {
|
||||||
@@ -3574,7 +3681,14 @@ function createServerContent(section, options = {}) {
|
|||||||
opt.modalonly = true;
|
opt.modalonly = true;
|
||||||
opt.rmempty = true;
|
opt.rmempty = true;
|
||||||
if (param.default !== "") opt.default = param.default;
|
if (param.default !== "") opt.default = param.default;
|
||||||
opt.depends("protocol", "awg");
|
if (awgV31TimerNames.includes(param.name)) {
|
||||||
|
opt.depends({ protocol: "awg", awg_version: "3.1" });
|
||||||
|
} else if (awgV3ParamNames.includes(param.name)) {
|
||||||
|
opt.depends({ protocol: "awg", awg_version: "3.0" });
|
||||||
|
opt.depends({ protocol: "awg", awg_version: "3.1" });
|
||||||
|
} else {
|
||||||
|
opt.depends("protocol", "awg");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TACHYON\n"
|
"Project-Id-Version: TACHYON\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-09-01 21:58+0300\n"
|
"POT-Creation-Date: 2026-09-05 10:59+0300\n"
|
||||||
"PO-Revision-Date: 2026-09-01 21:58+0300\n"
|
"PO-Revision-Date: 2026-09-05 10:59+0300\n"
|
||||||
"Last-Translator: Dushnilin\n"
|
"Last-Translator: Dushnilin\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
@@ -41,9 +41,15 @@ msgstr "+ Добавить стратегию"
|
|||||||
msgid "+ Add URLTest"
|
msgid "+ Add URLTest"
|
||||||
msgstr "+ Добавить URLTest"
|
msgstr "+ Добавить URLTest"
|
||||||
|
|
||||||
|
msgid "⏳ Stopping..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "⚠️ Benchmark completed. No working bypass found for this target."
|
msgid "⚠️ Benchmark completed. No working bypass found for this target."
|
||||||
msgstr "⚠️ Бенчмарк завершен. Не найдено рабочих стратегий для данной цели."
|
msgstr "⚠️ Бенчмарк завершен. Не найдено рабочих стратегий для данной цели."
|
||||||
|
|
||||||
|
msgid "⚠️ Benchmark stopped"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "⚠️ If all Bootstrap DNS fail 3 times, queries will be sent to your ISP's DNS in plaintext. Only use as a last resort to prevent complete internet loss."
|
msgid "⚠️ If all Bootstrap DNS fail 3 times, queries will be sent to your ISP's DNS in plaintext. Only use as a last resort to prevent complete internet loss."
|
||||||
msgstr "⚠️ Если все Bootstrap DNS завершатся с ошибкой 3 раза, запросы будут отправлены в DNS вашего провайдера в открытом виде. Используйте только в крайнем случае для предотвращения полной потери интернета."
|
msgstr "⚠️ Если все Bootstrap DNS завершатся с ошибкой 3 раза, запросы будут отправлены в DNS вашего провайдера в открытом виде. Используйте только в крайнем случае для предотвращения полной потери интернета."
|
||||||
|
|
||||||
@@ -59,8 +65,8 @@ msgstr "⚡ Быстрые (>1 МБ/с)"
|
|||||||
msgid "⚡ QUIC / HTTP/3 (UDP 443)"
|
msgid "⚡ QUIC / HTTP/3 (UDP 443)"
|
||||||
msgstr "⚡ QUIC / HTTP/3 (UDP 443)"
|
msgstr "⚡ QUIC / HTTP/3 (UDP 443)"
|
||||||
|
|
||||||
msgid "⚡ Quick Benchmark (Presets ~12-14)"
|
msgid "⚡ Quick Benchmark (Presets ~30+)"
|
||||||
msgstr "⚡ Быстрый бенчмарк (Пресеты ~12-14)"
|
msgstr ""
|
||||||
|
|
||||||
msgid "⚡ Strategy Fuzzer & Auto-Tuner"
|
msgid "⚡ Strategy Fuzzer & Auto-Tuner"
|
||||||
msgstr "⚡ Подборщик стратегий и авто-тюнер"
|
msgstr "⚡ Подборщик стратегий и авто-тюнер"
|
||||||
@@ -92,8 +98,8 @@ msgstr "✘ Остановлено"
|
|||||||
msgid "🌐 Custom Target URL..."
|
msgid "🌐 Custom Target URL..."
|
||||||
msgstr "🌐 Пользовательский URL цели..."
|
msgstr "🌐 Пользовательский URL цели..."
|
||||||
|
|
||||||
msgid "🎬 YouTube Suite (Web + 4K Stream)"
|
msgid "🎬 YouTube Full Suite (Web + 4K Stream + CDN)"
|
||||||
msgstr "🎬 YouTube Suite (Web + 4K Stream)"
|
msgstr ""
|
||||||
|
|
||||||
msgid "🏆 Apply Best Match"
|
msgid "🏆 Apply Best Match"
|
||||||
msgstr "🏆 Применить наилучшую"
|
msgstr "🏆 Применить наилучшую"
|
||||||
@@ -101,8 +107,11 @@ msgstr "🏆 Применить наилучшую"
|
|||||||
msgid "🏴☠️ RuTracker Suite"
|
msgid "🏴☠️ RuTracker Suite"
|
||||||
msgstr "🏴☠️ RuTracker Suite"
|
msgstr "🏴☠️ RuTracker Suite"
|
||||||
|
|
||||||
msgid "💬 Discord Suite (API + WSS + CDN)"
|
msgid "🐦 X / Twitter Suite (API + Media CDN)"
|
||||||
msgstr "💬 Discord Suite (API + WSS + CDN)"
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "💬 Discord Suite (Gateway + Voice + CDN)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "💾 Save Custom Patterns"
|
msgid "💾 Save Custom Patterns"
|
||||||
msgstr "💾 Сохранить пользовательские паттерны"
|
msgstr "💾 Сохранить пользовательские паттерны"
|
||||||
@@ -116,12 +125,15 @@ msgstr "🔄 Обновить"
|
|||||||
msgid "🔄 Reset to Factory Defaults"
|
msgid "🔄 Reset to Factory Defaults"
|
||||||
msgstr "🔄 Сбросить к заводским настройкам"
|
msgstr "🔄 Сбросить к заводским настройкам"
|
||||||
|
|
||||||
msgid "🔍 Combinatorial Deep Fuzzing (~40-80+)"
|
msgid "🔍 Combinatorial Deep Fuzzing (~150-300+)"
|
||||||
msgstr "🔍 Комбинаторный глубокий фаззинг (~40-80+)"
|
msgstr ""
|
||||||
|
|
||||||
msgid "🗑️ Clear History"
|
msgid "🗑️ Clear History"
|
||||||
msgstr "🗑️ Очистить историю"
|
msgstr "🗑️ Очистить историю"
|
||||||
|
|
||||||
|
msgid "🤖 ChatGPT / OpenAI Suite"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "🧠 Synthesize with AI"
|
msgid "🧠 Synthesize with AI"
|
||||||
msgstr "🧠 Сгенерировать через ИИ"
|
msgstr "🧠 Сгенерировать через ИИ"
|
||||||
|
|
||||||
@@ -134,12 +146,18 @@ msgstr "🚀 Инициализация бенчмарка в песочнице
|
|||||||
msgid "🚀 Start Benchmark"
|
msgid "🚀 Start Benchmark"
|
||||||
msgstr "🚀 Начать бенчмарк"
|
msgstr "🚀 Начать бенчмарк"
|
||||||
|
|
||||||
|
msgid "🛑 Benchmark stopped"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "🛑 Stop Benchmark"
|
msgid "🛑 Stop Benchmark"
|
||||||
msgstr "🛑 Остановить бенчмарк"
|
msgstr "🛑 Остановить бенчмарк"
|
||||||
|
|
||||||
msgid "🛠️ My Custom Strategies Only"
|
msgid "🛠️ My Custom Strategies Only"
|
||||||
msgstr "🛠️ Только мои стратегии"
|
msgstr "🛠️ Только мои стратегии"
|
||||||
|
|
||||||
|
msgid "🟣 Twitch Suite (Live Stream + HLS CDN)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Accept external proxy connections and route them with sing-box."
|
msgid "Accept external proxy connections and route them with sing-box."
|
||||||
msgstr "Принимать внешние прокси-подключения и маршрутизировать их через sing-box."
|
msgstr "Принимать внешние прокси-подключения и маршрутизировать их через sing-box."
|
||||||
|
|
||||||
@@ -398,12 +416,36 @@ msgstr "Всегда блокировать эти домены для всех
|
|||||||
msgid "Always visible"
|
msgid "Always visible"
|
||||||
msgstr "Всегда включено"
|
msgstr "Всегда включено"
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 content padding range, e.g. 38-104"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 header protection key"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 keepalive timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 max handshake attempts"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 reject after time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 rekey after time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1 rekey timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "AmneziaWG config loaded successfully!"
|
msgid "AmneziaWG config loaded successfully!"
|
||||||
msgstr "Конфигурация AmneziaWG успешно загружена!"
|
msgstr "Конфигурация AmneziaWG успешно загружена!"
|
||||||
|
|
||||||
msgid "AmneziaWG Generator"
|
msgid "AmneziaWG Generator"
|
||||||
msgstr "Генератор AmneziaWG"
|
msgstr "Генератор AmneziaWG"
|
||||||
|
|
||||||
|
msgid "AmneziaWG Version"
|
||||||
|
msgstr "Версия AmneziaWG"
|
||||||
|
|
||||||
msgid "Anonymized support report copied to clipboard"
|
msgid "Anonymized support report copied to clipboard"
|
||||||
msgstr "Анонимизированный отчет скопирован в буфер обмена"
|
msgstr "Анонимизированный отчет скопирован в буфер обмена"
|
||||||
|
|
||||||
@@ -425,6 +467,9 @@ msgstr "Применено"
|
|||||||
msgid "Apply"
|
msgid "Apply"
|
||||||
msgstr "Применить"
|
msgstr "Применить"
|
||||||
|
|
||||||
|
msgid "Apply Recommended DNS"
|
||||||
|
msgstr "Применить рекомендованный DNS"
|
||||||
|
|
||||||
msgid "Apply rules of this section only to selected protocols."
|
msgid "Apply rules of this section only to selected protocols."
|
||||||
msgstr "Применять правила этой секции только к выбранным протоколам."
|
msgstr "Применять правила этой секции только к выбранным протоколам."
|
||||||
|
|
||||||
@@ -500,6 +545,9 @@ msgstr "Авто-генерация HWID"
|
|||||||
msgid "Auto-Heal Network Stack"
|
msgid "Auto-Heal Network Stack"
|
||||||
msgstr "Автолечение сетевого стека"
|
msgstr "Автолечение сетевого стека"
|
||||||
|
|
||||||
|
msgid "Auto-Tune & Benchmark DNS"
|
||||||
|
msgstr "Подобрать и протестировать DNS"
|
||||||
|
|
||||||
msgid "Auto-update Hosts Lists"
|
msgid "Auto-update Hosts Lists"
|
||||||
msgstr "Автообновление списков Hosts"
|
msgstr "Автообновление списков Hosts"
|
||||||
|
|
||||||
@@ -518,6 +566,9 @@ msgstr "Автоматический выбор User-Agent"
|
|||||||
msgid "Automatically add text to the name of each server from this subscription for convenient filtering."
|
msgid "Automatically add text to the name of each server from this subscription for convenient filtering."
|
||||||
msgstr "Автоматически добавлять текст к имени каждого сервера из этой подписки для удобной фильтрации."
|
msgstr "Автоматически добавлять текст к имени каждого сервера из этой подписки для удобной фильтрации."
|
||||||
|
|
||||||
|
msgid "Automatically benchmark latency, packet loss, and anti-censorship reliability of major DNS servers (UDP/DoH) from this router to find and apply the optimal configuration."
|
||||||
|
msgstr "Автоматически замерить задержку, потери пакетов и защиту от цензуры основных DNS серверов (UDP/DoH) прямо с роутера, чтобы найти и применить оптимальную конфигурацию."
|
||||||
|
|
||||||
msgid "Automatically check installed components for new versions"
|
msgid "Automatically check installed components for new versions"
|
||||||
msgstr "Автоматически проверять установленные компоненты на наличие новых версий"
|
msgstr "Автоматически проверять установленные компоненты на наличие новых версий"
|
||||||
|
|
||||||
@@ -563,9 +614,15 @@ msgstr "Беларусь (by)"
|
|||||||
msgid "Benchmark & Test"
|
msgid "Benchmark & Test"
|
||||||
msgstr "Бенчмарк и тестирование"
|
msgstr "Бенчмарк и тестирование"
|
||||||
|
|
||||||
|
msgid "Benchmark completed successfully"
|
||||||
|
msgstr "Бенчмарк успешно завершён"
|
||||||
|
|
||||||
msgid "Benchmark History"
|
msgid "Benchmark History"
|
||||||
msgstr "История бенчмарков"
|
msgstr "История бенчмарков"
|
||||||
|
|
||||||
|
msgid "Benchmark measures actual latency and resolution reliability of major DNS servers (UDP 53 and encrypted DoH) directly from your router to find the fastest, unblocked upstream for your ISP."
|
||||||
|
msgstr "Бенчмарк замеряет реальную задержку и надёжность резолва основных DNS серверов (UDP 53 и шифрованный DoH) напрямую с роутера, чтобы найти самый быстрый и незаблокированный апстрим у вашего провайдера."
|
||||||
|
|
||||||
msgid "Benchmark stopped"
|
msgid "Benchmark stopped"
|
||||||
msgstr "Бенчмарк остановлен"
|
msgstr "Бенчмарк остановлен"
|
||||||
|
|
||||||
@@ -899,6 +956,9 @@ msgstr "Строка аргументов командной строки..."
|
|||||||
msgid "Community Lists"
|
msgid "Community Lists"
|
||||||
msgstr "Community-списки"
|
msgstr "Community-списки"
|
||||||
|
|
||||||
|
msgid "Component action timed out"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Component update available"
|
msgid "Component update available"
|
||||||
msgstr "Доступно обновление компонента"
|
msgstr "Доступно обновление компонента"
|
||||||
|
|
||||||
@@ -929,6 +989,9 @@ msgstr "Путь к файлу конфигурации"
|
|||||||
msgid "Config Snapshots"
|
msgid "Config Snapshots"
|
||||||
msgstr "Снапшоты конфигурации"
|
msgstr "Снапшоты конфигурации"
|
||||||
|
|
||||||
|
msgid "Configuration applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Configuration for Tachyon service"
|
msgid "Configuration for Tachyon service"
|
||||||
msgstr "Конфигурация сервиса Tachyon"
|
msgstr "Конфигурация сервиса Tachyon"
|
||||||
|
|
||||||
@@ -962,6 +1025,9 @@ msgstr "Консультируюсь с базой знаний DPI и ИИ..."
|
|||||||
msgid "Content Mode"
|
msgid "Content Mode"
|
||||||
msgstr "Режим контента"
|
msgstr "Режим контента"
|
||||||
|
|
||||||
|
msgid "Content Padding Addition"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Cookie packet junk size (S3)"
|
msgid "Cookie packet junk size (S3)"
|
||||||
msgstr "Размер мусора в пакете cookie (S3)"
|
msgstr "Размер мусора в пакете cookie (S3)"
|
||||||
|
|
||||||
@@ -1163,6 +1229,9 @@ msgstr "Отображаемое имя"
|
|||||||
msgid "DNS"
|
msgid "DNS"
|
||||||
msgstr "DNS"
|
msgstr "DNS"
|
||||||
|
|
||||||
|
msgid "DNS Auto-Tuner & Benchmark"
|
||||||
|
msgstr "Автоподбор и бенчмарк DNS"
|
||||||
|
|
||||||
msgid "DNS Check Interval"
|
msgid "DNS Check Interval"
|
||||||
msgstr "Интервал проверки DNS"
|
msgstr "Интервал проверки DNS"
|
||||||
|
|
||||||
@@ -1187,6 +1256,9 @@ msgstr "DNS через TLS (DoT)"
|
|||||||
msgid "DNS protocol"
|
msgid "DNS protocol"
|
||||||
msgstr "Протокол DNS"
|
msgstr "Протокол DNS"
|
||||||
|
|
||||||
|
msgid "DNS Protocol"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "DNS Protocol Type"
|
msgid "DNS Protocol Type"
|
||||||
msgstr "Тип протокола DNS"
|
msgstr "Тип протокола DNS"
|
||||||
|
|
||||||
@@ -1535,6 +1607,9 @@ msgstr "Ошибка обновления списков:"
|
|||||||
msgid "Every day"
|
msgid "Every day"
|
||||||
msgstr "Каждый день"
|
msgstr "Каждый день"
|
||||||
|
|
||||||
|
msgid "EXCELLENT"
|
||||||
|
msgstr "ОТЛИЧНО"
|
||||||
|
|
||||||
msgid "Exclude by proxy parameters"
|
msgid "Exclude by proxy parameters"
|
||||||
msgstr "Исключить по параметрам прокси"
|
msgstr "Исключить по параметрам прокси"
|
||||||
|
|
||||||
@@ -1577,6 +1652,9 @@ msgstr "Истекает"
|
|||||||
msgid "Expose this section as a local HTTP+SOCKS proxy"
|
msgid "Expose this section as a local HTTP+SOCKS proxy"
|
||||||
msgstr "Предоставить эту секцию как локальный HTTP+SOCKS прокси"
|
msgstr "Предоставить эту секцию как локальный HTTP+SOCKS прокси"
|
||||||
|
|
||||||
|
msgid "extended"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "External inbound proxy servers"
|
msgid "External inbound proxy servers"
|
||||||
msgstr "Внешние входящие прокси-серверы"
|
msgstr "Внешние входящие прокси-серверы"
|
||||||
|
|
||||||
@@ -1586,6 +1664,15 @@ msgstr "Внешние файлы конфигурации nfqws обходят
|
|||||||
msgid "External nfqws2 config files bypass Tachyon queue management and explicit validation."
|
msgid "External nfqws2 config files bypass Tachyon queue management and explicit validation."
|
||||||
msgstr "Внешние файлы конфигурации nfqws2 обходят управление очередями Tachyon и явную проверку."
|
msgstr "Внешние файлы конфигурации nfqws2 обходят управление очередями Tachyon и явную проверку."
|
||||||
|
|
||||||
|
msgid "FAILED"
|
||||||
|
msgstr "СБОЙ"
|
||||||
|
|
||||||
|
msgid "Failed to apply DNS configuration"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Failed to apply DNS settings"
|
||||||
|
msgstr "Не удалось применить настройки DNS"
|
||||||
|
|
||||||
msgid "Failed to apply fix"
|
msgid "Failed to apply fix"
|
||||||
msgstr "Не удалось применить исправление"
|
msgstr "Не удалось применить исправление"
|
||||||
|
|
||||||
@@ -1622,12 +1709,18 @@ msgstr "Не удалось определить тип DPI"
|
|||||||
msgid "Failed to execute"
|
msgid "Failed to execute"
|
||||||
msgstr "Не удалось выполнить"
|
msgstr "Не удалось выполнить"
|
||||||
|
|
||||||
|
msgid "Failed to fetch releases"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to generate bug report"
|
msgid "Failed to generate bug report"
|
||||||
msgstr "Не удалось создать отчёт об ошибке"
|
msgstr "Не удалось создать отчёт об ошибке"
|
||||||
|
|
||||||
msgid "Failed to generate WARP config:"
|
msgid "Failed to generate WARP config:"
|
||||||
msgstr "Не удалось сгенерировать конфигурацию WARP:"
|
msgstr "Не удалось сгенерировать конфигурацию WARP:"
|
||||||
|
|
||||||
|
msgid "Failed to get DNS benchmark status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to get fuzzer history"
|
msgid "Failed to get fuzzer history"
|
||||||
msgstr "Не удалось получить историю фаззера"
|
msgstr "Не удалось получить историю фаззера"
|
||||||
|
|
||||||
@@ -1640,12 +1733,18 @@ msgstr "Не удалось получить статус фаззера"
|
|||||||
msgid "Failed to get fuzzer strategies"
|
msgid "Failed to get fuzzer strategies"
|
||||||
msgstr "Не удалось получить стратегии фаззера"
|
msgstr "Не удалось получить стратегии фаззера"
|
||||||
|
|
||||||
|
msgid "Failed to install version"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to load history"
|
msgid "Failed to load history"
|
||||||
msgstr "Не удалось загрузить историю"
|
msgstr "Не удалось загрузить историю"
|
||||||
|
|
||||||
msgid "Failed to load snapshots"
|
msgid "Failed to load snapshots"
|
||||||
msgstr "Не удалось загрузить снапшоты"
|
msgstr "Не удалось загрузить снапшоты"
|
||||||
|
|
||||||
|
msgid "Failed to load versions"
|
||||||
|
msgstr "Не удалось загрузить версии"
|
||||||
|
|
||||||
msgid "Failed to parse file:"
|
msgid "Failed to parse file:"
|
||||||
msgstr "Ошибка разбора файла:"
|
msgstr "Ошибка разбора файла:"
|
||||||
|
|
||||||
@@ -1691,6 +1790,9 @@ msgstr "Не удалось запустить бенчмарк"
|
|||||||
msgid "Failed to start bot"
|
msgid "Failed to start bot"
|
||||||
msgstr "Не удалось запустить бота"
|
msgstr "Не удалось запустить бота"
|
||||||
|
|
||||||
|
msgid "Failed to start DNS benchmark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to start fuzzer"
|
msgid "Failed to start fuzzer"
|
||||||
msgstr "Не удалось запустить фаззер"
|
msgstr "Не удалось запустить фаззер"
|
||||||
|
|
||||||
@@ -1703,6 +1805,9 @@ msgstr "Не удалось запустить watchdog"
|
|||||||
msgid "Failed to stop bot"
|
msgid "Failed to stop bot"
|
||||||
msgstr "Не удалось остановить бота"
|
msgstr "Не удалось остановить бота"
|
||||||
|
|
||||||
|
msgid "Failed to stop DNS benchmark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to stop fuzzer"
|
msgid "Failed to stop fuzzer"
|
||||||
msgstr "Не удалось остановить фаззер"
|
msgstr "Не удалось остановить фаззер"
|
||||||
|
|
||||||
@@ -1724,6 +1829,9 @@ msgstr "Не удалось обновить подписки"
|
|||||||
msgid "Failover failure threshold"
|
msgid "Failover failure threshold"
|
||||||
msgstr "Порог срабатывания failover"
|
msgstr "Порог срабатывания failover"
|
||||||
|
|
||||||
|
msgid "FAIR"
|
||||||
|
msgstr "СРЕДНЕ"
|
||||||
|
|
||||||
msgid "FakeIP and control checks use different public IPs"
|
msgid "FakeIP and control checks use different public IPs"
|
||||||
msgstr "FakeIP и контрольная проверка используют разные публичные IP"
|
msgstr "FakeIP и контрольная проверка используют разные публичные IP"
|
||||||
|
|
||||||
@@ -1736,6 +1844,9 @@ msgstr "FakeIP работает; сравнение публичных IP не
|
|||||||
msgid "FakeTLS host"
|
msgid "FakeTLS host"
|
||||||
msgstr "FakeTLS host"
|
msgstr "FakeTLS host"
|
||||||
|
|
||||||
|
msgid "Fallback DNS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Fallback DNS Servers"
|
msgid "Fallback DNS Servers"
|
||||||
msgstr "Резервные DNS серверы"
|
msgstr "Резервные DNS серверы"
|
||||||
|
|
||||||
@@ -1748,75 +1859,6 @@ msgstr "Резервные DNS серверы должны быть обычны
|
|||||||
msgid "Fallback on unknown DC"
|
msgid "Fallback on unknown DC"
|
||||||
msgstr "Fallback при неизвестном DC"
|
msgstr "Fallback при неизвестном DC"
|
||||||
|
|
||||||
msgid "DNS Auto-Tuner & Benchmark"
|
|
||||||
msgstr "Автоподбор и бенчмарк DNS"
|
|
||||||
|
|
||||||
msgid "Auto-Tune & Benchmark DNS"
|
|
||||||
msgstr "Подобрать и протестировать DNS"
|
|
||||||
|
|
||||||
msgid "Automatically benchmark latency, packet loss, and anti-censorship reliability of major DNS servers (UDP/DoH) from this router to find and apply the optimal configuration."
|
|
||||||
msgstr "Автоматически замерить задержку, потери пакетов и защиту от цензуры основных DNS серверов (UDP/DoH) прямо с роутера, чтобы найти и применить оптимальную конфигурацию."
|
|
||||||
|
|
||||||
msgid "Tachyon DNS Benchmark & Auto-Tuning"
|
|
||||||
msgstr "Tachyon: Бенчмарк и автоподбор DNS"
|
|
||||||
|
|
||||||
msgid "Ready to benchmark DNS providers"
|
|
||||||
msgstr "Готов к тестированию DNS провайдеров"
|
|
||||||
|
|
||||||
msgid "Benchmark measures actual latency and resolution reliability of major DNS servers (UDP 53 and encrypted DoH) directly from your router to find the fastest, unblocked upstream for your ISP."
|
|
||||||
msgstr "Бенчмарк замеряет реальную задержку и надёжность резолва основных DNS серверов (UDP 53 и шифрованный DoH) напрямую с роутера, чтобы найти самый быстрый и незаблокированный апстрим у вашего провайдера."
|
|
||||||
|
|
||||||
msgid "Start Benchmark"
|
|
||||||
msgstr "Начать тест"
|
|
||||||
|
|
||||||
msgid "Starting DNS benchmark..."
|
|
||||||
msgstr "Запуск бенчмарка DNS..."
|
|
||||||
|
|
||||||
msgid "Benchmark completed successfully"
|
|
||||||
msgstr "Бенчмарк успешно завершён"
|
|
||||||
|
|
||||||
msgid "Apply Recommended DNS"
|
|
||||||
msgstr "Применить рекомендованный DNS"
|
|
||||||
|
|
||||||
msgid "Recommended DNS Configuration"
|
|
||||||
msgstr "Рекомендованная конфигурация DNS"
|
|
||||||
|
|
||||||
msgid "Recommended DNS settings applied successfully and service restarted!"
|
|
||||||
msgstr "Рекомендованные настройки DNS успешно применены, сервис перезапущен!"
|
|
||||||
|
|
||||||
msgid "Failed to start benchmark"
|
|
||||||
msgstr "Не удалось запустить бенчмарк"
|
|
||||||
|
|
||||||
msgid "Failed to apply DNS settings"
|
|
||||||
msgstr "Не удалось применить настройки DNS"
|
|
||||||
|
|
||||||
msgid "No benchmark data yet. Click \"Start Benchmark\" to begin."
|
|
||||||
msgstr "Нет данных бенчмарка. Нажмите «Начать тест», чтобы запустить проверку."
|
|
||||||
|
|
||||||
msgid "EXCELLENT"
|
|
||||||
msgstr "ОТЛИЧНО"
|
|
||||||
|
|
||||||
msgid "GOOD"
|
|
||||||
msgstr "ХОРОШО"
|
|
||||||
|
|
||||||
msgid "FAIR"
|
|
||||||
msgstr "СРЕДНЕ"
|
|
||||||
|
|
||||||
msgid "SLOW"
|
|
||||||
msgstr "МЕДЛЕННО"
|
|
||||||
|
|
||||||
msgid "FAILED"
|
|
||||||
msgstr "СБОЙ"
|
|
||||||
|
|
||||||
msgid "Protocol"
|
|
||||||
msgstr "Протокол"
|
|
||||||
|
|
||||||
msgid "Rating"
|
|
||||||
msgstr "Оценка"
|
|
||||||
|
|
||||||
msgid "Loss"
|
|
||||||
msgstr "Потери"
|
|
||||||
|
|
||||||
msgid "Family (🏠)"
|
msgid "Family (🏠)"
|
||||||
msgstr "Семья (🏠)"
|
msgstr "Семья (🏠)"
|
||||||
|
|
||||||
@@ -1847,6 +1889,9 @@ msgstr "Фильтровать серверы, отображаемые на д
|
|||||||
msgid "Filter:"
|
msgid "Filter:"
|
||||||
msgstr "Фильтр:"
|
msgstr "Фильтр:"
|
||||||
|
|
||||||
|
msgid "Finished with code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Finland (fi)"
|
msgid "Finland (fi)"
|
||||||
msgstr "Финляндия (fi)"
|
msgstr "Финляндия (fi)"
|
||||||
|
|
||||||
@@ -1886,6 +1931,9 @@ msgstr "Принудительно включает безопасный пои
|
|||||||
msgid "Forces sing-box to tunnel DNS requests via DoQ with Encrypted Client Hello (ECH) for SNI hiding."
|
msgid "Forces sing-box to tunnel DNS requests via DoQ with Encrypted Client Hello (ECH) for SNI hiding."
|
||||||
msgstr "Принудительно направлять DNS-запросы через DoQ с Encrypted Client Hello (ECH) для скрытия SNI."
|
msgstr "Принудительно направлять DNS-запросы через DoQ с Encrypted Client Hello (ECH) для скрытия SNI."
|
||||||
|
|
||||||
|
msgid "Found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "France (fr)"
|
msgid "France (fr)"
|
||||||
msgstr "Франция (fr)"
|
msgstr "Франция (fr)"
|
||||||
|
|
||||||
@@ -1973,6 +2021,9 @@ msgstr "Не удалось выполнить глобальную провер
|
|||||||
msgid "Global Default"
|
msgid "Global Default"
|
||||||
msgstr "Глобально по умолчанию"
|
msgstr "Глобально по умолчанию"
|
||||||
|
|
||||||
|
msgid "GOOD"
|
||||||
|
msgstr "ХОРОШО"
|
||||||
|
|
||||||
msgid "Group devices into family profiles to manage content filtering, SafeSearch, and screen time limits in one place."
|
msgid "Group devices into family profiles to manage content filtering, SafeSearch, and screen time limits in one place."
|
||||||
msgstr "Группируйте устройства в семейные профили для централизованного управления фильтрацией сайтов, безопасным поиском и лимитами экранного времени."
|
msgstr "Группируйте устройства в семейные профили для централизованного управления фильтрацией сайтов, безопасным поиском и лимитами экранного времени."
|
||||||
|
|
||||||
@@ -1982,6 +2033,9 @@ msgstr "Сервис gRPC"
|
|||||||
msgid "Handshake timeout"
|
msgid "Handshake timeout"
|
||||||
msgstr "Таймаут рукопожатия"
|
msgstr "Таймаут рукопожатия"
|
||||||
|
|
||||||
|
msgid "Header Protection Key"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Hello! I am Tachyon AI Assistant. How can I help you today? Ask me about domain blocks, diagnostics, or router settings."
|
msgid "Hello! I am Tachyon AI Assistant. How can I help you today? Ask me about domain blocks, diagnostics, or router settings."
|
||||||
msgstr "Привет! Я ИИ-ассистент Tachyon. Чем могу помочь? Задайте вопрос о блокировках, диагностике или настройках роутера."
|
msgstr "Привет! Я ИИ-ассистент Tachyon. Чем могу помочь? Задайте вопрос о блокировках, диагностике или настройках роутера."
|
||||||
|
|
||||||
@@ -2033,6 +2087,9 @@ msgstr "Скрыть узлы групп URLTest"
|
|||||||
msgid "Hide values"
|
msgid "Hide values"
|
||||||
msgstr "Скрывать значения"
|
msgstr "Скрывать значения"
|
||||||
|
|
||||||
|
msgid "Hide versions"
|
||||||
|
msgstr "Скрыть версии"
|
||||||
|
|
||||||
msgid "Higher-level check interval"
|
msgid "Higher-level check interval"
|
||||||
msgstr "Интервал проверки высших уровней"
|
msgstr "Интервал проверки высших уровней"
|
||||||
|
|
||||||
@@ -2534,6 +2591,9 @@ msgstr "Сохранять предыдущую рабочую версию ко
|
|||||||
msgid "Keep URLTest before latency-sorted servers"
|
msgid "Keep URLTest before latency-sorted servers"
|
||||||
msgstr "Сохранять URLTest перед серверами, отсортированными по задержке"
|
msgstr "Сохранять URLTest перед серверами, отсортированными по задержке"
|
||||||
|
|
||||||
|
msgid "Keepalive Timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Keeps FakeIP cache persistent across reboots and pre-resolves popular blocked domains on startup so first-visit latency is 0 ms."
|
msgid "Keeps FakeIP cache persistent across reboots and pre-resolves popular blocked domains on startup so first-visit latency is 0 ms."
|
||||||
msgstr "Сохраняет FakeIP-кэш между перезагрузками и заранее резолвит популярные заблокированные домены при старте — задержка при первом визите 0 мс."
|
msgstr "Сохраняет FakeIP-кэш между перезагрузками и заранее резолвит популярные заблокированные домены при старте — задержка при первом визите 0 мс."
|
||||||
|
|
||||||
@@ -2555,6 +2615,9 @@ msgstr "Язык ответов диагностики ИИ-доктора"
|
|||||||
msgid "Laptop / PC (💻)"
|
msgid "Laptop / PC (💻)"
|
||||||
msgstr "Ноутбук / ПК (💻)"
|
msgstr "Ноутбук / ПК (💻)"
|
||||||
|
|
||||||
|
msgid "Latency"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Latency test failed"
|
msgid "Latency test failed"
|
||||||
msgstr "Проверка задержки не удалась"
|
msgstr "Проверка задержки не удалась"
|
||||||
|
|
||||||
@@ -2627,6 +2690,9 @@ msgstr "Загрузка подключений"
|
|||||||
msgid "Loading service list..."
|
msgid "Loading service list..."
|
||||||
msgstr "Получение списка сервисов..."
|
msgstr "Получение списка сервисов..."
|
||||||
|
|
||||||
|
msgid "Loading versions..."
|
||||||
|
msgstr "Загрузка версий..."
|
||||||
|
|
||||||
msgid "Loading..."
|
msgid "Loading..."
|
||||||
msgstr "Загрузка..."
|
msgstr "Загрузка..."
|
||||||
|
|
||||||
@@ -2636,6 +2702,9 @@ msgstr "Локальный адрес"
|
|||||||
msgid "Log Level"
|
msgid "Log Level"
|
||||||
msgstr "Уровень логирования"
|
msgstr "Уровень логирования"
|
||||||
|
|
||||||
|
msgid "Loss"
|
||||||
|
msgstr "Потери"
|
||||||
|
|
||||||
msgid "LuCI Web UI"
|
msgid "LuCI Web UI"
|
||||||
msgstr "Веб-интерфейс LuCI"
|
msgstr "Веб-интерфейс LuCI"
|
||||||
|
|
||||||
@@ -2681,6 +2750,9 @@ msgstr "Совпадение найдено"
|
|||||||
msgid "Match traffic by packet DSCP mark (assigned in Windows via Policy-Based QoS). Examples: 46 (EF), 0x2e, 34 (AF41)"
|
msgid "Match traffic by packet DSCP mark (assigned in Windows via Policy-Based QoS). Examples: 46 (EF), 0x2e, 34 (AF41)"
|
||||||
msgstr "Сопоставлять трафик по DSCP-метке пакета (назначается в Windows через Policy-Based QoS). Примеры: 46 (EF), 0x2e, 34 (AF41)"
|
msgstr "Сопоставлять трафик по DSCP-метке пакета (назначается в Windows через Policy-Based QoS). Примеры: 46 (EF), 0x2e, 34 (AF41)"
|
||||||
|
|
||||||
|
msgid "Max Handshake Attempts"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Max reconnects per hour before alert (default 10)."
|
msgid "Max reconnects per hour before alert (default 10)."
|
||||||
msgstr "Макс. переподключений в час до оповещения (по умолчанию 10)."
|
msgstr "Макс. переподключений в час до оповещения (по умолчанию 10)."
|
||||||
|
|
||||||
@@ -2828,6 +2900,9 @@ msgstr "Активные устройства в локальной сети н
|
|||||||
msgid "No active routing sections found."
|
msgid "No active routing sections found."
|
||||||
msgstr "Активные секции маршрутизации не найдены."
|
msgstr "Активные секции маршрутизации не найдены."
|
||||||
|
|
||||||
|
msgid "No benchmark data yet. Click \"Start Benchmark\" to begin."
|
||||||
|
msgstr "Нет данных бенчмарка. Нажмите «Начать тест», чтобы запустить проверку."
|
||||||
|
|
||||||
msgid "No benchmark history yet. Run a benchmark to see results here."
|
msgid "No benchmark history yet. Run a benchmark to see results here."
|
||||||
msgstr "История бенчмарков пуста. Запустите бенчмарк, чтобы увидеть результаты здесь."
|
msgstr "История бенчмарков пуста. Запустите бенчмарк, чтобы увидеть результаты здесь."
|
||||||
|
|
||||||
@@ -2900,6 +2975,12 @@ msgstr "Снапшотов пока нет"
|
|||||||
msgid "No strategies match the active filter."
|
msgid "No strategies match the active filter."
|
||||||
msgstr "Нет стратегий, соответствующих выбранному фильтру."
|
msgstr "Нет стратегий, соответствующих выбранному фильтру."
|
||||||
|
|
||||||
|
msgid "No versions found"
|
||||||
|
msgstr "Версии не найдены"
|
||||||
|
|
||||||
|
msgid "No working strategy to apply"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Node list is empty"
|
msgid "Node list is empty"
|
||||||
msgstr "Список узлов пуст"
|
msgstr "Список узлов пуст"
|
||||||
|
|
||||||
@@ -3239,6 +3320,9 @@ msgstr "Предварительно собранный индекс фрагм
|
|||||||
msgid "Pre-download all preset lists"
|
msgid "Pre-download all preset lists"
|
||||||
msgstr "Предзагрузить все предустановленные списки"
|
msgstr "Предзагрузить все предустановленные списки"
|
||||||
|
|
||||||
|
msgid "pre-release"
|
||||||
|
msgstr "пре-релиз"
|
||||||
|
|
||||||
msgid "Pre-shared key"
|
msgid "Pre-shared key"
|
||||||
msgstr "Предварительный общий ключ"
|
msgstr "Предварительный общий ключ"
|
||||||
|
|
||||||
@@ -3266,6 +3350,9 @@ msgstr "Предварительный общий ключ"
|
|||||||
msgid "Prevents multiple reload_firewall calls within 120 seconds to avoid connection drops."
|
msgid "Prevents multiple reload_firewall calls within 120 seconds to avoid connection drops."
|
||||||
msgstr "Предотвращает множественные вызовы reload_firewall в течение 120 секунд для избежания разрыва соединений."
|
msgstr "Предотвращает множественные вызовы reload_firewall в течение 120 секунд для избежания разрыва соединений."
|
||||||
|
|
||||||
|
msgid "Primary DNS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Priority"
|
msgid "Priority"
|
||||||
msgstr "Приоритет"
|
msgstr "Приоритет"
|
||||||
|
|
||||||
@@ -3308,6 +3395,12 @@ msgstr "Защита"
|
|||||||
msgid "Protocol"
|
msgid "Protocol"
|
||||||
msgstr "Протокол"
|
msgstr "Протокол"
|
||||||
|
|
||||||
|
msgid "Protocol version: 2.0 (standard integer headers) or 3.1 (header protection key, padding ranges, advanced timers)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Provider"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Provider Global Default"
|
msgid "Provider Global Default"
|
||||||
msgstr "Глобальные настройки провайдера"
|
msgstr "Глобальные настройки провайдера"
|
||||||
|
|
||||||
@@ -3350,12 +3443,18 @@ msgstr "QUIC (HTTP/3)"
|
|||||||
msgid "RAG Knowledge Base + Live ISP Probe Context"
|
msgid "RAG Knowledge Base + Live ISP Probe Context"
|
||||||
msgstr "База знаний RAG + результаты живого зондирования провайдера"
|
msgstr "База знаний RAG + результаты живого зондирования провайдера"
|
||||||
|
|
||||||
|
msgid "Rating"
|
||||||
|
msgstr "Оценка"
|
||||||
|
|
||||||
msgid "RDP"
|
msgid "RDP"
|
||||||
msgstr "RDP"
|
msgstr "RDP"
|
||||||
|
|
||||||
msgid "Read error"
|
msgid "Read error"
|
||||||
msgstr "Ошибка чтения"
|
msgstr "Ошибка чтения"
|
||||||
|
|
||||||
|
msgid "Ready to benchmark DNS providers"
|
||||||
|
msgstr "Готов к тестированию DNS провайдеров"
|
||||||
|
|
||||||
msgid "Reality fake site"
|
msgid "Reality fake site"
|
||||||
msgstr "Фейковый сайт Reality"
|
msgstr "Фейковый сайт Reality"
|
||||||
|
|
||||||
@@ -3386,6 +3485,12 @@ msgstr "Пересобранный релиз"
|
|||||||
msgid "Recommended"
|
msgid "Recommended"
|
||||||
msgstr "Рекомендовано"
|
msgstr "Рекомендовано"
|
||||||
|
|
||||||
|
msgid "Recommended DNS Configuration"
|
||||||
|
msgstr "Рекомендованная конфигурация DNS"
|
||||||
|
|
||||||
|
msgid "Recommended DNS settings applied successfully and service restarted!"
|
||||||
|
msgstr "Рекомендованные настройки DNS успешно применены, сервис перезапущен!"
|
||||||
|
|
||||||
msgid "Recommended Quick Fixes:"
|
msgid "Recommended Quick Fixes:"
|
||||||
msgstr "Рекомендуемые исправления:"
|
msgstr "Рекомендуемые исправления:"
|
||||||
|
|
||||||
@@ -3419,6 +3524,15 @@ msgstr "Регулярное выражение не должно содержа
|
|||||||
msgid "Reinstall"
|
msgid "Reinstall"
|
||||||
msgstr "Переустановить"
|
msgstr "Переустановить"
|
||||||
|
|
||||||
|
msgid "Reject After Time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Rekey After Time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Rekey Timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Reload now"
|
msgid "Reload now"
|
||||||
msgstr "Перезагрузить сейчас"
|
msgstr "Перезагрузить сейчас"
|
||||||
|
|
||||||
@@ -3938,9 +4052,6 @@ msgstr "Сервисы и доступ"
|
|||||||
msgid "Services are online and ready! Reloading page..."
|
msgid "Services are online and ready! Reloading page..."
|
||||||
msgstr "Службы запущены и готовы к работе! Перезагрузка страницы..."
|
msgstr "Службы запущены и готовы к работе! Перезагрузка страницы..."
|
||||||
|
|
||||||
msgid "Services are online, waiting for full initialization..."
|
|
||||||
msgstr "Сервисы запущены, ожидание полной инициализации..."
|
|
||||||
|
|
||||||
msgid "Services info"
|
msgid "Services info"
|
||||||
msgstr "Информация о сервисах"
|
msgstr "Информация о сервисах"
|
||||||
|
|
||||||
@@ -4037,6 +4148,9 @@ msgstr "Пропущены комментарии/невалидные:"
|
|||||||
msgid "Skipped loopback:"
|
msgid "Skipped loopback:"
|
||||||
msgstr "Пропущены loopback:"
|
msgstr "Пропущены loopback:"
|
||||||
|
|
||||||
|
msgid "SLOW"
|
||||||
|
msgstr "МЕДЛЕННО"
|
||||||
|
|
||||||
msgid "Snapshot name"
|
msgid "Snapshot name"
|
||||||
msgstr "Имя снапшота"
|
msgstr "Имя снапшота"
|
||||||
|
|
||||||
@@ -4136,6 +4250,9 @@ msgstr "Стандартный"
|
|||||||
msgid "Start"
|
msgid "Start"
|
||||||
msgstr "Старт"
|
msgstr "Старт"
|
||||||
|
|
||||||
|
msgid "Start Benchmark"
|
||||||
|
msgstr "Начать тест"
|
||||||
|
|
||||||
msgid "Start bot"
|
msgid "Start bot"
|
||||||
msgstr "Запустить бота"
|
msgstr "Запустить бота"
|
||||||
|
|
||||||
@@ -4151,6 +4268,9 @@ msgstr "Время начала (ЧЧ:ММ)"
|
|||||||
msgid "Start watchdog"
|
msgid "Start watchdog"
|
||||||
msgstr "Запустить watchdog"
|
msgstr "Запустить watchdog"
|
||||||
|
|
||||||
|
msgid "Starting DNS benchmark..."
|
||||||
|
msgstr "Запуск бенчмарка DNS..."
|
||||||
|
|
||||||
msgid "Starting…"
|
msgid "Starting…"
|
||||||
msgstr "Запуск…"
|
msgstr "Запуск…"
|
||||||
|
|
||||||
@@ -4235,6 +4355,9 @@ msgstr "Успех"
|
|||||||
msgid "Successfully imported %d DNS record(s)"
|
msgid "Successfully imported %d DNS record(s)"
|
||||||
msgstr "Успешно импортировано %d DNS-записей"
|
msgstr "Успешно импортировано %d DNS-записей"
|
||||||
|
|
||||||
|
msgid "Successfully updated %d hosts entries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Sun"
|
msgid "Sun"
|
||||||
msgstr "Вс"
|
msgstr "Вс"
|
||||||
|
|
||||||
@@ -4268,9 +4391,15 @@ msgstr "Порядок и видимость вкладок"
|
|||||||
msgid "Table exist"
|
msgid "Table exist"
|
||||||
msgstr "Таблица существует"
|
msgstr "Таблица существует"
|
||||||
|
|
||||||
|
msgid "Tachyon"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Tachyon Core"
|
msgid "Tachyon Core"
|
||||||
msgstr "Ядро Tachyon"
|
msgstr "Ядро Tachyon"
|
||||||
|
|
||||||
|
msgid "Tachyon DNS Benchmark & Auto-Tuning"
|
||||||
|
msgstr "Tachyon: Бенчмарк и автоподбор DNS"
|
||||||
|
|
||||||
msgid "Tachyon Error"
|
msgid "Tachyon Error"
|
||||||
msgstr "Ошибка Tachyon"
|
msgstr "Ошибка Tachyon"
|
||||||
|
|
||||||
@@ -4409,6 +4538,9 @@ msgstr "Тестировать серверы, чьи имена соответ
|
|||||||
msgid "Test Telegram Connection"
|
msgid "Test Telegram Connection"
|
||||||
msgstr "Проверить подключение к Telegram"
|
msgstr "Проверить подключение к Telegram"
|
||||||
|
|
||||||
|
msgid "Testing"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Testing bypass strategies in isolated sandbox..."
|
msgid "Testing bypass strategies in isolated sandbox..."
|
||||||
msgstr "Тестирование стратегий обхода в изолированной песочнице..."
|
msgstr "Тестирование стратегий обхода в изолированной песочнице..."
|
||||||
|
|
||||||
@@ -4502,6 +4634,9 @@ msgstr "Время суток для запуска планового обно
|
|||||||
msgid "Time skew tolerance"
|
msgid "Time skew tolerance"
|
||||||
msgstr "Допуск отклонения времени"
|
msgstr "Допуск отклонения времени"
|
||||||
|
|
||||||
|
msgid "Timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "tiny"
|
msgid "tiny"
|
||||||
msgstr "tiny"
|
msgstr "tiny"
|
||||||
|
|
||||||
@@ -4727,6 +4862,9 @@ msgstr "Хранится до 10 снапшотов; самые старые у
|
|||||||
msgid "Update"
|
msgid "Update"
|
||||||
msgstr "Обновить"
|
msgstr "Обновить"
|
||||||
|
|
||||||
|
msgid "Update failed:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Update is available"
|
msgid "Update is available"
|
||||||
msgstr "Доступно обновление"
|
msgstr "Доступно обновление"
|
||||||
|
|
||||||
@@ -4739,6 +4877,9 @@ msgstr "Доступна новая версия:"
|
|||||||
msgid "Update lists now"
|
msgid "Update lists now"
|
||||||
msgstr "Обновить списки сейчас"
|
msgstr "Обновить списки сейчас"
|
||||||
|
|
||||||
|
msgid "Update Lists Now"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Update subscriptions"
|
msgid "Update subscriptions"
|
||||||
msgstr "Обновить подписки"
|
msgstr "Обновить подписки"
|
||||||
|
|
||||||
@@ -4760,6 +4901,9 @@ msgstr "Обновление режима маршрутизации устро
|
|||||||
msgid "Updating lists..."
|
msgid "Updating lists..."
|
||||||
msgstr "Обновление списков..."
|
msgstr "Обновление списков..."
|
||||||
|
|
||||||
|
msgid "Updating…"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Uplink"
|
msgid "Uplink"
|
||||||
msgstr "Исходящий"
|
msgstr "Исходящий"
|
||||||
|
|
||||||
@@ -4889,6 +5033,9 @@ msgstr "Значение не должно содержать символы у
|
|||||||
msgid "Verifying router and service readiness..."
|
msgid "Verifying router and service readiness..."
|
||||||
msgstr "Проверка готовности роутера и служб..."
|
msgstr "Проверка готовности роутера и служб..."
|
||||||
|
|
||||||
|
msgid "Versions"
|
||||||
|
msgstr "Версии"
|
||||||
|
|
||||||
msgid "Via country.is"
|
msgid "Via country.is"
|
||||||
msgstr "Через country.is"
|
msgstr "Через country.is"
|
||||||
|
|
||||||
@@ -4925,9 +5072,6 @@ msgstr "Токен доступа WARP"
|
|||||||
msgid "WARP Account ID"
|
msgid "WARP Account ID"
|
||||||
msgstr "ID аккаунта WARP"
|
msgstr "ID аккаунта WARP"
|
||||||
|
|
||||||
msgid "WARP Configuration generated and loaded successfully!"
|
|
||||||
msgstr "Конфигурация WARP успешно сгенерирована и загружена!"
|
|
||||||
|
|
||||||
msgid "WARP Generator Proxy Section"
|
msgid "WARP Generator Proxy Section"
|
||||||
msgstr "Секция прокси для генератора WARP"
|
msgstr "Секция прокси для генератора WARP"
|
||||||
|
|
||||||
@@ -4973,6 +5117,9 @@ msgstr "Приватный ключ WireGuard из вашего аккаунта
|
|||||||
msgid "Working"
|
msgid "Working"
|
||||||
msgstr "Рабочих"
|
msgstr "Рабочих"
|
||||||
|
|
||||||
|
msgid "working strategies"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "XHTTP mode"
|
msgid "XHTTP mode"
|
||||||
msgstr "Режим XHTTP"
|
msgstr "Режим XHTTP"
|
||||||
|
|
||||||
@@ -5039,6 +5186,24 @@ msgstr "sing-box outbound для Zapret2 настроен"
|
|||||||
msgid "Zapret2 sing-box outbound is not configured"
|
msgid "Zapret2 sing-box outbound is not configured"
|
||||||
msgstr "sing-box outbound для Zapret2 не настроен"
|
msgstr "sing-box outbound для Zapret2 не настроен"
|
||||||
|
|
||||||
|
msgid "⚡ Quick Benchmark (Presets ~12-14)"
|
||||||
|
msgstr "⚡ Быстрый бенчмарк (Пресеты ~12-14)"
|
||||||
|
|
||||||
|
msgid "🎬 YouTube Suite (Web + 4K Stream)"
|
||||||
|
msgstr "🎬 YouTube Suite (Web + 4K Stream)"
|
||||||
|
|
||||||
|
msgid "💬 Discord Suite (API + WSS + CDN)"
|
||||||
|
msgstr "💬 Discord Suite (API + WSS + CDN)"
|
||||||
|
|
||||||
|
msgid "🔍 Combinatorial Deep Fuzzing (~40-80+)"
|
||||||
|
msgstr "🔍 Комбинаторный глубокий фаззинг (~40-80+)"
|
||||||
|
|
||||||
|
msgid "Services are online, waiting for full initialization..."
|
||||||
|
msgstr "Сервисы запущены, ожидание полной инициализации..."
|
||||||
|
|
||||||
|
msgid "WARP Configuration generated and loaded successfully!"
|
||||||
|
msgstr "Конфигурация WARP успешно сгенерирована и загружена!"
|
||||||
|
|
||||||
msgid "⏹ Stop"
|
msgid "⏹ Stop"
|
||||||
msgstr "⏹ Стоп"
|
msgstr "⏹ Стоп"
|
||||||
|
|
||||||
@@ -5726,18 +5891,6 @@ msgstr "CleanBrowsing (Семейный)"
|
|||||||
msgid "Yandex Safe"
|
msgid "Yandex Safe"
|
||||||
msgstr "Yandex (Безопасный)"
|
msgstr "Yandex (Безопасный)"
|
||||||
|
|
||||||
msgid "Versions"
|
|
||||||
msgstr "Версии"
|
|
||||||
|
|
||||||
msgid "Loading versions..."
|
|
||||||
msgstr "Загрузка версий..."
|
|
||||||
|
|
||||||
msgid "No versions found"
|
|
||||||
msgstr "Версии не найдены"
|
|
||||||
|
|
||||||
msgid "Failed to load versions"
|
|
||||||
msgstr "Не удалось загрузить версии"
|
|
||||||
|
|
||||||
msgid "Installing "
|
msgid "Installing "
|
||||||
msgstr "Установка "
|
msgstr "Установка "
|
||||||
|
|
||||||
@@ -5750,5 +5903,26 @@ msgstr "Ошибка установки: "
|
|||||||
msgid "Installed "
|
msgid "Installed "
|
||||||
msgstr "Установлено "
|
msgstr "Установлено "
|
||||||
|
|
||||||
msgid "pre-release"
|
msgid "AmneziaWG 2.0"
|
||||||
msgstr "пре-релиз"
|
msgstr "AmneziaWG 2.0"
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.0"
|
||||||
|
msgstr "AmneziaWG 3.0"
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.1"
|
||||||
|
msgstr "AmneziaWG 3.1"
|
||||||
|
|
||||||
|
msgid "Protocol version: 2.0 (standard headers, WARP compatible), 3.0 (header protection key, padding ranges), or 3.1 (header protection key, padding ranges, advanced timers)"
|
||||||
|
msgstr "Версия протокола: 2.0 (стандартные заголовки, совместимо с WARP), 3.0 (ключ защиты заголовков, диапазоны паддинга), или 3.1 (ключ защиты заголовков, диапазоны паддинга, расширенные таймеры)"
|
||||||
|
|
||||||
|
msgid "AmneziaWG %s configuration generated and loaded successfully!"
|
||||||
|
msgstr "Конфигурация AmneziaWG %s успешно сгенерирована и загружена!"
|
||||||
|
|
||||||
|
msgid "Notice: Cloudflare WARP edge servers only support AmneziaWG 2.0 (standard headers). For Cloudflare WARP, select version 2.0. Versions 3.0 and 3.1 are intended for dedicated AmneziaWG servers."
|
||||||
|
msgstr "Обратите внимание: серверы Cloudflare WARP поддерживают только AmneziaWG 2.0 (стандартные заголовки). Для Cloudflare WARP выберите версию 2.0. Версии 3.0 и 3.1 предназначены для выделенных серверов AmneziaWG."
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.0 / 3.1 header protection key"
|
||||||
|
msgstr "Ключ защиты заголовков AmneziaWG 3.0 / 3.1"
|
||||||
|
|
||||||
|
msgid "AmneziaWG 3.0 / 3.1 content padding range, e.g. 38-104"
|
||||||
|
msgstr "Диапазон дополнительного паддинга контента AmneziaWG 3.0 / 3.1, например 38-104"
|
||||||
|
|||||||
+2287
-1917
File diff suppressed because it is too large
Load Diff
@@ -282,7 +282,7 @@ function command_spec(command) {
|
|||||||
fuzzer_auto_apply: [ "diagnostics/fuzzer.uc", "auto_apply", 1 ],
|
fuzzer_auto_apply: [ "diagnostics/fuzzer.uc", "auto_apply", 1 ],
|
||||||
fuzzer_history: [ "diagnostics/fuzzer.uc", "history", 1 ],
|
fuzzer_history: [ "diagnostics/fuzzer.uc", "history", 1 ],
|
||||||
fuzzer_clear_history: [ "diagnostics/fuzzer.uc", "clear_history", 0 ],
|
fuzzer_clear_history: [ "diagnostics/fuzzer.uc", "clear_history", 0 ],
|
||||||
generate_warp: [ "service/warp_generator.uc", "", 1 ],
|
generate_warp: [ "service/warp_generator.uc", "", 2 ],
|
||||||
package_prerm: [ "service/package.uc", "prerm", 1 ],
|
package_prerm: [ "service/package.uc", "prerm", 1 ],
|
||||||
package_postinst: [ "service/package.uc", "postinst", 0 ],
|
package_postinst: [ "service/package.uc", "postinst", 0 ],
|
||||||
luci_postinst: [ "service/package.uc", "luci-postinst", 0 ],
|
luci_postinst: [ "service/package.uc", "luci-postinst", 0 ],
|
||||||
|
|||||||
@@ -176,6 +176,12 @@ function awg_tag_chain(value) {
|
|||||||
if (value == "" || value == "0")
|
if (value == "" || value == "0")
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
|
// Heal previously truncated tag chains (e.g. from broken conf import)
|
||||||
|
if (match(value, /^[0-9a-fA-F]+><[^<>]+>/))
|
||||||
|
value = "<b 0x" + value;
|
||||||
|
if (match(value, /<[^<>]+$/))
|
||||||
|
value = value + ">";
|
||||||
|
|
||||||
// A well-formed tag chain: keep it verbatim, including inner spacing
|
// A well-formed tag chain: keep it verbatim, including inner spacing
|
||||||
// ("<b 0x..>" carries a space inside each tag).
|
// ("<b 0x..>" carries a space inside each tag).
|
||||||
if (match(value, /^(<[^<>]+>)+$/))
|
if (match(value, /^(<[^<>]+>)+$/))
|
||||||
|
|||||||
@@ -641,7 +641,7 @@ function section_has_dscp_matchers(section) {
|
|||||||
|
|
||||||
function section_needs_priority_sets(section) {
|
function section_needs_priority_sets(section) {
|
||||||
return section_priority_action(section) != "" &&
|
return section_priority_action(section) != "" &&
|
||||||
(section_has_nft_ip_matchers(section) || section_has_nft_port_only_matchers(section) || section_has_dscp_matchers(section));
|
(section_has_nft_ip_matchers(section) || section_has_nft_port_only_matchers(section) || section_has_dscp_matchers(section) || section_has_source_ip_matchers(section));
|
||||||
}
|
}
|
||||||
|
|
||||||
function nft_create_priority_chains(table) {
|
function nft_create_priority_chains(table) {
|
||||||
@@ -791,6 +791,28 @@ function nft_add_section_priority_rules(table, section, interface_set, localv4_s
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let has_source_only_matchers = section_has_source_ip_matchers(section) &&
|
||||||
|
!needs_plain_ip_rules &&
|
||||||
|
!needs_ip_port_rules &&
|
||||||
|
!has_port_only_matchers &&
|
||||||
|
!section_has_dscp_matchers(section);
|
||||||
|
|
||||||
|
if (has_source_only_matchers) {
|
||||||
|
if (is_bypass) {
|
||||||
|
if (!nft_add_priority_rule_pair(table, "priority_rules", section, interface_set, localv4_set, localv6_set, [], [], mark) ||
|
||||||
|
!nft_add_priority_rule_pair(table, "priority_output_rules", section, interface_set, localv4_set, localv6_set, [], [], mark))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
let match_tcp = [ "meta", "l4proto", "tcp" ];
|
||||||
|
let match_udp = [ "meta", "l4proto", "udp" ];
|
||||||
|
if (!nft_add_priority_rule_pair(table, "priority_rules", section, interface_set, localv4_set, localv6_set, match_tcp, match_tcp, mark) ||
|
||||||
|
!nft_add_priority_rule_pair(table, "priority_rules", section, interface_set, localv4_set, localv6_set, match_udp, match_udp, mark) ||
|
||||||
|
!nft_add_priority_rule_pair(table, "priority_output_rules", section, interface_set, localv4_set, localv6_set, match_tcp, match_tcp, mark) ||
|
||||||
|
!nft_add_priority_rule_pair(table, "priority_output_rules", section, interface_set, localv4_set, localv6_set, match_udp, match_udp, mark))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -424,7 +424,17 @@ if (!response_data.warp_enabled) {
|
|||||||
fs.unlink(tmp_patch);
|
fs.unlink(tmp_patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
let license_key = ARGV[0] || "";
|
let target_version = "2.0";
|
||||||
|
let license_key = "";
|
||||||
|
|
||||||
|
for (let a in ARGV) {
|
||||||
|
if (a == "2.0" || a == "3.1") {
|
||||||
|
target_version = a;
|
||||||
|
} else if (a != null && trim(a) != "") {
|
||||||
|
license_key = trim(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (license_key != "") {
|
if (license_key != "") {
|
||||||
let patch_body = { license_key: license_key };
|
let patch_body = { license_key: license_key };
|
||||||
let tmp_patch = exec_output("mktemp 2>/dev/null") || "/tmp/warp_patch.json";
|
let tmp_patch = exec_output("mktemp 2>/dev/null") || "/tmp/warp_patch.json";
|
||||||
@@ -511,23 +521,71 @@ let i3 = to_hex(generate_extra_cps());
|
|||||||
let i4 = to_hex(generate_extra_cps());
|
let i4 = to_hex(generate_extra_cps());
|
||||||
let i5 = to_hex(generate_extra_cps());
|
let i5 = to_hex(generate_extra_cps());
|
||||||
|
|
||||||
write_json({
|
function generate_base64_key() {
|
||||||
|
let k = exec_output("head -c 32 /dev/urandom | base64 2>/dev/null");
|
||||||
|
if (k != "") {
|
||||||
|
k = replace(trim(k), /[\r\n\t ]/g, "");
|
||||||
|
if (length(k) >= 40) return k;
|
||||||
|
}
|
||||||
|
let pair = exec_output("/usr/bin/sing-box generate wg-keypair 2>/dev/null");
|
||||||
|
for (let l in split(pair, "\n")) {
|
||||||
|
let m = match(l, /^PrivateKey:\s*(.+)$/);
|
||||||
|
if (m) return trim(m[1]);
|
||||||
|
}
|
||||||
|
return "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
||||||
|
}
|
||||||
|
|
||||||
|
function random_range(min_bound, max_bound, span_min, span_max) {
|
||||||
|
let span = span_min + (time() * 7 + int(exec_output("head -c 2 /dev/urandom | hexdump -ve '1/2 \"%u\"' 2>/dev/null") || "1000")) % (span_max - span_min + 1);
|
||||||
|
let start = min_bound + (time() * 13 + int(exec_output("head -c 4 /dev/urandom | hexdump -ve '1/4 \"%u\"' 2>/dev/null") || "50000")) % (max_bound - min_bound - span);
|
||||||
|
let end = start + span;
|
||||||
|
return sprintf("%u-%u", start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
function random_s() {
|
||||||
|
let r = 20 + (int(exec_output("head -c 2 /dev/urandom | hexdump -ve '1/2 \"%u\"' 2>/dev/null") || "50")) % 130;
|
||||||
|
return r >= 12 ? r : 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
let req_version = "2.0";
|
||||||
|
if (length(ARGV) > 2 && ARGV[2] != "") {
|
||||||
|
req_version = trim(ARGV[2]);
|
||||||
|
} else if (length(ARGV) > 1 && (ARGV[1] == "2.0" || ARGV[1] == "3.0" || ARGV[1] == "3.1")) {
|
||||||
|
req_version = trim(ARGV[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cloudflare WARP servers ONLY support standard WireGuard / AWG 2.0 headers.
|
||||||
|
// They do NOT run AmneziaWG and do not support HeaderProtectionKey or AWG 3.x.
|
||||||
|
// Therefore, the WARP generator always outputs a working AWG 2.0 configuration.
|
||||||
|
let result = {
|
||||||
success: true,
|
success: true,
|
||||||
local_address: response_data.config.interface.addresses.v4 + "/32 " + response_data.config.interface.addresses.v6 + "/128",
|
local_address: response_data.config.interface.addresses.v4 + "/32 " + response_data.config.interface.addresses.v6 + "/128",
|
||||||
private_key: private_key,
|
private_key: private_key,
|
||||||
peer_public_key: response_data.config.peers[0].public_key,
|
peer_public_key: response_data.config.peers[0].public_key,
|
||||||
server_address: best_ip,
|
server_address: best_ip,
|
||||||
server_port: random_port,
|
server_port: random_port,
|
||||||
|
awg_version: "2.0",
|
||||||
awg_jc: 4,
|
awg_jc: 5,
|
||||||
awg_jmin: 40,
|
awg_jmin: 40,
|
||||||
awg_jmax: 70,
|
awg_jmax: 70,
|
||||||
awg_s1: 0, awg_s2: 0, awg_s3: 0, awg_s4: 0,
|
awg_s1: 0,
|
||||||
awg_h1: 1, awg_h2: 2, awg_h3: 3, awg_h4: 4,
|
awg_s2: 0,
|
||||||
|
awg_s3: 0,
|
||||||
|
awg_s4: 0,
|
||||||
|
awg_h1: 1,
|
||||||
|
awg_h2: 2,
|
||||||
|
awg_h3: 3,
|
||||||
|
awg_h4: 4,
|
||||||
awg_i1: i1,
|
awg_i1: i1,
|
||||||
awg_i2: i2,
|
awg_i2: i2,
|
||||||
awg_i3: i3,
|
awg_i3: i3,
|
||||||
awg_i4: i4,
|
awg_i4: i4,
|
||||||
awg_i5: i5
|
awg_i5: i5
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (req_version != "2.0") {
|
||||||
|
result.message_hint = "warning_warp_needs_awg20";
|
||||||
|
}
|
||||||
|
|
||||||
|
write_json(result);
|
||||||
|
|
||||||
|
|||||||
@@ -1303,8 +1303,10 @@ function add_awg_endpoint(config, section) {
|
|||||||
let j2 = awg_cps_option(section, "awg_j2");
|
let j2 = awg_cps_option(section, "awg_j2");
|
||||||
let j3 = awg_cps_option(section, "awg_j3");
|
let j3 = awg_cps_option(section, "awg_j3");
|
||||||
let itime = int_option(section, "awg_itime", "0");
|
let itime = int_option(section, "awg_itime", "0");
|
||||||
let is_lx = trim(fs.readfile("/etc/tachyon/sing-box-variant") || "") == "lx" ||
|
let sb_variant_file = getenv("SB_VARIANT_STATE_FILE") || "/etc/tachyon/sing-box-variant";
|
||||||
index(trim(fs.readfile("/etc/tachyon/sing-box-version") || ""), "-lx") >= 0;
|
let sb_version_file = getenv("SB_VERSION_STATE_FILE") || "/etc/tachyon/sing-box-version";
|
||||||
|
let sb_version_val = trim(fs.readfile(sb_version_file) || "");
|
||||||
|
let is_lx = sb_version_val != "" ? (index(sb_version_val, "-lx") >= 0) : (trim(fs.readfile(sb_variant_file) || "") == "lx");
|
||||||
|
|
||||||
if (is_lx) {
|
if (is_lx) {
|
||||||
// sing-box-lx expects AWG fields at the endpoint root (AWG 2.0 schema).
|
// sing-box-lx expects AWG fields at the endpoint root (AWG 2.0 schema).
|
||||||
@@ -1326,6 +1328,52 @@ function add_awg_endpoint(config, section) {
|
|||||||
if (i3 != "" && i3 != "0") endpoint.i3 = i3;
|
if (i3 != "" && i3 != "0") endpoint.i3 = i3;
|
||||||
if (i4 != "" && i4 != "0") endpoint.i4 = i4;
|
if (i4 != "" && i4 != "0") endpoint.i4 = i4;
|
||||||
if (i5 != "" && i5 != "0") endpoint.i5 = i5;
|
if (i5 != "" && i5 != "0") endpoint.i5 = i5;
|
||||||
|
|
||||||
|
// AmneziaWG version handling: 2.0, 3.0, and 3.1 (sing-box-lx v1.14.0-lx.32+)
|
||||||
|
let awg_ver = option(section, "awg_version", "");
|
||||||
|
if (awg_ver == "") {
|
||||||
|
if (option(section, "awg_rekey_after_time", "") != "" || option(section, "awg_rekey_timeout", "") != "" ||
|
||||||
|
option(section, "awg_reject_after_time", "") != "" || option(section, "awg_keepalive_timeout", "") != "" ||
|
||||||
|
option(section, "awg_max_handshake_attempts", "") != "") {
|
||||||
|
awg_ver = "3.1";
|
||||||
|
} else if (option(section, "awg_header_protection_key", "") != "" || option(section, "awg_content_padding_addition", "") != "") {
|
||||||
|
awg_ver = "3.0";
|
||||||
|
} else {
|
||||||
|
awg_ver = "2.0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (awg_ver == "3.0" || awg_ver == "3.1") {
|
||||||
|
let hpk = option(section, "awg_header_protection_key", "");
|
||||||
|
if (hpk != "") {
|
||||||
|
// Ensure S1-S4 are >= 12 if header_protection_key is set (sing-box-lx schema requirement)
|
||||||
|
if (endpoint.s1 < 12) endpoint.s1 = 20;
|
||||||
|
if (endpoint.s2 < 12) endpoint.s2 = 20;
|
||||||
|
if (endpoint.s3 < 12) endpoint.s3 = 20;
|
||||||
|
if (endpoint.s4 < 12) endpoint.s4 = 20;
|
||||||
|
endpoint.header_protection_key = hpk;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cpa = option(section, "awg_content_padding_addition", "");
|
||||||
|
if (cpa != "") endpoint.content_padding_addition = cpa;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (awg_ver == "3.1") {
|
||||||
|
let rka = option(section, "awg_rekey_after_time", "");
|
||||||
|
if (rka != "") endpoint.rekey_after_time = rka;
|
||||||
|
|
||||||
|
let rkt = option(section, "awg_rekey_timeout", "");
|
||||||
|
if (rkt != "") endpoint.rekey_timeout = rkt;
|
||||||
|
|
||||||
|
let rja = option(section, "awg_reject_after_time", "");
|
||||||
|
if (rja != "") endpoint.reject_after_time = rja;
|
||||||
|
|
||||||
|
let kpt = option(section, "awg_keepalive_timeout", "");
|
||||||
|
if (kpt != "") endpoint.keepalive_timeout = kpt;
|
||||||
|
|
||||||
|
let mha = option(section, "awg_max_handshake_attempts", "");
|
||||||
|
if (mha != "") endpoint.max_handshake_attempts = mha;
|
||||||
|
}
|
||||||
// j1-j3/itime are sing-box-extended-only fields and are not part of
|
// j1-j3/itime are sing-box-extended-only fields and are not part of
|
||||||
// the lx AWG 2.0 schema, so they are intentionally not emitted here.
|
// the lx AWG 2.0 schema, so they are intentionally not emitted here.
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1340,7 +1340,9 @@ function add_combined_route_for_section(config, section) {
|
|||||||
|
|
||||||
let has_route_matchers = route_rule.domain != null || route_rule.domain_suffix != null ||
|
let has_route_matchers = route_rule.domain != null || route_rule.domain_suffix != null ||
|
||||||
route_rule.domain_keyword != null || route_rule.domain_regex != null ||
|
route_rule.domain_keyword != null || route_rule.domain_regex != null ||
|
||||||
route_rule.ip_cidr != null || route_rule.port != null || route_rule.port_range != null ||
|
route_rule.ip_cidr != null || route_rule.source_ip_cidr != null ||
|
||||||
|
route_rule.port != null || route_rule.port_range != null ||
|
||||||
|
route_rule.protocol != null || route_rule.dscp != null ||
|
||||||
route_rule.rule_set != null;
|
route_rule.rule_set != null;
|
||||||
if (has_route_matchers) {
|
if (has_route_matchers) {
|
||||||
let resolve = runtime_route.resolve_rule_for_section(section, route_rule);
|
let resolve = runtime_route.resolve_rule_for_section(section, route_rule);
|
||||||
|
|||||||
@@ -989,6 +989,27 @@ function init_config(populate_nft, caches_prepared, no_refresh) {
|
|||||||
stripped = true;
|
stripped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (match(check_result.reason, /header_protection_key/)) {
|
||||||
|
log_message("Installed sing-box rejected header_protection_key: " + check_result.reason + "; stripping and retrying", "warn");
|
||||||
|
let cfg_text = as_string(fs.readfile(temp_config) || "");
|
||||||
|
let cfg = length(cfg_text) > 0 ? json(cfg_text) : null;
|
||||||
|
if (type(cfg) == "object") {
|
||||||
|
if (type(cfg.endpoints) == "array") {
|
||||||
|
for (let ep in cfg.endpoints) {
|
||||||
|
if (type(ep) == "object" && ep.header_protection_key != null)
|
||||||
|
delete ep.header_protection_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type(cfg.inbounds) == "array") {
|
||||||
|
for (let inb in cfg.inbounds) {
|
||||||
|
if (type(inb) == "object" && inb.header_protection_key != null)
|
||||||
|
delete inb.header_protection_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write_file(temp_config, sprintf("%J", cfg));
|
||||||
|
stripped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!stripped)
|
if (!stripped)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -212,6 +212,10 @@ function apply_transport(inbound, section, protocol) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function add_standard_inbound(config, section, protocol, tag_name) {
|
function add_standard_inbound(config, section, protocol, tag_name) {
|
||||||
|
let sb_variant_file = getenv("SB_VARIANT_STATE_FILE") || "/etc/tachyon/sing-box-variant";
|
||||||
|
let sb_version_file = getenv("SB_VERSION_STATE_FILE") || "/etc/tachyon/sing-box-version";
|
||||||
|
let sb_version_val = trim(fs.readfile(sb_version_file) || "");
|
||||||
|
let is_lx = sb_version_val != "" ? (index(sb_version_val, "-lx") >= 0) : (trim(fs.readfile(sb_variant_file) || "") == "lx");
|
||||||
let inbound = {
|
let inbound = {
|
||||||
type: protocol,
|
type: protocol,
|
||||||
tag: tag_name,
|
tag: tag_name,
|
||||||
@@ -305,8 +309,6 @@ function add_standard_inbound(config, section, protocol, tag_name) {
|
|||||||
let jmin = int_option(section, "awg_jmin", "40");
|
let jmin = int_option(section, "awg_jmin", "40");
|
||||||
let jmax = int_option(section, "awg_jmax", "70");
|
let jmax = int_option(section, "awg_jmax", "70");
|
||||||
if (jmax > 1200) jmax = 1200;
|
if (jmax > 1200) jmax = 1200;
|
||||||
let is_lx = trim(fs.readfile("/etc/tachyon/sing-box-variant") || "") == "lx" ||
|
|
||||||
index(trim(fs.readfile("/etc/tachyon/sing-box-version") || ""), "-lx") >= 0;
|
|
||||||
|
|
||||||
let amnezia = {
|
let amnezia = {
|
||||||
jc: jc,
|
jc: jc,
|
||||||
@@ -354,6 +356,52 @@ function add_standard_inbound(config, section, protocol, tag_name) {
|
|||||||
if (i3 != "" && i3 != "0") inbound.i3 = i3;
|
if (i3 != "" && i3 != "0") inbound.i3 = i3;
|
||||||
if (i4 != "" && i4 != "0") inbound.i4 = i4;
|
if (i4 != "" && i4 != "0") inbound.i4 = i4;
|
||||||
if (i5 != "" && i5 != "0") inbound.i5 = i5;
|
if (i5 != "" && i5 != "0") inbound.i5 = i5;
|
||||||
|
|
||||||
|
// AmneziaWG version handling: 2.0, 3.0, and 3.1 (sing-box-lx v1.14.0-lx.32+)
|
||||||
|
let awg_ver = option(section, "awg_version", "");
|
||||||
|
if (awg_ver == "") {
|
||||||
|
if (option(section, "awg_rekey_after_time", "") != "" || option(section, "awg_rekey_timeout", "") != "" ||
|
||||||
|
option(section, "awg_reject_after_time", "") != "" || option(section, "awg_keepalive_timeout", "") != "" ||
|
||||||
|
option(section, "awg_max_handshake_attempts", "") != "") {
|
||||||
|
awg_ver = "3.1";
|
||||||
|
} else if (option(section, "awg_header_protection_key", "") != "" || option(section, "awg_content_padding_addition", "") != "") {
|
||||||
|
awg_ver = "3.0";
|
||||||
|
} else {
|
||||||
|
awg_ver = "2.0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (awg_ver == "3.0" || awg_ver == "3.1") {
|
||||||
|
let hpk = option(section, "awg_header_protection_key", "");
|
||||||
|
if (hpk != "") {
|
||||||
|
// Ensure S1-S4 are >= 12 if header_protection_key is set (sing-box-lx schema requirement)
|
||||||
|
if (inbound.s1 < 12) inbound.s1 = 20;
|
||||||
|
if (inbound.s2 < 12) inbound.s2 = 20;
|
||||||
|
if (inbound.s3 < 12) inbound.s3 = 20;
|
||||||
|
if (inbound.s4 < 12) inbound.s4 = 20;
|
||||||
|
inbound.header_protection_key = hpk;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cpa = option(section, "awg_content_padding_addition", "");
|
||||||
|
if (cpa != "") inbound.content_padding_addition = cpa;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (awg_ver == "3.1") {
|
||||||
|
let rka = option(section, "awg_rekey_after_time", "");
|
||||||
|
if (rka != "") inbound.rekey_after_time = rka;
|
||||||
|
|
||||||
|
let rkt = option(section, "awg_rekey_timeout", "");
|
||||||
|
if (rkt != "") inbound.rekey_timeout = rkt;
|
||||||
|
|
||||||
|
let rja = option(section, "awg_reject_after_time", "");
|
||||||
|
if (rja != "") inbound.reject_after_time = rja;
|
||||||
|
|
||||||
|
let kpt = option(section, "awg_keepalive_timeout", "");
|
||||||
|
if (kpt != "") inbound.keepalive_timeout = kpt;
|
||||||
|
|
||||||
|
let mha = option(section, "awg_max_handshake_attempts", "");
|
||||||
|
if (mha != "") inbound.max_handshake_attempts = mha;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (i1 != "") amnezia.i1 = i1;
|
if (i1 != "") amnezia.i1 = i1;
|
||||||
if (i2 != "") amnezia.i2 = i2;
|
if (i2 != "") amnezia.i2 = i2;
|
||||||
@@ -380,7 +428,16 @@ function add_standard_inbound(config, section, protocol, tag_name) {
|
|||||||
|
|
||||||
apply_tls(inbound, section, protocol);
|
apply_tls(inbound, section, protocol);
|
||||||
apply_transport(inbound, section, protocol);
|
apply_transport(inbound, section, protocol);
|
||||||
push(config.inbounds, inbound);
|
if (protocol == "awg" && is_lx) {
|
||||||
|
let server_port = int_option(section, "awg_server_port", int_option(section, "listen_port", 51820));
|
||||||
|
inbound.listen_port = server_port;
|
||||||
|
delete inbound.listen;
|
||||||
|
if (!config.endpoints)
|
||||||
|
config.endpoints = [];
|
||||||
|
push(config.endpoints, inbound);
|
||||||
|
} else {
|
||||||
|
push(config.inbounds, inbound);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_json_inbound(config, section, tag_name) {
|
function add_json_inbound(config, section, tag_name) {
|
||||||
|
|||||||
@@ -328,6 +328,20 @@ cat >"$WORK_DIR/priority-rules.json" <<'JSON'
|
|||||||
"enabled": "1",
|
"enabled": "1",
|
||||||
"action": "bypass",
|
"action": "bypass",
|
||||||
"ports": [ "8443" ]
|
"ports": [ "8443" ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
".name": "source_bypass",
|
||||||
|
".type": "section",
|
||||||
|
"enabled": "1",
|
||||||
|
"action": "bypass",
|
||||||
|
"source_ip_cidr": [ "192.168.1.50/32" ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
".name": "source_proxy",
|
||||||
|
".type": "section",
|
||||||
|
"enabled": "1",
|
||||||
|
"action": "proxy",
|
||||||
|
"source_ip_cidr": [ "192.168.1.60/32" ]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -341,6 +355,9 @@ assert_contains "$NFT_LOG" $'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\
|
|||||||
assert_contains "$NFT_LOG" $'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tdaddr\t!=\t@localv4\tip\tdaddr\t@tachyon_rule_wide_proxy_subnets\tmeta\tl4proto\ttcp\tmeta\tmark\tset\t0x00100000\tcounter\taccept' "proxy priority capture tcp rule"
|
assert_contains "$NFT_LOG" $'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tdaddr\t!=\t@localv4\tip\tdaddr\t@tachyon_rule_wide_proxy_subnets\tmeta\tl4proto\ttcp\tmeta\tmark\tset\t0x00100000\tcounter\taccept' "proxy priority capture tcp rule"
|
||||||
assert_contains "$NFT_LOG" $'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tdaddr\t!=\t@localv4\tip\tdaddr\t@tachyon_rule_wide_proxy_subnets\tmeta\tl4proto\tudp\tmeta\tmark\tset\t0x00100000\tcounter\taccept' "proxy priority capture udp rule"
|
assert_contains "$NFT_LOG" $'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tdaddr\t!=\t@localv4\tip\tdaddr\t@tachyon_rule_wide_proxy_subnets\tmeta\tl4proto\tudp\tmeta\tmark\tset\t0x00100000\tcounter\taccept' "proxy priority capture udp rule"
|
||||||
assert_contains "$NFT_LOG" $'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tdaddr\t!=\t@localv4\ttcp\tdport\t@tachyon_rule_port_bypass_ports\tcounter\taccept' "port-only bypass priority rule"
|
assert_contains "$NFT_LOG" $'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tdaddr\t!=\t@localv4\ttcp\tdport\t@tachyon_rule_port_bypass_ports\tcounter\taccept' "port-only bypass priority rule"
|
||||||
|
assert_contains "$NFT_LOG" $'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tsaddr\t@tachyon_rule_source_bypass_sources\tip\tdaddr\t!=\t@localv4\tcounter\taccept' "source-only bypass priority rule"
|
||||||
|
assert_contains "$NFT_LOG" $'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tsaddr\t@tachyon_rule_source_proxy_sources\tip\tdaddr\t!=\t@localv4\tmeta\tl4proto\ttcp\tmeta\tmark\tset\t0x00100000\tcounter\taccept' "source-only proxy tcp priority rule"
|
||||||
|
assert_contains "$NFT_LOG" $'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tsaddr\t@tachyon_rule_source_proxy_sources\tip\tdaddr\t!=\t@localv4\tmeta\tl4proto\tudp\tmeta\tmark\tset\t0x00100000\tcounter\taccept' "source-only proxy udp priority rule"
|
||||||
assert_line_before "$NFT_LOG" \
|
assert_line_before "$NFT_LOG" \
|
||||||
$'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tdaddr\t!=\t@localv4\tip\tdaddr\t@tachyon_rule_bypass_first_subnets\tcounter\taccept' \
|
$'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tdaddr\t!=\t@localv4\tip\tdaddr\t@tachyon_rule_bypass_first_subnets\tcounter\taccept' \
|
||||||
$'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tdaddr\t!=\t@localv4\tip\tdaddr\t@tachyon_rule_wide_proxy_subnets\tmeta\tl4proto\ttcp\tmeta\tmark\tset\t0x00100000\tcounter\taccept' \
|
$'nft\tadd\trule\tinet\tTachyonTable\tpriority_rules\tiifname\t@tachyon_interfaces\tip\tdaddr\t!=\t@localv4\tip\tdaddr\t@tachyon_rule_wide_proxy_subnets\tmeta\tl4proto\ttcp\tmeta\tmark\tset\t0x00100000\tcounter\taccept' \
|
||||||
|
|||||||
+69
-2
@@ -16,7 +16,7 @@ fail() {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# 1. Test sing-box configuration generation with AWG server
|
# 1. Test sing-box configuration generation with AWG server (2.0, 3.0, and 3.1)
|
||||||
cat >"$WORK_DIR/awg_fixture.json" <<'JSON'
|
cat >"$WORK_DIR/awg_fixture.json" <<'JSON'
|
||||||
{
|
{
|
||||||
"settings": {
|
"settings": {
|
||||||
@@ -30,6 +30,7 @@ cat >"$WORK_DIR/awg_fixture.json" <<'JSON'
|
|||||||
".type": "server",
|
".type": "server",
|
||||||
"enabled": "1",
|
"enabled": "1",
|
||||||
"protocol": "awg",
|
"protocol": "awg",
|
||||||
|
"awg_version": "2.0",
|
||||||
"awg_private_key": "aW5ib3VuZF9wcml2YXRlX2tleQ==",
|
"awg_private_key": "aW5ib3VuZF9wcml2YXRlX2tleQ==",
|
||||||
"awg_peer_public_key": "cGVlcl9wdWJsaWNfa2V5",
|
"awg_peer_public_key": "cGVlcl9wdWJsaWNfa2V5",
|
||||||
"awg_server_address": "192.168.1.100",
|
"awg_server_address": "192.168.1.100",
|
||||||
@@ -44,6 +45,59 @@ cat >"$WORK_DIR/awg_fixture.json" <<'JSON'
|
|||||||
"awg_h2": "200",
|
"awg_h2": "200",
|
||||||
"awg_h3": "300",
|
"awg_h3": "300",
|
||||||
"awg_h4": "400"
|
"awg_h4": "400"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
".name": "my_awg30_server",
|
||||||
|
".type": "server",
|
||||||
|
"enabled": "1",
|
||||||
|
"protocol": "awg",
|
||||||
|
"awg_version": "3.0",
|
||||||
|
"awg_private_key": "aW5ib3VuZF9wcml2YXRlX2tleQ==",
|
||||||
|
"awg_peer_public_key": "cGVlcl9wdWJsaWNfa2V5",
|
||||||
|
"awg_server_address": "192.168.1.100",
|
||||||
|
"awg_server_port": "51821",
|
||||||
|
"awg_local_address": ["10.0.0.1/24"],
|
||||||
|
"awg_jc": "6",
|
||||||
|
"awg_jmin": "200",
|
||||||
|
"awg_jmax": "600",
|
||||||
|
"awg_s1": "20",
|
||||||
|
"awg_s2": "30",
|
||||||
|
"awg_h1": "100-200",
|
||||||
|
"awg_h2": "300-400",
|
||||||
|
"awg_h3": "500-600",
|
||||||
|
"awg_h4": "700-800",
|
||||||
|
"awg_header_protection_key": "dyBkZypS0O8PSlG0Ide3Agjp4Fng3YdYlPvXzZIldYQ=",
|
||||||
|
"awg_content_padding_addition": "38-104"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
".name": "my_awg31_server",
|
||||||
|
".type": "server",
|
||||||
|
"enabled": "1",
|
||||||
|
"protocol": "awg",
|
||||||
|
"awg_version": "3.1",
|
||||||
|
"awg_private_key": "aW5ib3VuZF9wcml2YXRlX2tleQ==",
|
||||||
|
"awg_peer_public_key": "cGVlcl9wdWJsaWNfa2V5",
|
||||||
|
"awg_server_address": "192.168.1.100",
|
||||||
|
"awg_server_port": "51822",
|
||||||
|
"awg_local_address": ["10.0.0.1/24"],
|
||||||
|
"awg_jc": "6",
|
||||||
|
"awg_jmin": "292",
|
||||||
|
"awg_jmax": "743",
|
||||||
|
"awg_s1": "28",
|
||||||
|
"awg_s2": "130",
|
||||||
|
"awg_s3": "53",
|
||||||
|
"awg_s4": "25",
|
||||||
|
"awg_h1": "179761265-179779753",
|
||||||
|
"awg_h2": "1691691036-1691701489",
|
||||||
|
"awg_h3": "2788983576-2789001884",
|
||||||
|
"awg_h4": "3784650023-3784673067",
|
||||||
|
"awg_header_protection_key": "dyBkZypS0O8PSlG0Ide3Agjp4Fng3YdYlPvXzZIldYQ=",
|
||||||
|
"awg_content_padding_addition": "38-104",
|
||||||
|
"awg_rekey_after_time": "107-132",
|
||||||
|
"awg_rekey_timeout": "5-6",
|
||||||
|
"awg_reject_after_time": "171-193",
|
||||||
|
"awg_keepalive_timeout": "11-18",
|
||||||
|
"awg_max_handshake_attempts": "15-24"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"section": [
|
"section": [
|
||||||
@@ -69,4 +123,17 @@ grep -q '"jc": 5' "$out_json" || fail "sing-box config missing amnezia jc parame
|
|||||||
grep -q '"s1": 15' "$out_json" || fail "sing-box config missing amnezia s1 parameter"
|
grep -q '"s1": 15' "$out_json" || fail "sing-box config missing amnezia s1 parameter"
|
||||||
grep -q '"h1": 100' "$out_json" || fail "sing-box config missing amnezia h1 parameter"
|
grep -q '"h1": 100' "$out_json" || fail "sing-box config missing amnezia h1 parameter"
|
||||||
|
|
||||||
printf 'AWG server configuration checks passed\n'
|
# Check AWG 3.0 server inbound
|
||||||
|
grep -q '"tag": "server-my_awg30_server-in"' "$out_json" || fail "sing-box config missing server-my_awg30_server-in tag"
|
||||||
|
grep -q '"header_protection_key": "dyBkZypS0O8PSlG0Ide3Agjp4Fng3YdYlPvXzZIldYQ="' "$out_json" || fail "AWG 3.0 server missing header_protection_key"
|
||||||
|
grep -q '"content_padding_addition": "38-104"' "$out_json" || fail "AWG 3.0 server missing content_padding_addition"
|
||||||
|
|
||||||
|
# Check AWG 3.1 server inbound
|
||||||
|
grep -q '"tag": "server-my_awg31_server-in"' "$out_json" || fail "sing-box config missing server-my_awg31_server-in tag"
|
||||||
|
grep -q '"rekey_after_time": "107-132"' "$out_json" || fail "AWG 3.1 server missing rekey_after_time"
|
||||||
|
grep -q '"rekey_timeout": "5-6"' "$out_json" || fail "AWG 3.1 server missing rekey_timeout"
|
||||||
|
grep -q '"reject_after_time": "171-193"' "$out_json" || fail "AWG 3.1 server missing reject_after_time"
|
||||||
|
grep -q '"keepalive_timeout": "11-18"' "$out_json" || fail "AWG 3.1 server missing keepalive_timeout"
|
||||||
|
grep -q '"max_handshake_attempts": "15-24"' "$out_json" || fail "AWG 3.1 server missing max_handshake_attempts"
|
||||||
|
|
||||||
|
printf 'AWG 2.0, 3.0, and 3.1 server configuration checks passed\n'
|
||||||
|
|||||||
@@ -344,6 +344,14 @@ cat >"$WORK_DIR/runtime-matchers-fixture.json" <<'JSON'
|
|||||||
"mixed_proxy_auth_enabled": "1",
|
"mixed_proxy_auth_enabled": "1",
|
||||||
"mixed_proxy_username": "user",
|
"mixed_proxy_username": "user",
|
||||||
"mixed_proxy_password": "pass"
|
"mixed_proxy_password": "pass"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
".name": "source_only",
|
||||||
|
".type": "section",
|
||||||
|
"enabled": "1",
|
||||||
|
"action": "connection",
|
||||||
|
"selector_proxy_links": [ "socks5://127.0.0.1:1080" ],
|
||||||
|
"source_ip_cidr": [ "192.168.1.77/32" ]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1242,6 +1250,7 @@ assert(route_rule(matchers, r => r.outbound == "proxy-out" && contains(r.domain_
|
|||||||
assert(route_rule(matchers, r => contains(r.inbound, "tproxy-in") && contains(r.inbound, "tproxy6-in") && r.outbound == "proxy-out") != null, "section route dual tproxy inbound");
|
assert(route_rule(matchers, r => contains(r.inbound, "tproxy-in") && contains(r.inbound, "tproxy6-in") && r.outbound == "proxy-out") != null, "section route dual tproxy inbound");
|
||||||
assert(route_rule(matchers, r => r.outbound == "direct-out" && contains(r.source_ip_cidr, "192.168.1.5/32")) == null, "routing excluded source removed");
|
assert(route_rule(matchers, r => r.outbound == "direct-out" && contains(r.source_ip_cidr, "192.168.1.5/32")) == null, "routing excluded source removed");
|
||||||
assert(route_rule(matchers, r => r.outbound == "proxy-out" && contains(r.source_ip_cidr, "10.0.0.2/32") && contains(r.source_ip_cidr, "2001:db8::2/128")) != null, "source_ip_cidr matcher");
|
assert(route_rule(matchers, r => r.outbound == "proxy-out" && contains(r.source_ip_cidr, "10.0.0.2/32") && contains(r.source_ip_cidr, "2001:db8::2/128")) != null, "source_ip_cidr matcher");
|
||||||
|
assert(route_rule(matchers, r => r.outbound == "source_only-out" && contains(r.source_ip_cidr, "192.168.1.77/32")) != null, "source_only route rule generated");
|
||||||
let commented_ip_rule = route_rule(matchers, r => r.outbound == "proxy-out" && contains(r.ip_cidr, "77.111.247.0/24") && contains(r.ip_cidr, "198.51.100.0/24"));
|
let commented_ip_rule = route_rule(matchers, r => r.outbound == "proxy-out" && contains(r.ip_cidr, "77.111.247.0/24") && contains(r.ip_cidr, "198.51.100.0/24"));
|
||||||
assert(commented_ip_rule != null, "comment-aware ip_cidr matcher");
|
assert(commented_ip_rule != null, "comment-aware ip_cidr matcher");
|
||||||
assert(contains(commented_ip_rule.port, 80) && contains(commented_ip_rule.port, 8080), "comment-aware port matcher");
|
assert(contains(commented_ip_rule.port, 80) && contains(commented_ip_rule.port, 8080), "comment-aware port matcher");
|
||||||
|
|||||||
+13
-3
@@ -57,9 +57,19 @@ if (res1 != "<b 0x123450>") {
|
|||||||
warn("awg_tag_chain should pad odd length hex: got " + res1 + "\n");
|
warn("awg_tag_chain should pad odd length hex: got " + res1 + "\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
let res2 = common.awg_tag_chain("1234");
|
let res3 = common.awg_tag_chain("<t><r 10><b 0x69d107975bdca8994ea71d><rc 12><rd 7>");
|
||||||
if (res2 != "<b 0x1234>") {
|
if (res3 != "<t><r 10><b 0x69d107975bdca8994ea71d><rc 12><rd 7>") {
|
||||||
warn("awg_tag_chain should format even length hex: got " + res2 + "\n");
|
warn("awg_tag_chain should preserve tag chain: got " + res3 + "\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
let res4 = common.awg_tag_chain("<t><r 10><b 0x69d107975bdca8994ea71d><rc 12><rd 7");
|
||||||
|
if (res4 != "<t><r 10><b 0x69d107975bdca8994ea71d><rc 12><rd 7>") {
|
||||||
|
warn("awg_tag_chain should heal unclosed tag: got " + res4 + "\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
let res5 = common.awg_tag_chain("729cd37af1ee1d><t><rc 4><r 24><rd 5");
|
||||||
|
if (res5 != "<b 0x729cd37af1ee1d><t><rc 4><r 24><rd 5>") {
|
||||||
|
warn("awg_tag_chain should heal stripped opening and closing tags: got " + res5 + "\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
' || fail "awg_tag_chain odd-hex padding failed"
|
' || fail "awg_tag_chain odd-hex padding failed"
|
||||||
|
|||||||
Reference in New Issue
Block a user