fix(awg): support AmneziaWG 2.0/3.0/3.1, fix WARP generator safety & update release 1.3.20

This commit is contained in:
Dushnilin
2026-09-05 12:00:14 +03:00
parent dbe6eb013c
commit a4a757223f
25 changed files with 8476 additions and 6142 deletions
+10
View File
@@ -593,6 +593,15 @@ const dictionary = {
// WARP / 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",
"Load .conf": "Загрузить .conf",
"Load .conf config": "Загрузить конфигурацию .conf",
@@ -1335,6 +1344,7 @@ const dictionary = {
"CleanBrowsing Security": "CleanBrowsing (Безопасность)",
"CleanBrowsing Family": "CleanBrowsing (Семейный)",
"Yandex Safe": "Yandex (Безопасный)",
"Hide versions": "Скрыть версии",
};
function escapePoString(str) {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+273 -99
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: TACHYON\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-09-01 21:58+0300\n"
"PO-Revision-Date: 2026-09-01 21:58+0300\n"
"POT-Creation-Date: 2026-09-05 10:59+0300\n"
"PO-Revision-Date: 2026-09-05 10:59+0300\n"
"Last-Translator: Dushnilin\n"
"Language-Team: none\n"
"Language: ru\n"
@@ -41,9 +41,15 @@ msgstr "+ Добавить стратегию"
msgid "+ Add URLTest"
msgstr "+ Добавить URLTest"
msgid "⏳ Stopping..."
msgstr ""
msgid "⚠️ Benchmark completed. No working bypass found for this target."
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."
msgstr "⚠️ Если все Bootstrap DNS завершатся с ошибкой 3 раза, запросы будут отправлены в DNS вашего провайдера в открытом виде. Используйте только в крайнем случае для предотвращения полной потери интернета."
@@ -59,8 +65,8 @@ msgstr "⚡ Быстрые (>1 МБ/с)"
msgid "⚡ QUIC / HTTP/3 (UDP 443)"
msgstr "⚡ QUIC / HTTP/3 (UDP 443)"
msgid "⚡ Quick Benchmark (Presets ~12-14)"
msgstr "⚡ Быстрый бенчмарк (Пресеты ~12-14)"
msgid "⚡ Quick Benchmark (Presets ~30+)"
msgstr ""
msgid "⚡ Strategy Fuzzer & Auto-Tuner"
msgstr "⚡ Подборщик стратегий и авто-тюнер"
@@ -92,8 +98,8 @@ msgstr "✘ Остановлено"
msgid "🌐 Custom Target URL..."
msgstr "🌐 Пользовательский URL цели..."
msgid "🎬 YouTube Suite (Web + 4K Stream)"
msgstr "🎬 YouTube Suite (Web + 4K Stream)"
msgid "🎬 YouTube Full Suite (Web + 4K Stream + CDN)"
msgstr ""
msgid "🏆 Apply Best Match"
msgstr "🏆 Применить наилучшую"
@@ -101,8 +107,11 @@ msgstr "🏆 Применить наилучшую"
msgid "🏴‍☠️ RuTracker Suite"
msgstr "🏴‍☠️ RuTracker Suite"
msgid "💬 Discord Suite (API + WSS + CDN)"
msgstr "💬 Discord Suite (API + WSS + CDN)"
msgid "🐦 X / Twitter Suite (API + Media CDN)"
msgstr ""
msgid "💬 Discord Suite (Gateway + Voice + CDN)"
msgstr ""
msgid "💾 Save Custom Patterns"
msgstr "💾 Сохранить пользовательские паттерны"
@@ -116,12 +125,15 @@ msgstr "🔄 Обновить"
msgid "🔄 Reset to Factory Defaults"
msgstr "🔄 Сбросить к заводским настройкам"
msgid "🔍 Combinatorial Deep Fuzzing (~40-80+)"
msgstr "🔍 Комбинаторный глубокий фаззинг (~40-80+)"
msgid "🔍 Combinatorial Deep Fuzzing (~150-300+)"
msgstr ""
msgid "🗑️ Clear History"
msgstr "🗑️ Очистить историю"
msgid "🤖 ChatGPT / OpenAI Suite"
msgstr ""
msgid "🧠 Synthesize with AI"
msgstr "🧠 Сгенерировать через ИИ"
@@ -134,12 +146,18 @@ msgstr "🚀 Инициализация бенчмарка в песочнице
msgid "🚀 Start Benchmark"
msgstr "🚀 Начать бенчмарк"
msgid "🛑 Benchmark stopped"
msgstr ""
msgid "🛑 Stop Benchmark"
msgstr "🛑 Остановить бенчмарк"
msgid "🛠️ My Custom Strategies Only"
msgstr "🛠️ Только мои стратегии"
msgid "🟣 Twitch Suite (Live Stream + HLS CDN)"
msgstr ""
msgid "Accept external proxy connections and route them with sing-box."
msgstr "Принимать внешние прокси-подключения и маршрутизировать их через sing-box."
@@ -398,12 +416,36 @@ msgstr "Всегда блокировать эти домены для всех
msgid "Always visible"
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!"
msgstr "Конфигурация AmneziaWG успешно загружена!"
msgid "AmneziaWG Generator"
msgstr "Генератор AmneziaWG"
msgid "AmneziaWG Version"
msgstr "Версия AmneziaWG"
msgid "Anonymized support report copied to clipboard"
msgstr "Анонимизированный отчет скопирован в буфер обмена"
@@ -425,6 +467,9 @@ msgstr "Применено"
msgid "Apply"
msgstr "Применить"
msgid "Apply Recommended DNS"
msgstr "Применить рекомендованный DNS"
msgid "Apply rules of this section only to selected protocols."
msgstr "Применять правила этой секции только к выбранным протоколам."
@@ -500,6 +545,9 @@ msgstr "Авто-генерация HWID"
msgid "Auto-Heal Network Stack"
msgstr "Автолечение сетевого стека"
msgid "Auto-Tune & Benchmark DNS"
msgstr "Подобрать и протестировать DNS"
msgid "Auto-update Hosts Lists"
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."
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"
msgstr "Автоматически проверять установленные компоненты на наличие новых версий"
@@ -563,9 +614,15 @@ msgstr "Беларусь (by)"
msgid "Benchmark & Test"
msgstr "Бенчмарк и тестирование"
msgid "Benchmark completed successfully"
msgstr "Бенчмарк успешно завершён"
msgid "Benchmark History"
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"
msgstr "Бенчмарк остановлен"
@@ -899,6 +956,9 @@ msgstr "Строка аргументов командной строки..."
msgid "Community Lists"
msgstr "Community-списки"
msgid "Component action timed out"
msgstr ""
msgid "Component update available"
msgstr "Доступно обновление компонента"
@@ -929,6 +989,9 @@ msgstr "Путь к файлу конфигурации"
msgid "Config Snapshots"
msgstr "Снапшоты конфигурации"
msgid "Configuration applied"
msgstr ""
msgid "Configuration for Tachyon service"
msgstr "Конфигурация сервиса Tachyon"
@@ -962,6 +1025,9 @@ msgstr "Консультируюсь с базой знаний DPI и ИИ..."
msgid "Content Mode"
msgstr "Режим контента"
msgid "Content Padding Addition"
msgstr ""
msgid "Cookie packet junk size (S3)"
msgstr "Размер мусора в пакете cookie (S3)"
@@ -1163,6 +1229,9 @@ msgstr "Отображаемое имя"
msgid "DNS"
msgstr "DNS"
msgid "DNS Auto-Tuner & Benchmark"
msgstr "Автоподбор и бенчмарк DNS"
msgid "DNS Check Interval"
msgstr "Интервал проверки DNS"
@@ -1187,6 +1256,9 @@ msgstr "DNS через TLS (DoT)"
msgid "DNS protocol"
msgstr "Протокол DNS"
msgid "DNS Protocol"
msgstr ""
msgid "DNS Protocol Type"
msgstr "Тип протокола DNS"
@@ -1535,6 +1607,9 @@ msgstr "Ошибка обновления списков:"
msgid "Every day"
msgstr "Каждый день"
msgid "EXCELLENT"
msgstr "ОТЛИЧНО"
msgid "Exclude by proxy parameters"
msgstr "Исключить по параметрам прокси"
@@ -1577,6 +1652,9 @@ msgstr "Истекает"
msgid "Expose this section as a local HTTP+SOCKS proxy"
msgstr "Предоставить эту секцию как локальный HTTP+SOCKS прокси"
msgid "extended"
msgstr ""
msgid "External inbound proxy servers"
msgstr "Внешние входящие прокси-серверы"
@@ -1586,6 +1664,15 @@ msgstr "Внешние файлы конфигурации nfqws обходят
msgid "External nfqws2 config files bypass Tachyon queue management and explicit validation."
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"
msgstr "Не удалось применить исправление"
@@ -1622,12 +1709,18 @@ msgstr "Не удалось определить тип DPI"
msgid "Failed to execute"
msgstr "Не удалось выполнить"
msgid "Failed to fetch releases"
msgstr ""
msgid "Failed to generate bug report"
msgstr "Не удалось создать отчёт об ошибке"
msgid "Failed to generate WARP config:"
msgstr "Не удалось сгенерировать конфигурацию WARP:"
msgid "Failed to get DNS benchmark status"
msgstr ""
msgid "Failed to get fuzzer history"
msgstr "Не удалось получить историю фаззера"
@@ -1640,12 +1733,18 @@ msgstr "Не удалось получить статус фаззера"
msgid "Failed to get fuzzer strategies"
msgstr "Не удалось получить стратегии фаззера"
msgid "Failed to install version"
msgstr ""
msgid "Failed to load history"
msgstr "Не удалось загрузить историю"
msgid "Failed to load snapshots"
msgstr "Не удалось загрузить снапшоты"
msgid "Failed to load versions"
msgstr "Не удалось загрузить версии"
msgid "Failed to parse file:"
msgstr "Ошибка разбора файла:"
@@ -1691,6 +1790,9 @@ msgstr "Не удалось запустить бенчмарк"
msgid "Failed to start bot"
msgstr "Не удалось запустить бота"
msgid "Failed to start DNS benchmark"
msgstr ""
msgid "Failed to start fuzzer"
msgstr "Не удалось запустить фаззер"
@@ -1703,6 +1805,9 @@ msgstr "Не удалось запустить watchdog"
msgid "Failed to stop bot"
msgstr "Не удалось остановить бота"
msgid "Failed to stop DNS benchmark"
msgstr ""
msgid "Failed to stop fuzzer"
msgstr "Не удалось остановить фаззер"
@@ -1724,6 +1829,9 @@ msgstr "Не удалось обновить подписки"
msgid "Failover failure threshold"
msgstr "Порог срабатывания failover"
msgid "FAIR"
msgstr "СРЕДНЕ"
msgid "FakeIP and control checks use different public IPs"
msgstr "FakeIP и контрольная проверка используют разные публичные IP"
@@ -1736,6 +1844,9 @@ msgstr "FakeIP работает; сравнение публичных IP не
msgid "FakeTLS host"
msgstr "FakeTLS host"
msgid "Fallback DNS"
msgstr ""
msgid "Fallback DNS Servers"
msgstr "Резервные DNS серверы"
@@ -1748,75 +1859,6 @@ msgstr "Резервные DNS серверы должны быть обычны
msgid "Fallback on unknown 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 (🏠)"
msgstr "Семья (🏠)"
@@ -1847,6 +1889,9 @@ msgstr "Фильтровать серверы, отображаемые на д
msgid "Filter:"
msgstr "Фильтр:"
msgid "Finished with code"
msgstr ""
msgid "Finland (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."
msgstr "Принудительно направлять DNS-запросы через DoQ с Encrypted Client Hello (ECH) для скрытия SNI."
msgid "Found"
msgstr ""
msgid "France (fr)"
msgstr "Франция (fr)"
@@ -1973,6 +2021,9 @@ msgstr "Не удалось выполнить глобальную провер
msgid "Global Default"
msgstr "Глобально по умолчанию"
msgid "GOOD"
msgstr "ХОРОШО"
msgid "Group devices into family profiles to manage content filtering, SafeSearch, and screen time limits in one place."
msgstr "Группируйте устройства в семейные профили для централизованного управления фильтрацией сайтов, безопасным поиском и лимитами экранного времени."
@@ -1982,6 +2033,9 @@ msgstr "Сервис gRPC"
msgid "Handshake timeout"
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."
msgstr "Привет! Я ИИ-ассистент Tachyon. Чем могу помочь? Задайте вопрос о блокировках, диагностике или настройках роутера."
@@ -2033,6 +2087,9 @@ msgstr "Скрыть узлы групп URLTest"
msgid "Hide values"
msgstr "Скрывать значения"
msgid "Hide versions"
msgstr "Скрыть версии"
msgid "Higher-level check interval"
msgstr "Интервал проверки высших уровней"
@@ -2534,6 +2591,9 @@ msgstr "Сохранять предыдущую рабочую версию ко
msgid "Keep URLTest before latency-sorted servers"
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."
msgstr "Сохраняет FakeIP-кэш между перезагрузками и заранее резолвит популярные заблокированные домены при старте — задержка при первом визите 0 мс."
@@ -2555,6 +2615,9 @@ msgstr "Язык ответов диагностики ИИ-доктора"
msgid "Laptop / PC (💻)"
msgstr "Ноутбук / ПК (💻)"
msgid "Latency"
msgstr ""
msgid "Latency test failed"
msgstr "Проверка задержки не удалась"
@@ -2627,6 +2690,9 @@ msgstr "Загрузка подключений"
msgid "Loading service list..."
msgstr "Получение списка сервисов..."
msgid "Loading versions..."
msgstr "Загрузка версий..."
msgid "Loading..."
msgstr "Загрузка..."
@@ -2636,6 +2702,9 @@ msgstr "Локальный адрес"
msgid "Log Level"
msgstr "Уровень логирования"
msgid "Loss"
msgstr "Потери"
msgid "LuCI Web UI"
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)"
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)."
msgstr "Макс. переподключений в час до оповещения (по умолчанию 10)."
@@ -2828,6 +2900,9 @@ msgstr "Активные устройства в локальной сети н
msgid "No active routing sections found."
msgstr "Активные секции маршрутизации не найдены."
msgid "No benchmark data yet. Click \"Start Benchmark\" to begin."
msgstr "Нет данных бенчмарка. Нажмите «Начать тест», чтобы запустить проверку."
msgid "No benchmark history yet. Run a benchmark to see results here."
msgstr "История бенчмарков пуста. Запустите бенчмарк, чтобы увидеть результаты здесь."
@@ -2900,6 +2975,12 @@ msgstr "Снапшотов пока нет"
msgid "No strategies match the active filter."
msgstr "Нет стратегий, соответствующих выбранному фильтру."
msgid "No versions found"
msgstr "Версии не найдены"
msgid "No working strategy to apply"
msgstr ""
msgid "Node list is empty"
msgstr "Список узлов пуст"
@@ -3239,6 +3320,9 @@ msgstr "Предварительно собранный индекс фрагм
msgid "Pre-download all preset lists"
msgstr "Предзагрузить все предустановленные списки"
msgid "pre-release"
msgstr "пре-релиз"
msgid "Pre-shared key"
msgstr "Предварительный общий ключ"
@@ -3266,6 +3350,9 @@ msgstr "Предварительный общий ключ"
msgid "Prevents multiple reload_firewall calls within 120 seconds to avoid connection drops."
msgstr "Предотвращает множественные вызовы reload_firewall в течение 120 секунд для избежания разрыва соединений."
msgid "Primary DNS"
msgstr ""
msgid "Priority"
msgstr "Приоритет"
@@ -3308,6 +3395,12 @@ msgstr "Защита"
msgid "Protocol"
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"
msgstr "Глобальные настройки провайдера"
@@ -3350,12 +3443,18 @@ msgstr "QUIC (HTTP/3)"
msgid "RAG Knowledge Base + Live ISP Probe Context"
msgstr "База знаний RAG + результаты живого зондирования провайдера"
msgid "Rating"
msgstr "Оценка"
msgid "RDP"
msgstr "RDP"
msgid "Read error"
msgstr "Ошибка чтения"
msgid "Ready to benchmark DNS providers"
msgstr "Готов к тестированию DNS провайдеров"
msgid "Reality fake site"
msgstr "Фейковый сайт Reality"
@@ -3386,6 +3485,12 @@ msgstr "Пересобранный релиз"
msgid "Recommended"
msgstr "Рекомендовано"
msgid "Recommended DNS Configuration"
msgstr "Рекомендованная конфигурация DNS"
msgid "Recommended DNS settings applied successfully and service restarted!"
msgstr "Рекомендованные настройки DNS успешно применены, сервис перезапущен!"
msgid "Recommended Quick Fixes:"
msgstr "Рекомендуемые исправления:"
@@ -3419,6 +3524,15 @@ msgstr "Регулярное выражение не должно содержа
msgid "Reinstall"
msgstr "Переустановить"
msgid "Reject After Time"
msgstr ""
msgid "Rekey After Time"
msgstr ""
msgid "Rekey Timeout"
msgstr ""
msgid "Reload now"
msgstr "Перезагрузить сейчас"
@@ -3938,9 +4052,6 @@ msgstr "Сервисы и доступ"
msgid "Services are online and ready! Reloading page..."
msgstr "Службы запущены и готовы к работе! Перезагрузка страницы..."
msgid "Services are online, waiting for full initialization..."
msgstr "Сервисы запущены, ожидание полной инициализации..."
msgid "Services info"
msgstr "Информация о сервисах"
@@ -4037,6 +4148,9 @@ msgstr "Пропущены комментарии/невалидные:"
msgid "Skipped loopback:"
msgstr "Пропущены loopback:"
msgid "SLOW"
msgstr "МЕДЛЕННО"
msgid "Snapshot name"
msgstr "Имя снапшота"
@@ -4136,6 +4250,9 @@ msgstr "Стандартный"
msgid "Start"
msgstr "Старт"
msgid "Start Benchmark"
msgstr "Начать тест"
msgid "Start bot"
msgstr "Запустить бота"
@@ -4151,6 +4268,9 @@ msgstr "Время начала (ЧЧ:ММ)"
msgid "Start watchdog"
msgstr "Запустить watchdog"
msgid "Starting DNS benchmark..."
msgstr "Запуск бенчмарка DNS..."
msgid "Starting…"
msgstr "Запуск…"
@@ -4235,6 +4355,9 @@ msgstr "Успех"
msgid "Successfully imported %d DNS record(s)"
msgstr "Успешно импортировано %d DNS-записей"
msgid "Successfully updated %d hosts entries"
msgstr ""
msgid "Sun"
msgstr "Вс"
@@ -4268,9 +4391,15 @@ msgstr "Порядок и видимость вкладок"
msgid "Table exist"
msgstr "Таблица существует"
msgid "Tachyon"
msgstr ""
msgid "Tachyon Core"
msgstr "Ядро Tachyon"
msgid "Tachyon DNS Benchmark & Auto-Tuning"
msgstr "Tachyon: Бенчмарк и автоподбор DNS"
msgid "Tachyon Error"
msgstr "Ошибка Tachyon"
@@ -4409,6 +4538,9 @@ msgstr "Тестировать серверы, чьи имена соответ
msgid "Test Telegram Connection"
msgstr "Проверить подключение к Telegram"
msgid "Testing"
msgstr ""
msgid "Testing bypass strategies in isolated sandbox..."
msgstr "Тестирование стратегий обхода в изолированной песочнице..."
@@ -4502,6 +4634,9 @@ msgstr "Время суток для запуска планового обно
msgid "Time skew tolerance"
msgstr "Допуск отклонения времени"
msgid "Timeout"
msgstr ""
msgid "tiny"
msgstr "tiny"
@@ -4727,6 +4862,9 @@ msgstr "Хранится до 10 снапшотов; самые старые у
msgid "Update"
msgstr "Обновить"
msgid "Update failed:"
msgstr ""
msgid "Update is available"
msgstr "Доступно обновление"
@@ -4739,6 +4877,9 @@ msgstr "Доступна новая версия:"
msgid "Update lists now"
msgstr "Обновить списки сейчас"
msgid "Update Lists Now"
msgstr ""
msgid "Update subscriptions"
msgstr "Обновить подписки"
@@ -4760,6 +4901,9 @@ msgstr "Обновление режима маршрутизации устро
msgid "Updating lists..."
msgstr "Обновление списков..."
msgid "Updating…"
msgstr ""
msgid "Uplink"
msgstr "Исходящий"
@@ -4889,6 +5033,9 @@ msgstr "Значение не должно содержать символы у
msgid "Verifying router and service readiness..."
msgstr "Проверка готовности роутера и служб..."
msgid "Versions"
msgstr "Версии"
msgid "Via country.is"
msgstr "Через country.is"
@@ -4925,9 +5072,6 @@ msgstr "Токен доступа WARP"
msgid "WARP Account ID"
msgstr "ID аккаунта WARP"
msgid "WARP Configuration generated and loaded successfully!"
msgstr "Конфигурация WARP успешно сгенерирована и загружена!"
msgid "WARP Generator Proxy Section"
msgstr "Секция прокси для генератора WARP"
@@ -4973,6 +5117,9 @@ msgstr "Приватный ключ WireGuard из вашего аккаунта
msgid "Working"
msgstr "Рабочих"
msgid "working strategies"
msgstr ""
msgid "XHTTP mode"
msgstr "Режим XHTTP"
@@ -5039,6 +5186,24 @@ msgstr "sing-box outbound для Zapret2 настроен"
msgid "Zapret2 sing-box outbound is not configured"
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"
msgstr "⏹ Стоп"
@@ -5726,18 +5891,6 @@ msgstr "CleanBrowsing (Семейный)"
msgid "Yandex Safe"
msgstr "Yandex (Безопасный)"
msgid "Versions"
msgstr "Версии"
msgid "Loading versions..."
msgstr "Загрузка версий..."
msgid "No versions found"
msgstr "Версии не найдены"
msgid "Failed to load versions"
msgstr "Не удалось загрузить версии"
msgid "Installing "
msgstr "Установка "
@@ -5750,5 +5903,26 @@ msgstr "Ошибка установки: "
msgid "Installed "
msgstr "Установлено "
msgid "pre-release"
msgstr "пре-релиз"
msgid "AmneziaWG 2.0"
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',
{
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'),
);
@@ -1463,19 +1463,6 @@ function renderVersionPickerDropdown(
container.appendChild(
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;
}
@@ -1512,20 +1499,6 @@ function renderVersionPickerDropdown(
}
container.appendChild(list);
container.appendChild(
E(
'button',
{
class: 'cbi-button tachyon-version-picker__close',
click: () => {
activeVersionPickerComponent = null;
renderUpdatesComponents();
},
},
_('Close'),
),
);
return container;
}
@@ -210,7 +210,7 @@ export const styles = `
justify-content: space-between;
align-items: center;
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;
}
@@ -223,7 +223,8 @@ export const styles = `
.tachyon-update-modal__component-name {
font-size: 16px;
color: var(--text-color-high, #fff);
font-weight: bold;
color: var(--text-color-high, inherit);
}
.tachyon-update-modal__version-badge {
@@ -231,22 +232,22 @@ export const styles = `
font-family: monospace;
padding: 2px 6px;
border-radius: 4px;
background: var(--background-color-low, rgba(0,0,0,0.1));
color: var(--text-color-medium, #aaa);
border: 1px solid var(--border-color, rgba(255,255,255,0.1));
background: var(--background-color-low, rgba(0, 0, 0, 0.05));
color: var(--text-color-high, inherit);
border: 1px solid var(--border-color-low, #dee2e6);
}
.tachyon-update-modal__timer-badge {
font-size: 13px;
font-family: monospace;
color: var(--text-color-medium, #888);
color: var(--text-color-medium, #6c757d);
}
.tachyon-update-modal__success-banner {
display: flex;
align-items: center;
gap: 8px;
color: #2ecc71;
color: var(--color-green-base, #2ecc71);
font-weight: bold;
}
@@ -254,7 +255,7 @@ export const styles = `
display: flex;
align-items: center;
gap: 8px;
color: #e74c3c;
color: var(--color-red-base, #e74c3c);
font-weight: bold;
}
@@ -264,7 +265,7 @@ export const styles = `
align-items: center;
gap: 8px;
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;
flex-wrap: wrap;
}
@@ -289,6 +290,7 @@ export const styles = `
justify-content: space-between;
align-items: center;
gap: 8px;
color: var(--text-color-high, inherit);
}
.tachyon-update-modal__log-copy {
@@ -306,9 +308,9 @@ export const styles = `
font-family: monospace;
font-size: 11px;
line-height: 1.5;
color: var(--text-color, #ddd);
background: rgba(0, 0, 0, 0.35);
border: 1px solid var(--border-color, rgba(255,255,255,0.12));
color: var(--text-color-high, #212529);
background: var(--background-color-low, #f8f9fa);
border: 1px solid var(--border-color-low, #dee2e6);
border-radius: 4px;
padding: 8px;
flex: 1 1 auto;
@@ -318,20 +320,20 @@ export const styles = `
.tachyon-version-picker {
margin-top: 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;
background: rgba(0, 0, 0, 0.2);
background: var(--background-color-low, #f8f9fa);
}
.tachyon-version-picker__loading,
.tachyon-version-picker__error {
padding: 6px 0;
font-size: 12px;
color: var(--text-color, #aaa);
color: var(--text-color-medium, #6c757d);
}
.tachyon-version-picker__error {
color: var(--error-color, #e74c3c);
color: var(--color-red-base, #e74c3c);
}
.tachyon-version-picker__list {
@@ -345,7 +347,7 @@ export const styles = `
align-items: center;
gap: 8px;
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 {
@@ -355,24 +357,19 @@ export const styles = `
.tachyon-version-picker__tag {
font-weight: bold;
font-size: 13px;
color: var(--text-color, #ddd);
color: var(--text-color-high, inherit);
}
.tachyon-version-picker__date {
font-size: 11px;
color: var(--text-color, #aaa);
color: var(--text-color-medium, #6c757d);
}
.tachyon-version-picker__prerelease {
font-size: 10px;
color: var(--warn-color, #f39c12);
border: 1px solid var(--warn-color, #f39c12);
color: var(--color-yellow-base, #f39c12);
border: 1px solid var(--color-yellow-base, #f39c12);
border-radius: 3px;
padding: 1px 4px;
}
.tachyon-version-picker__close {
margin-top: 8px;
width: 100%;
}
`;
+17
View File
@@ -343,6 +343,7 @@ ASSUME_YES=0
DRY_RUN=0
VERBOSE=0
QUIET=0
SKIP_SING_BOX=0
TACHYON_RELEASE_JSON=""
TACHYON_RELEASE_TAG=""
@@ -508,6 +509,7 @@ Options:
download, install, remove, or modify anything on disk
-v, --verbose Print extra diagnostic detail while installing
-q, --quiet Suppress informational output (errors/warnings still show)
--skip-sing-box Skip sing-box installation
--version Print the installer version and exit
-h, --help Show this help text and exit
@@ -538,6 +540,9 @@ parse_args() {
-q|--quiet)
QUIET=1
;;
--skip-sing-box|--no-sing-box)
SKIP_SING_BOX=1
;;
*)
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_tiny) printf '%s\n' "singbox tiny (минимум функций)" ;;
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." ;;
installing_singbox_backend) printf '%s\n' "Установка выбранного варианта sing-box..." ;;
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_tiny) printf '%s\n' "singbox tiny (minimal features)" ;;
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." ;;
installing_singbox_backend) printf '%s\n' "Installing selected sing-box variant..." ;;
install_start) printf '%s\n' "=== Starting Tachyon Installation ===" ;;
@@ -2324,6 +2331,11 @@ select_sing_box_installation() {
return 0
fi
if [ "$SKIP_SING_BOX" -eq 1 ]; then
SING_BOX_INSTALL_VARIANT=""
return 0
fi
if [ "$ASSUME_YES" -eq 1 ] || [ ! -t 0 ]; then
SING_BOX_INSTALL_VARIANT="stable"
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 ' 4) %s\n' "$(installer_text sing_box_lx)"
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"
read -r answer || return 1
[ -n "$answer" ] || answer="$default_choice"
@@ -2361,6 +2374,10 @@ select_sing_box_installation() {
SING_BOX_INSTALL_VARIANT="tiny"
return 0
fi
if [ "$answer" = "6" ]; then
SING_BOX_INSTALL_VARIANT=""
return 0
fi
warn "$(installer_text invalid_choice)"
done
@@ -13931,7 +13931,7 @@ function renderDnsBenchmarkModal() {
const statusLabel = E(
"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")
);
@@ -20457,19 +20457,6 @@ function renderVersionPickerDropdown(component) {
container.appendChild(
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;
}
const list = E("div", { class: "tachyon-version-picker__list" });
@@ -20504,19 +20491,6 @@ function renderVersionPickerDropdown(component) {
);
}
container.appendChild(list);
container.appendChild(
E(
"button",
{
class: "cbi-button tachyon-version-picker__close",
click: () => {
activeVersionPickerComponent = null;
renderUpdatesComponents();
}
},
_("Close")
)
);
return container;
}
function renderComponentCard(card) {
@@ -21084,7 +21058,7 @@ var styles6 = `
justify-content: space-between;
align-items: center;
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;
}
@@ -21097,7 +21071,8 @@ var styles6 = `
.tachyon-update-modal__component-name {
font-size: 16px;
color: var(--text-color-high, #fff);
font-weight: bold;
color: var(--text-color-high, inherit);
}
.tachyon-update-modal__version-badge {
@@ -21105,22 +21080,22 @@ var styles6 = `
font-family: monospace;
padding: 2px 6px;
border-radius: 4px;
background: var(--background-color-low, rgba(0,0,0,0.1));
color: var(--text-color-medium, #aaa);
border: 1px solid var(--border-color, rgba(255,255,255,0.1));
background: var(--background-color-low, rgba(0, 0, 0, 0.05));
color: var(--text-color-high, inherit);
border: 1px solid var(--border-color-low, #dee2e6);
}
.tachyon-update-modal__timer-badge {
font-size: 13px;
font-family: monospace;
color: var(--text-color-medium, #888);
color: var(--text-color-medium, #6c757d);
}
.tachyon-update-modal__success-banner {
display: flex;
align-items: center;
gap: 8px;
color: #2ecc71;
color: var(--color-green-base, #2ecc71);
font-weight: bold;
}
@@ -21128,7 +21103,7 @@ var styles6 = `
display: flex;
align-items: center;
gap: 8px;
color: #e74c3c;
color: var(--color-red-base, #e74c3c);
font-weight: bold;
}
@@ -21138,7 +21113,7 @@ var styles6 = `
align-items: center;
gap: 8px;
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;
flex-wrap: wrap;
}
@@ -21163,6 +21138,7 @@ var styles6 = `
justify-content: space-between;
align-items: center;
gap: 8px;
color: var(--text-color-high, inherit);
}
.tachyon-update-modal__log-copy {
@@ -21180,9 +21156,9 @@ var styles6 = `
font-family: monospace;
font-size: 11px;
line-height: 1.5;
color: var(--text-color, #ddd);
background: rgba(0, 0, 0, 0.35);
border: 1px solid var(--border-color, rgba(255,255,255,0.12));
color: var(--text-color-high, #212529);
background: var(--background-color-low, #f8f9fa);
border: 1px solid var(--border-color-low, #dee2e6);
border-radius: 4px;
padding: 8px;
flex: 1 1 auto;
@@ -21192,20 +21168,20 @@ var styles6 = `
.tachyon-version-picker {
margin-top: 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;
background: rgba(0, 0, 0, 0.2);
background: var(--background-color-low, #f8f9fa);
}
.tachyon-version-picker__loading,
.tachyon-version-picker__error {
padding: 6px 0;
font-size: 12px;
color: var(--text-color, #aaa);
color: var(--text-color-medium, #6c757d);
}
.tachyon-version-picker__error {
color: var(--error-color, #e74c3c);
color: var(--color-red-base, #e74c3c);
}
.tachyon-version-picker__list {
@@ -21219,7 +21195,7 @@ var styles6 = `
align-items: center;
gap: 8px;
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 {
@@ -21229,26 +21205,21 @@ var styles6 = `
.tachyon-version-picker__tag {
font-weight: bold;
font-size: 13px;
color: var(--text-color, #ddd);
color: var(--text-color-high, inherit);
}
.tachyon-version-picker__date {
font-size: 11px;
color: var(--text-color, #aaa);
color: var(--text-color-medium, #6c757d);
}
.tachyon-version-picker__prerelease {
font-size: 10px;
color: var(--warn-color, #f39c12);
border: 1px solid var(--warn-color, #f39c12);
color: var(--color-yellow-base, #f39c12);
border: 1px solid var(--color-yellow-base, #f39c12);
border-radius: 3px;
padding: 1px 4px;
}
.tachyon-version-picker__close {
margin-top: 8px;
width: 100%;
}
`;
// src/tachyon/tabs/updates/index.ts
@@ -8412,6 +8412,25 @@ function createSectionContent(section) {
: _("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(
"settings",
form.Button,
@@ -8503,9 +8522,26 @@ function createSectionContent(section) {
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…"));
fs.exec("/usr/bin/tachyon", ["generate_warp"])
fs.exec("/usr/bin/tachyon", ["generate_warp", "", "2.0"])
.then(function (response) {
if (!response || (response.code ?? 0) !== 0 || !response.stdout) {
setState("error", _("Error"));
@@ -8533,25 +8569,6 @@ function createSectionContent(section) {
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 widget = getControlWidget(opt);
if (widget) {
@@ -8562,6 +8579,8 @@ function createSectionContent(section) {
uci.set(UCI_PACKAGE, section_id, opt, val);
};
const genVer = data.awg_version || "2.0";
setWidgetValue("awg_local_address", data.local_address);
setWidgetValue("awg_private_key", data.private_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_s3", `${data.awg_s3}`);
setWidgetValue("awg_s4", `${data.awg_s4}`);
setWidgetValue("awg_i1", stripUciBinary(data.awg_i1));
setWidgetValue("awg_i2", stripUciBinary(data.awg_i2));
setWidgetValue("awg_i3", stripUciBinary(data.awg_i3));
setWidgetValue("awg_i4", stripUciBinary(data.awg_i4));
setWidgetValue("awg_i5", stripUciBinary(data.awg_i5));
setWidgetValue("awg_i1", cleanAwgPayload(data.awg_i1));
setWidgetValue("awg_i2", cleanAwgPayload(data.awg_i2));
setWidgetValue("awg_i3", cleanAwgPayload(data.awg_i3));
setWidgetValue("awg_i4", cleanAwgPayload(data.awg_i4));
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!"));
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(
_("Success"),
_("WARP Configuration generated and loaded successfully!"),
successMsg,
false,
);
} catch (err) {
@@ -8630,15 +8671,24 @@ function createSectionContent(section) {
let cur = null;
for (const raw of text.split(/\r?\n/)) {
const line = raw.trim();
if (!line || line.startsWith("#")) continue;
const sm = line.match(/^\[(\w+)\]$/);
if (!line || line.startsWith("#") || line.startsWith(";")) continue;
const sm = line.match(/^\[([^\]]+)\]$/);
if (sm) {
cur = sm[1].toLowerCase();
cur = sm[1].trim().toLowerCase();
out[cur] = out[cur] || {};
continue;
}
const kv = line.match(/^(\w+)\s*=\s*(.+)$/);
if (kv && cur) out[cur][kv[1]] = kv[2].trim();
const kv = line.match(/^([^=]+)\s*=\s*(.+)$/);
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;
};
@@ -8654,22 +8704,16 @@ function createSectionContent(section) {
)
.join(" ");
// Strip UCI binary literal format: <b 0xHEX> → HEX
const stripBin = (v) =>
typeof v === "string"
? v
.replace(/^<b\s+0x/, "")
.replace(/>$/, "")
.trim()
: "";
// Use shared payload cleaner for tag chains and hex normalization
const cleanPayload = cleanAwgPayload;
// Write value into a form widget and the UCI cache
const setVal = (opt, val) => {
if (val === undefined || val === null) return;
const str = String(val);
const el = document.getElementById(
`widget.cbid.${UCI_PACKAGE}.${section_id}.${opt}`,
);
const el =
document.getElementById(`widget.cbid.${UCI_PACKAGE}.${section_id}.${opt}`) ||
document.getElementById(`cbid.${UCI_PACKAGE}.${section_id}.${opt}`);
const w =
el &&
(/^(INPUT|SELECT|TEXTAREA)$/.test(el.tagName)
@@ -8743,42 +8787,148 @@ function createSectionContent(section) {
const iface = cfg.interface || {};
const peer = cfg.peer || {};
// --- [Interface] ---
if (iface.Address)
setVal("awg_local_address", normalizeAddr(iface.Address));
if (iface.PrivateKey) setVal("awg_private_key", iface.PrivateKey);
if (iface.MTU !== undefined) setVal("awg_mtu", iface.MTU);
if (peer.PersistentKeepalive)
setVal("awg_keepalive", peer.PersistentKeepalive);
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);
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);
if (iface.S4 !== undefined) setVal("awg_s4", iface.S4);
if (iface.H1 !== undefined) setVal("awg_h1", iface.H1);
if (iface.H2 !== undefined) setVal("awg_h2", iface.H2);
if (iface.H3 !== undefined) setVal("awg_h3", iface.H3);
if (iface.H4 !== undefined) setVal("awg_h4", iface.H4);
if (iface.I1) setVal("awg_i1", stripBin(iface.I1));
if (iface.I2) setVal("awg_i2", stripBin(iface.I2));
if (iface.I3) setVal("awg_i3", stripBin(iface.I3));
if (iface.I4) setVal("awg_i4", stripBin(iface.I4));
if (iface.I5) setVal("awg_i5", stripBin(iface.I5));
if (iface.J1) setVal("awg_j1", stripBin(iface.J1));
if (iface.J2) setVal("awg_j2", stripBin(iface.J2));
if (iface.J3) setVal("awg_j3", stripBin(iface.J3));
if (iface.Itime !== undefined) setVal("awg_itime", iface.Itime);
// Case-insensitive lookup across [Interface] and [Peer]
const getConfVal = (k) => {
const lk = k.toLowerCase();
for (const s of [iface, peer]) {
if (!s) continue;
for (const key in s) {
if (key.toLowerCase() === lk) return s[key];
}
}
return undefined;
};
// --- [Interface] / [Peer] ---
const addr = getConfVal("Address") || getConfVal("awg_local_address");
if (addr) setVal("awg_local_address", normalizeAddr(addr));
const priv = getConfVal("PrivateKey") || getConfVal("awg_private_key");
if (priv) setVal("awg_private_key", priv);
const mtu = getConfVal("MTU");
if (mtu !== undefined) setVal("awg_mtu", mtu);
const keepalive = getConfVal("PersistentKeepalive") || getConfVal("Keepalive");
if (keepalive !== undefined) setVal("awg_keepalive", keepalive);
const jc = getConfVal("Jc");
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] ---
if (peer.PublicKey) setVal("awg_peer_public_key", peer.PublicKey);
if (peer.PresharedKey) setVal("awg_preshared_key", peer.PresharedKey);
if (peer.Endpoint) {
const i = peer.Endpoint.lastIndexOf(":");
const pub = getConfVal("PublicKey") || getConfVal("awg_peer_public_key");
if (pub) setVal("awg_peer_public_key", pub);
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) {
setVal("awg_server_address", peer.Endpoint.slice(0, i));
setVal("awg_server_port", peer.Endpoint.slice(i + 1));
setVal("awg_server_address", ep.slice(0, i));
setVal("awg_server_port", ep.slice(i + 1));
}
}
@@ -8889,6 +9039,40 @@ function createSectionContent(section) {
o.modalonly = true;
o.rmempty = true;
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) ──────────────
const addAwgParam = (name, title, desc, def) => {
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_h3", _("Underload Packet Magic Header (H3)"), "", "3");
addAwgParam("awg_h4", _("Underload Packet Magic Header (H4)"), "", "4");
addAwgParam("awg_i1", _("Init Packet Payload (I1)"), "", "0");
addAwgParam("awg_i2", _("Init Packet Payload (I2)"), "", "0");
addAwgParam("awg_i3", _("Init Packet Payload (I3)"), "", "0");
addAwgParam("awg_i4", _("Init Packet Payload (I4)"), "", "0");
addAwgParam("awg_i5", _("Init Packet Payload (I5)"), "", "0");
const addAwgPayloadParam = (name, title, desc, def) => {
let opt = section.taboption("settings", form.Value, name, title, desc);
opt.modalonly = true;
opt.rmempty = false;
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) ──────────────────────────
@@ -1466,6 +1466,26 @@ function buildAwgClientConfig(sectionId) {
if (j3) conf += `J3 = ${j3}\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`;
if (presharedKey) conf += `PresharedKey = ${presharedKey}\n`;
@@ -3446,6 +3466,51 @@ function createServerContent(section, options = {}) {
o.rmempty = true;
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 = [
{
name: "awg_jc",
@@ -3567,6 +3632,48 @@ function createServerContent(section, options = {}) {
desc: _("Init handshake timeout"),
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) => {
@@ -3574,7 +3681,14 @@ function createServerContent(section, options = {}) {
opt.modalonly = true;
opt.rmempty = true;
if (param.default !== "") opt.default = param.default;
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");
}
});
}
+273 -99
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: TACHYON\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-09-01 21:58+0300\n"
"PO-Revision-Date: 2026-09-01 21:58+0300\n"
"POT-Creation-Date: 2026-09-05 10:59+0300\n"
"PO-Revision-Date: 2026-09-05 10:59+0300\n"
"Last-Translator: Dushnilin\n"
"Language-Team: none\n"
"Language: ru\n"
@@ -41,9 +41,15 @@ msgstr "+ Добавить стратегию"
msgid "+ Add URLTest"
msgstr "+ Добавить URLTest"
msgid "⏳ Stopping..."
msgstr ""
msgid "⚠️ Benchmark completed. No working bypass found for this target."
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."
msgstr "⚠️ Если все Bootstrap DNS завершатся с ошибкой 3 раза, запросы будут отправлены в DNS вашего провайдера в открытом виде. Используйте только в крайнем случае для предотвращения полной потери интернета."
@@ -59,8 +65,8 @@ msgstr "⚡ Быстрые (>1 МБ/с)"
msgid "⚡ QUIC / HTTP/3 (UDP 443)"
msgstr "⚡ QUIC / HTTP/3 (UDP 443)"
msgid "⚡ Quick Benchmark (Presets ~12-14)"
msgstr "⚡ Быстрый бенчмарк (Пресеты ~12-14)"
msgid "⚡ Quick Benchmark (Presets ~30+)"
msgstr ""
msgid "⚡ Strategy Fuzzer & Auto-Tuner"
msgstr "⚡ Подборщик стратегий и авто-тюнер"
@@ -92,8 +98,8 @@ msgstr "✘ Остановлено"
msgid "🌐 Custom Target URL..."
msgstr "🌐 Пользовательский URL цели..."
msgid "🎬 YouTube Suite (Web + 4K Stream)"
msgstr "🎬 YouTube Suite (Web + 4K Stream)"
msgid "🎬 YouTube Full Suite (Web + 4K Stream + CDN)"
msgstr ""
msgid "🏆 Apply Best Match"
msgstr "🏆 Применить наилучшую"
@@ -101,8 +107,11 @@ msgstr "🏆 Применить наилучшую"
msgid "🏴‍☠️ RuTracker Suite"
msgstr "🏴‍☠️ RuTracker Suite"
msgid "💬 Discord Suite (API + WSS + CDN)"
msgstr "💬 Discord Suite (API + WSS + CDN)"
msgid "🐦 X / Twitter Suite (API + Media CDN)"
msgstr ""
msgid "💬 Discord Suite (Gateway + Voice + CDN)"
msgstr ""
msgid "💾 Save Custom Patterns"
msgstr "💾 Сохранить пользовательские паттерны"
@@ -116,12 +125,15 @@ msgstr "🔄 Обновить"
msgid "🔄 Reset to Factory Defaults"
msgstr "🔄 Сбросить к заводским настройкам"
msgid "🔍 Combinatorial Deep Fuzzing (~40-80+)"
msgstr "🔍 Комбинаторный глубокий фаззинг (~40-80+)"
msgid "🔍 Combinatorial Deep Fuzzing (~150-300+)"
msgstr ""
msgid "🗑️ Clear History"
msgstr "🗑️ Очистить историю"
msgid "🤖 ChatGPT / OpenAI Suite"
msgstr ""
msgid "🧠 Synthesize with AI"
msgstr "🧠 Сгенерировать через ИИ"
@@ -134,12 +146,18 @@ msgstr "🚀 Инициализация бенчмарка в песочнице
msgid "🚀 Start Benchmark"
msgstr "🚀 Начать бенчмарк"
msgid "🛑 Benchmark stopped"
msgstr ""
msgid "🛑 Stop Benchmark"
msgstr "🛑 Остановить бенчмарк"
msgid "🛠️ My Custom Strategies Only"
msgstr "🛠️ Только мои стратегии"
msgid "🟣 Twitch Suite (Live Stream + HLS CDN)"
msgstr ""
msgid "Accept external proxy connections and route them with sing-box."
msgstr "Принимать внешние прокси-подключения и маршрутизировать их через sing-box."
@@ -398,12 +416,36 @@ msgstr "Всегда блокировать эти домены для всех
msgid "Always visible"
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!"
msgstr "Конфигурация AmneziaWG успешно загружена!"
msgid "AmneziaWG Generator"
msgstr "Генератор AmneziaWG"
msgid "AmneziaWG Version"
msgstr "Версия AmneziaWG"
msgid "Anonymized support report copied to clipboard"
msgstr "Анонимизированный отчет скопирован в буфер обмена"
@@ -425,6 +467,9 @@ msgstr "Применено"
msgid "Apply"
msgstr "Применить"
msgid "Apply Recommended DNS"
msgstr "Применить рекомендованный DNS"
msgid "Apply rules of this section only to selected protocols."
msgstr "Применять правила этой секции только к выбранным протоколам."
@@ -500,6 +545,9 @@ msgstr "Авто-генерация HWID"
msgid "Auto-Heal Network Stack"
msgstr "Автолечение сетевого стека"
msgid "Auto-Tune & Benchmark DNS"
msgstr "Подобрать и протестировать DNS"
msgid "Auto-update Hosts Lists"
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."
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"
msgstr "Автоматически проверять установленные компоненты на наличие новых версий"
@@ -563,9 +614,15 @@ msgstr "Беларусь (by)"
msgid "Benchmark & Test"
msgstr "Бенчмарк и тестирование"
msgid "Benchmark completed successfully"
msgstr "Бенчмарк успешно завершён"
msgid "Benchmark History"
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"
msgstr "Бенчмарк остановлен"
@@ -899,6 +956,9 @@ msgstr "Строка аргументов командной строки..."
msgid "Community Lists"
msgstr "Community-списки"
msgid "Component action timed out"
msgstr ""
msgid "Component update available"
msgstr "Доступно обновление компонента"
@@ -929,6 +989,9 @@ msgstr "Путь к файлу конфигурации"
msgid "Config Snapshots"
msgstr "Снапшоты конфигурации"
msgid "Configuration applied"
msgstr ""
msgid "Configuration for Tachyon service"
msgstr "Конфигурация сервиса Tachyon"
@@ -962,6 +1025,9 @@ msgstr "Консультируюсь с базой знаний DPI и ИИ..."
msgid "Content Mode"
msgstr "Режим контента"
msgid "Content Padding Addition"
msgstr ""
msgid "Cookie packet junk size (S3)"
msgstr "Размер мусора в пакете cookie (S3)"
@@ -1163,6 +1229,9 @@ msgstr "Отображаемое имя"
msgid "DNS"
msgstr "DNS"
msgid "DNS Auto-Tuner & Benchmark"
msgstr "Автоподбор и бенчмарк DNS"
msgid "DNS Check Interval"
msgstr "Интервал проверки DNS"
@@ -1187,6 +1256,9 @@ msgstr "DNS через TLS (DoT)"
msgid "DNS protocol"
msgstr "Протокол DNS"
msgid "DNS Protocol"
msgstr ""
msgid "DNS Protocol Type"
msgstr "Тип протокола DNS"
@@ -1535,6 +1607,9 @@ msgstr "Ошибка обновления списков:"
msgid "Every day"
msgstr "Каждый день"
msgid "EXCELLENT"
msgstr "ОТЛИЧНО"
msgid "Exclude by proxy parameters"
msgstr "Исключить по параметрам прокси"
@@ -1577,6 +1652,9 @@ msgstr "Истекает"
msgid "Expose this section as a local HTTP+SOCKS proxy"
msgstr "Предоставить эту секцию как локальный HTTP+SOCKS прокси"
msgid "extended"
msgstr ""
msgid "External inbound proxy servers"
msgstr "Внешние входящие прокси-серверы"
@@ -1586,6 +1664,15 @@ msgstr "Внешние файлы конфигурации nfqws обходят
msgid "External nfqws2 config files bypass Tachyon queue management and explicit validation."
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"
msgstr "Не удалось применить исправление"
@@ -1622,12 +1709,18 @@ msgstr "Не удалось определить тип DPI"
msgid "Failed to execute"
msgstr "Не удалось выполнить"
msgid "Failed to fetch releases"
msgstr ""
msgid "Failed to generate bug report"
msgstr "Не удалось создать отчёт об ошибке"
msgid "Failed to generate WARP config:"
msgstr "Не удалось сгенерировать конфигурацию WARP:"
msgid "Failed to get DNS benchmark status"
msgstr ""
msgid "Failed to get fuzzer history"
msgstr "Не удалось получить историю фаззера"
@@ -1640,12 +1733,18 @@ msgstr "Не удалось получить статус фаззера"
msgid "Failed to get fuzzer strategies"
msgstr "Не удалось получить стратегии фаззера"
msgid "Failed to install version"
msgstr ""
msgid "Failed to load history"
msgstr "Не удалось загрузить историю"
msgid "Failed to load snapshots"
msgstr "Не удалось загрузить снапшоты"
msgid "Failed to load versions"
msgstr "Не удалось загрузить версии"
msgid "Failed to parse file:"
msgstr "Ошибка разбора файла:"
@@ -1691,6 +1790,9 @@ msgstr "Не удалось запустить бенчмарк"
msgid "Failed to start bot"
msgstr "Не удалось запустить бота"
msgid "Failed to start DNS benchmark"
msgstr ""
msgid "Failed to start fuzzer"
msgstr "Не удалось запустить фаззер"
@@ -1703,6 +1805,9 @@ msgstr "Не удалось запустить watchdog"
msgid "Failed to stop bot"
msgstr "Не удалось остановить бота"
msgid "Failed to stop DNS benchmark"
msgstr ""
msgid "Failed to stop fuzzer"
msgstr "Не удалось остановить фаззер"
@@ -1724,6 +1829,9 @@ msgstr "Не удалось обновить подписки"
msgid "Failover failure threshold"
msgstr "Порог срабатывания failover"
msgid "FAIR"
msgstr "СРЕДНЕ"
msgid "FakeIP and control checks use different public IPs"
msgstr "FakeIP и контрольная проверка используют разные публичные IP"
@@ -1736,6 +1844,9 @@ msgstr "FakeIP работает; сравнение публичных IP не
msgid "FakeTLS host"
msgstr "FakeTLS host"
msgid "Fallback DNS"
msgstr ""
msgid "Fallback DNS Servers"
msgstr "Резервные DNS серверы"
@@ -1748,75 +1859,6 @@ msgstr "Резервные DNS серверы должны быть обычны
msgid "Fallback on unknown 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 (🏠)"
msgstr "Семья (🏠)"
@@ -1847,6 +1889,9 @@ msgstr "Фильтровать серверы, отображаемые на д
msgid "Filter:"
msgstr "Фильтр:"
msgid "Finished with code"
msgstr ""
msgid "Finland (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."
msgstr "Принудительно направлять DNS-запросы через DoQ с Encrypted Client Hello (ECH) для скрытия SNI."
msgid "Found"
msgstr ""
msgid "France (fr)"
msgstr "Франция (fr)"
@@ -1973,6 +2021,9 @@ msgstr "Не удалось выполнить глобальную провер
msgid "Global Default"
msgstr "Глобально по умолчанию"
msgid "GOOD"
msgstr "ХОРОШО"
msgid "Group devices into family profiles to manage content filtering, SafeSearch, and screen time limits in one place."
msgstr "Группируйте устройства в семейные профили для централизованного управления фильтрацией сайтов, безопасным поиском и лимитами экранного времени."
@@ -1982,6 +2033,9 @@ msgstr "Сервис gRPC"
msgid "Handshake timeout"
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."
msgstr "Привет! Я ИИ-ассистент Tachyon. Чем могу помочь? Задайте вопрос о блокировках, диагностике или настройках роутера."
@@ -2033,6 +2087,9 @@ msgstr "Скрыть узлы групп URLTest"
msgid "Hide values"
msgstr "Скрывать значения"
msgid "Hide versions"
msgstr "Скрыть версии"
msgid "Higher-level check interval"
msgstr "Интервал проверки высших уровней"
@@ -2534,6 +2591,9 @@ msgstr "Сохранять предыдущую рабочую версию ко
msgid "Keep URLTest before latency-sorted servers"
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."
msgstr "Сохраняет FakeIP-кэш между перезагрузками и заранее резолвит популярные заблокированные домены при старте — задержка при первом визите 0 мс."
@@ -2555,6 +2615,9 @@ msgstr "Язык ответов диагностики ИИ-доктора"
msgid "Laptop / PC (💻)"
msgstr "Ноутбук / ПК (💻)"
msgid "Latency"
msgstr ""
msgid "Latency test failed"
msgstr "Проверка задержки не удалась"
@@ -2627,6 +2690,9 @@ msgstr "Загрузка подключений"
msgid "Loading service list..."
msgstr "Получение списка сервисов..."
msgid "Loading versions..."
msgstr "Загрузка версий..."
msgid "Loading..."
msgstr "Загрузка..."
@@ -2636,6 +2702,9 @@ msgstr "Локальный адрес"
msgid "Log Level"
msgstr "Уровень логирования"
msgid "Loss"
msgstr "Потери"
msgid "LuCI Web UI"
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)"
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)."
msgstr "Макс. переподключений в час до оповещения (по умолчанию 10)."
@@ -2828,6 +2900,9 @@ msgstr "Активные устройства в локальной сети н
msgid "No active routing sections found."
msgstr "Активные секции маршрутизации не найдены."
msgid "No benchmark data yet. Click \"Start Benchmark\" to begin."
msgstr "Нет данных бенчмарка. Нажмите «Начать тест», чтобы запустить проверку."
msgid "No benchmark history yet. Run a benchmark to see results here."
msgstr "История бенчмарков пуста. Запустите бенчмарк, чтобы увидеть результаты здесь."
@@ -2900,6 +2975,12 @@ msgstr "Снапшотов пока нет"
msgid "No strategies match the active filter."
msgstr "Нет стратегий, соответствующих выбранному фильтру."
msgid "No versions found"
msgstr "Версии не найдены"
msgid "No working strategy to apply"
msgstr ""
msgid "Node list is empty"
msgstr "Список узлов пуст"
@@ -3239,6 +3320,9 @@ msgstr "Предварительно собранный индекс фрагм
msgid "Pre-download all preset lists"
msgstr "Предзагрузить все предустановленные списки"
msgid "pre-release"
msgstr "пре-релиз"
msgid "Pre-shared key"
msgstr "Предварительный общий ключ"
@@ -3266,6 +3350,9 @@ msgstr "Предварительный общий ключ"
msgid "Prevents multiple reload_firewall calls within 120 seconds to avoid connection drops."
msgstr "Предотвращает множественные вызовы reload_firewall в течение 120 секунд для избежания разрыва соединений."
msgid "Primary DNS"
msgstr ""
msgid "Priority"
msgstr "Приоритет"
@@ -3308,6 +3395,12 @@ msgstr "Защита"
msgid "Protocol"
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"
msgstr "Глобальные настройки провайдера"
@@ -3350,12 +3443,18 @@ msgstr "QUIC (HTTP/3)"
msgid "RAG Knowledge Base + Live ISP Probe Context"
msgstr "База знаний RAG + результаты живого зондирования провайдера"
msgid "Rating"
msgstr "Оценка"
msgid "RDP"
msgstr "RDP"
msgid "Read error"
msgstr "Ошибка чтения"
msgid "Ready to benchmark DNS providers"
msgstr "Готов к тестированию DNS провайдеров"
msgid "Reality fake site"
msgstr "Фейковый сайт Reality"
@@ -3386,6 +3485,12 @@ msgstr "Пересобранный релиз"
msgid "Recommended"
msgstr "Рекомендовано"
msgid "Recommended DNS Configuration"
msgstr "Рекомендованная конфигурация DNS"
msgid "Recommended DNS settings applied successfully and service restarted!"
msgstr "Рекомендованные настройки DNS успешно применены, сервис перезапущен!"
msgid "Recommended Quick Fixes:"
msgstr "Рекомендуемые исправления:"
@@ -3419,6 +3524,15 @@ msgstr "Регулярное выражение не должно содержа
msgid "Reinstall"
msgstr "Переустановить"
msgid "Reject After Time"
msgstr ""
msgid "Rekey After Time"
msgstr ""
msgid "Rekey Timeout"
msgstr ""
msgid "Reload now"
msgstr "Перезагрузить сейчас"
@@ -3938,9 +4052,6 @@ msgstr "Сервисы и доступ"
msgid "Services are online and ready! Reloading page..."
msgstr "Службы запущены и готовы к работе! Перезагрузка страницы..."
msgid "Services are online, waiting for full initialization..."
msgstr "Сервисы запущены, ожидание полной инициализации..."
msgid "Services info"
msgstr "Информация о сервисах"
@@ -4037,6 +4148,9 @@ msgstr "Пропущены комментарии/невалидные:"
msgid "Skipped loopback:"
msgstr "Пропущены loopback:"
msgid "SLOW"
msgstr "МЕДЛЕННО"
msgid "Snapshot name"
msgstr "Имя снапшота"
@@ -4136,6 +4250,9 @@ msgstr "Стандартный"
msgid "Start"
msgstr "Старт"
msgid "Start Benchmark"
msgstr "Начать тест"
msgid "Start bot"
msgstr "Запустить бота"
@@ -4151,6 +4268,9 @@ msgstr "Время начала (ЧЧ:ММ)"
msgid "Start watchdog"
msgstr "Запустить watchdog"
msgid "Starting DNS benchmark..."
msgstr "Запуск бенчмарка DNS..."
msgid "Starting…"
msgstr "Запуск…"
@@ -4235,6 +4355,9 @@ msgstr "Успех"
msgid "Successfully imported %d DNS record(s)"
msgstr "Успешно импортировано %d DNS-записей"
msgid "Successfully updated %d hosts entries"
msgstr ""
msgid "Sun"
msgstr "Вс"
@@ -4268,9 +4391,15 @@ msgstr "Порядок и видимость вкладок"
msgid "Table exist"
msgstr "Таблица существует"
msgid "Tachyon"
msgstr ""
msgid "Tachyon Core"
msgstr "Ядро Tachyon"
msgid "Tachyon DNS Benchmark & Auto-Tuning"
msgstr "Tachyon: Бенчмарк и автоподбор DNS"
msgid "Tachyon Error"
msgstr "Ошибка Tachyon"
@@ -4409,6 +4538,9 @@ msgstr "Тестировать серверы, чьи имена соответ
msgid "Test Telegram Connection"
msgstr "Проверить подключение к Telegram"
msgid "Testing"
msgstr ""
msgid "Testing bypass strategies in isolated sandbox..."
msgstr "Тестирование стратегий обхода в изолированной песочнице..."
@@ -4502,6 +4634,9 @@ msgstr "Время суток для запуска планового обно
msgid "Time skew tolerance"
msgstr "Допуск отклонения времени"
msgid "Timeout"
msgstr ""
msgid "tiny"
msgstr "tiny"
@@ -4727,6 +4862,9 @@ msgstr "Хранится до 10 снапшотов; самые старые у
msgid "Update"
msgstr "Обновить"
msgid "Update failed:"
msgstr ""
msgid "Update is available"
msgstr "Доступно обновление"
@@ -4739,6 +4877,9 @@ msgstr "Доступна новая версия:"
msgid "Update lists now"
msgstr "Обновить списки сейчас"
msgid "Update Lists Now"
msgstr ""
msgid "Update subscriptions"
msgstr "Обновить подписки"
@@ -4760,6 +4901,9 @@ msgstr "Обновление режима маршрутизации устро
msgid "Updating lists..."
msgstr "Обновление списков..."
msgid "Updating…"
msgstr ""
msgid "Uplink"
msgstr "Исходящий"
@@ -4889,6 +5033,9 @@ msgstr "Значение не должно содержать символы у
msgid "Verifying router and service readiness..."
msgstr "Проверка готовности роутера и служб..."
msgid "Versions"
msgstr "Версии"
msgid "Via country.is"
msgstr "Через country.is"
@@ -4925,9 +5072,6 @@ msgstr "Токен доступа WARP"
msgid "WARP Account ID"
msgstr "ID аккаунта WARP"
msgid "WARP Configuration generated and loaded successfully!"
msgstr "Конфигурация WARP успешно сгенерирована и загружена!"
msgid "WARP Generator Proxy Section"
msgstr "Секция прокси для генератора WARP"
@@ -4973,6 +5117,9 @@ msgstr "Приватный ключ WireGuard из вашего аккаунта
msgid "Working"
msgstr "Рабочих"
msgid "working strategies"
msgstr ""
msgid "XHTTP mode"
msgstr "Режим XHTTP"
@@ -5039,6 +5186,24 @@ msgstr "sing-box outbound для Zapret2 настроен"
msgid "Zapret2 sing-box outbound is not configured"
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"
msgstr "⏹ Стоп"
@@ -5726,18 +5891,6 @@ msgstr "CleanBrowsing (Семейный)"
msgid "Yandex Safe"
msgstr "Yandex (Безопасный)"
msgid "Versions"
msgstr "Версии"
msgid "Loading versions..."
msgstr "Загрузка версий..."
msgid "No versions found"
msgstr "Версии не найдены"
msgid "Failed to load versions"
msgstr "Не удалось загрузить версии"
msgid "Installing "
msgstr "Установка "
@@ -5750,5 +5903,26 @@ msgstr "Ошибка установки: "
msgid "Installed "
msgstr "Установлено "
msgid "pre-release"
msgstr "пре-релиз"
msgid "AmneziaWG 2.0"
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"
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -282,7 +282,7 @@ function command_spec(command) {
fuzzer_auto_apply: [ "diagnostics/fuzzer.uc", "auto_apply", 1 ],
fuzzer_history: [ "diagnostics/fuzzer.uc", "history", 1 ],
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_postinst: [ "service/package.uc", "postinst", 0 ],
luci_postinst: [ "service/package.uc", "luci-postinst", 0 ],
+6
View File
@@ -176,6 +176,12 @@ function awg_tag_chain(value) {
if (value == "" || value == "0")
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
// ("<b 0x..>" carries a space inside each tag).
if (match(value, /^(<[^<>]+>)+$/))
+23 -1
View File
@@ -641,7 +641,7 @@ function section_has_dscp_matchers(section) {
function section_needs_priority_sets(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) {
@@ -791,6 +791,28 @@ function nft_add_section_priority_rules(table, section, interface_set, localv4_s
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;
}
@@ -424,7 +424,17 @@ if (!response_data.warp_enabled) {
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 != "") {
let patch_body = { license_key: license_key };
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 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,
local_address: response_data.config.interface.addresses.v4 + "/32 " + response_data.config.interface.addresses.v6 + "/128",
private_key: private_key,
peer_public_key: response_data.config.peers[0].public_key,
server_address: best_ip,
server_port: random_port,
awg_jc: 4,
awg_version: "2.0",
awg_jc: 5,
awg_jmin: 40,
awg_jmax: 70,
awg_s1: 0, awg_s2: 0, awg_s3: 0, awg_s4: 0,
awg_h1: 1, awg_h2: 2, awg_h3: 3, awg_h4: 4,
awg_s1: 0,
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_i2: i2,
awg_i3: i3,
awg_i4: i4,
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 j3 = awg_cps_option(section, "awg_j3");
let itime = int_option(section, "awg_itime", "0");
let is_lx = trim(fs.readfile("/etc/tachyon/sing-box-variant") || "") == "lx" ||
index(trim(fs.readfile("/etc/tachyon/sing-box-version") || ""), "-lx") >= 0;
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");
if (is_lx) {
// 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 (i4 != "" && i4 != "0") endpoint.i4 = i4;
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
// the lx AWG 2.0 schema, so they are intentionally not emitted here.
} 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 ||
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;
if (has_route_matchers) {
let resolve = runtime_route.resolve_rule_for_section(section, route_rule);
+21
View File
@@ -989,6 +989,27 @@ function init_config(populate_nft, caches_prepared, no_refresh) {
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)
break;
+59 -2
View File
@@ -212,6 +212,10 @@ function apply_transport(inbound, section, protocol) {
}
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 = {
type: protocol,
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 jmax = int_option(section, "awg_jmax", "70");
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 = {
jc: jc,
@@ -354,6 +356,52 @@ function add_standard_inbound(config, section, protocol, tag_name) {
if (i3 != "" && i3 != "0") inbound.i3 = i3;
if (i4 != "" && i4 != "0") inbound.i4 = i4;
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 {
if (i1 != "") amnezia.i1 = i1;
if (i2 != "") amnezia.i2 = i2;
@@ -380,8 +428,17 @@ function add_standard_inbound(config, section, protocol, tag_name) {
apply_tls(inbound, section, protocol);
apply_transport(inbound, section, protocol);
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) {
let inbound = {};
+17
View File
@@ -328,6 +328,20 @@ cat >"$WORK_DIR/priority-rules.json" <<'JSON'
"enabled": "1",
"action": "bypass",
"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\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\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" \
$'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' \
+69 -2
View File
@@ -16,7 +16,7 @@ fail() {
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'
{
"settings": {
@@ -30,6 +30,7 @@ cat >"$WORK_DIR/awg_fixture.json" <<'JSON'
".type": "server",
"enabled": "1",
"protocol": "awg",
"awg_version": "2.0",
"awg_private_key": "aW5ib3VuZF9wcml2YXRlX2tleQ==",
"awg_peer_public_key": "cGVlcl9wdWJsaWNfa2V5",
"awg_server_address": "192.168.1.100",
@@ -44,6 +45,59 @@ cat >"$WORK_DIR/awg_fixture.json" <<'JSON'
"awg_h2": "200",
"awg_h3": "300",
"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": [
@@ -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 '"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'
+9
View File
@@ -344,6 +344,14 @@ cat >"$WORK_DIR/runtime-matchers-fixture.json" <<'JSON'
"mixed_proxy_auth_enabled": "1",
"mixed_proxy_username": "user",
"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 => 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 == "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"));
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");
+13 -3
View File
@@ -57,9 +57,19 @@ if (res1 != "<b 0x123450>") {
warn("awg_tag_chain should pad odd length hex: got " + res1 + "\n");
exit(1);
}
let res2 = common.awg_tag_chain("1234");
if (res2 != "<b 0x1234>") {
warn("awg_tag_chain should format even length hex: got " + res2 + "\n");
let res3 = common.awg_tag_chain("<t><r 10><b 0x69d107975bdca8994ea71d><rc 12><rd 7>");
if (res3 != "<t><r 10><b 0x69d107975bdca8994ea71d><rc 12><rd 7>") {
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);
}
' || fail "awg_tag_chain odd-hex padding failed"