feat(fuzzer): мульти-таргетные сьюты, конструктор паттернов, кастомные стратегии и минималистичный UI
This commit is contained in:
+1321
-951
File diff suppressed because it is too large
Load Diff
+1142
-907
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: TACHYON\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-08-27 07:39+0300\n"
|
||||
"PO-Revision-Date: 2026-08-27 07:39+0300\n"
|
||||
"POT-Creation-Date: 2026-08-27 13:54+0300\n"
|
||||
"PO-Revision-Date: 2026-08-27 13:54+0300\n"
|
||||
"Last-Translator: Dushnilin\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: ru\n"
|
||||
@@ -35,6 +35,9 @@ msgstr "+ Добавить уровень"
|
||||
msgid "+ Add priority"
|
||||
msgstr "+ Добавить приоритет"
|
||||
|
||||
msgid "+ Add Strategy"
|
||||
msgstr ""
|
||||
|
||||
msgid "+ Add URLTest"
|
||||
msgstr "+ Добавить URLTest"
|
||||
|
||||
@@ -59,6 +62,12 @@ msgstr "⚠️ Если все основные DNS завершатся с ош
|
||||
msgid "⚡ DPI Strategy Fuzzer"
|
||||
msgstr "⚡ DPI Strategy Fuzzer"
|
||||
|
||||
msgid "⚡ Fast (>1MB/s)"
|
||||
msgstr ""
|
||||
|
||||
msgid "⚡ QUIC / HTTP/3 (UDP 443)"
|
||||
msgstr ""
|
||||
|
||||
msgid "⚡ Quick Benchmark (Presets ~12-14)"
|
||||
msgstr "⚡ Быстрый бенчмарк (Пресеты ~12-14)"
|
||||
|
||||
@@ -68,6 +77,12 @@ msgstr "⚡ Подборщик стратегий и авто-тюнер"
|
||||
msgid "✅ Benchmark completed! Optimal strategy identified."
|
||||
msgstr "✅ Бенчмарк завершен! Оптимальная стратегия определена."
|
||||
|
||||
msgid "✅ Working only"
|
||||
msgstr ""
|
||||
|
||||
msgid "✈️ Telegram Suite (Web + Bot API)"
|
||||
msgstr ""
|
||||
|
||||
msgid "✔ Online"
|
||||
msgstr ""
|
||||
|
||||
@@ -80,11 +95,32 @@ msgstr ""
|
||||
msgid "✘ Stopped"
|
||||
msgstr "✘ Остановлено"
|
||||
|
||||
msgid "🏆 Apply Best Strategy"
|
||||
msgstr "🏆 Применить лучшую стратегию"
|
||||
msgid "🌐 Custom Target URL..."
|
||||
msgstr ""
|
||||
|
||||
msgid "🔍 Combinatorial Deep Fuzzing (~40-60)"
|
||||
msgstr "🔍 Комбинаторный глубокий перебор (~40-60)"
|
||||
msgid "🎬 YouTube Suite (Web + 4K Stream)"
|
||||
msgstr ""
|
||||
|
||||
msgid "🏆 Apply Best Match"
|
||||
msgstr ""
|
||||
|
||||
msgid "🏴☠️ RuTracker Suite"
|
||||
msgstr ""
|
||||
|
||||
msgid "💬 Discord Suite (API + WSS + CDN)"
|
||||
msgstr ""
|
||||
|
||||
msgid "💾 Save Custom Patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "📸 Instagram / Meta (Web + CDN)"
|
||||
msgstr ""
|
||||
|
||||
msgid "🔄 Reset to Factory Defaults"
|
||||
msgstr ""
|
||||
|
||||
msgid "🔍 Combinatorial Deep Fuzzing (~40-80+)"
|
||||
msgstr ""
|
||||
|
||||
msgid "🔑 Generate"
|
||||
msgstr "🔑 Сгенерировать"
|
||||
@@ -95,15 +131,15 @@ msgstr "🧠 Сгенерировать через ИИ"
|
||||
msgid "🧠 Synthesizing..."
|
||||
msgstr "🧠 Генерация..."
|
||||
|
||||
msgid "🚀 Run Benchmark Again"
|
||||
msgstr "🚀 Запустить бенчмарк снова"
|
||||
|
||||
msgid "🚀 Start Benchmark"
|
||||
msgstr "🚀 Начать бенчмарк"
|
||||
|
||||
msgid "🛑 Stop Benchmark"
|
||||
msgstr "🛑 Остановить бенчмарк"
|
||||
|
||||
msgid "🛠️ My Custom Strategies Only"
|
||||
msgstr ""
|
||||
|
||||
msgid "Accept external proxy connections and route them with sing-box."
|
||||
msgstr "Принимать внешние прокси-подключения и маршрутизировать их через sing-box."
|
||||
|
||||
@@ -119,6 +155,9 @@ msgstr "Действие не выполнено"
|
||||
msgid "Action Mode"
|
||||
msgstr "Режим действия"
|
||||
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Active"
|
||||
msgstr "Активные"
|
||||
|
||||
@@ -155,6 +194,9 @@ msgstr "Добавить серверный инбаунд"
|
||||
msgid "Add at least one DNS server"
|
||||
msgstr "Добавьте как минимум один DNS-сервер"
|
||||
|
||||
msgid "Add Custom DPI Strategy"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add prefix to nodes"
|
||||
msgstr "Добавить префикс к узлам"
|
||||
|
||||
@@ -245,8 +287,11 @@ msgstr "Ошибка ИИ-доктора"
|
||||
msgid "AI Doctor Language"
|
||||
msgstr "Язык ИИ-доктора"
|
||||
|
||||
msgid "AI DPI Engineer & Strategy Synthesizer (RAG-Powered)"
|
||||
msgstr "ИИ-инженер DPI и генератор стратегий (на базе RAG)"
|
||||
msgid "AI Doctor RAG"
|
||||
msgstr ""
|
||||
|
||||
msgid "AI DPI Engineer & Strategy Synthesizer"
|
||||
msgstr ""
|
||||
|
||||
msgid "AI Model"
|
||||
msgstr "Модель ИИ"
|
||||
@@ -386,6 +431,9 @@ msgstr "Применение исправления"
|
||||
msgid "Applying..."
|
||||
msgstr "Применение..."
|
||||
|
||||
msgid "Arguments"
|
||||
msgstr ""
|
||||
|
||||
msgid "Ask Tachyon AI Assistant a question..."
|
||||
msgstr "Задайте вопрос ИИ-ассистенту..."
|
||||
|
||||
@@ -404,6 +452,9 @@ msgstr "Auth Digest"
|
||||
msgid "Auto"
|
||||
msgstr "Авто"
|
||||
|
||||
msgid "Auto Modes (--auto)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Auto refresh"
|
||||
msgstr "Автообновление"
|
||||
|
||||
@@ -431,9 +482,6 @@ msgstr "Автолечение сетевого стека"
|
||||
msgid "Auto-update Hosts Lists"
|
||||
msgstr "Автообновление списков Hosts"
|
||||
|
||||
msgid "Automated DPI Strategy Fuzzer & Auto-Tuner"
|
||||
msgstr "Автоматический подборщик и оптимизатор стратегий DPI"
|
||||
|
||||
msgid "Automatic component update checks"
|
||||
msgstr "Автоматическая проверка обновлений компонентов"
|
||||
|
||||
@@ -452,6 +500,9 @@ msgstr "Автоматически создать аккаунт Cloudflare WARP
|
||||
msgid "Automatically increase check intervals when healthy (to 5 min) and decrease on problems (to 120s)."
|
||||
msgstr "Автоматически увеличивать интервалы проверки при нормальном состоянии (до 5 мин) и уменьшать при проблемах (до 120с)."
|
||||
|
||||
msgid "Automatically runs a diagnostic probe against the target service, queries the built-in DPI Knowledge Base, and synthesizes 3-5 custom bypass strategies tailored to your ISP."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically select the fastest node in the current level"
|
||||
msgstr "Автовыбор самого быстрого узла уровня"
|
||||
|
||||
@@ -482,15 +533,15 @@ msgstr "Начало интервала расписания (например,
|
||||
msgid "Belarus (by)"
|
||||
msgstr "Беларусь (by)"
|
||||
|
||||
msgid "Benchmark & Test"
|
||||
msgstr ""
|
||||
|
||||
msgid "Benchmark stopped"
|
||||
msgstr "Бенчмарк остановлен"
|
||||
|
||||
msgid "Benchmarking in progress..."
|
||||
msgstr "Выполняется бенчмарк..."
|
||||
|
||||
msgid "Benchmarks a suite of packet desynchronization strategies in an isolated sandbox without disrupting active traffic, ranking them by latency, TTFB, and throughput."
|
||||
msgstr "Тестирует набор стратегий десинхронизации пакетов в изолированном сэндбоксе без влияния на активный трафик и ранжирует их по задержке, TTFB и скорости."
|
||||
|
||||
msgid "BitTorrent / P2P"
|
||||
msgstr "BitTorrent / P2P"
|
||||
|
||||
@@ -782,6 +833,9 @@ msgstr "Токен доступа Cloudflare WARP API"
|
||||
msgid "Comma-separated list of Telegram user IDs authorized to control the bot."
|
||||
msgstr "Список Telegram user ID через запятую, авторизованных для управления ботом."
|
||||
|
||||
msgid "Command-line arguments string..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Community Lists"
|
||||
msgstr "Community-списки"
|
||||
|
||||
@@ -908,6 +962,9 @@ msgstr "Пользовательский заголовок для инициа
|
||||
msgid "Custom header for handshake response"
|
||||
msgstr "Пользовательский заголовок для ответа рукопожатия"
|
||||
|
||||
msgid "Custom interface/section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Custom OpenAI-Compatible API"
|
||||
msgstr "Пользовательский OpenAI-совместимый API"
|
||||
|
||||
@@ -917,8 +974,8 @@ msgstr "Пользовательский URL эндпоинта OpenAI-совм
|
||||
msgid "Custom outbound configurations in JSON format"
|
||||
msgstr "Пользовательские конфигурации outbound в формате JSON"
|
||||
|
||||
msgid "Custom Target URL..."
|
||||
msgstr "Свой URL для теста..."
|
||||
msgid "Custom strategy added!"
|
||||
msgstr ""
|
||||
|
||||
msgid "Daily Quota"
|
||||
msgstr "Дневная квота"
|
||||
@@ -941,9 +998,6 @@ msgstr "По умолчанию (авто)"
|
||||
msgid "Default (Direct WAN / Default mixed proxy)"
|
||||
msgstr "По умолчанию (WAN / стандартный смешанный прокси)"
|
||||
|
||||
msgid "default (service mixed proxy)"
|
||||
msgstr "по умолчанию (сервисный смешанный прокси)"
|
||||
|
||||
msgid "Default address for checking server availability and latency. URLTest uses its own address."
|
||||
msgstr "Адрес по умолчанию для проверки доступности и задержки сервера. URLTest использует свой собственный адрес."
|
||||
|
||||
@@ -1031,8 +1085,8 @@ msgstr "Отключено"
|
||||
msgid "Disabling interception is incompatible with action=zapret2 because Tachyon sends matched traffic through NFQUEUE."
|
||||
msgstr "Отключение перехвата несовместимо с action=zapret2, потому что Tachyon направляет совпавший трафик через NFQUEUE."
|
||||
|
||||
msgid "Discord (Gateway / API / Voice)"
|
||||
msgstr "Discord (Шлюз / API / Голосовые каналы)"
|
||||
msgid "Disorder Values (-d)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Display name"
|
||||
msgstr "Отображаемое имя"
|
||||
@@ -1481,6 +1535,9 @@ msgstr "Не удалось создать отчёт об ошибке"
|
||||
msgid "Failed to generate WARP config:"
|
||||
msgstr "Не удалось сгенерировать конфигурацию WARP:"
|
||||
|
||||
msgid "Failed to get fuzzer patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to get fuzzer status"
|
||||
msgstr ""
|
||||
|
||||
@@ -1505,6 +1562,9 @@ msgstr "Не удалось прочитать лог операции"
|
||||
msgid "Failed to receive response from AI service."
|
||||
msgstr "Не удалось получить ответ от ИИ-сервиса."
|
||||
|
||||
msgid "Failed to reset fuzzer patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to reset settings"
|
||||
msgstr "Не удалось сбросить настройки"
|
||||
|
||||
@@ -1526,6 +1586,12 @@ msgstr "Ошибка сохранения IP устройств"
|
||||
msgid "Failed to save DNS Turbo Cache"
|
||||
msgstr "Не удалось сохранить DNS Turbo Cache"
|
||||
|
||||
msgid "Failed to save fuzzer patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to save patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to save Smart Detect settings"
|
||||
msgstr "Ошибка сохранения настроек Smart Detect"
|
||||
|
||||
@@ -1601,6 +1667,9 @@ msgstr "Фильтр по сервису:"
|
||||
msgid "Filter the servers that will be displayed on the dashboard."
|
||||
msgstr "Фильтровать серверы, отображаемые на дашборде."
|
||||
|
||||
msgid "Filter:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Finland (fi)"
|
||||
msgstr "Финляндия (fi)"
|
||||
|
||||
@@ -1622,6 +1691,12 @@ msgstr "Исправлено"
|
||||
msgid "Flush Conntrack Table"
|
||||
msgstr "Очистить таблицу соед. (conntrack)"
|
||||
|
||||
msgid "Fooling Methods (dpi-desync-fooling)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Fooling Methods (fooling)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Force immediate download and refresh of all remote lists and rule sets"
|
||||
msgstr "Принудительно скачать и обновить все удаленные списки и наборы правил"
|
||||
|
||||
@@ -1925,9 +2000,6 @@ msgstr "Полезный груз init (I1)"
|
||||
msgid "Init timeout (Itime)"
|
||||
msgstr "Таймаут init (Itime)"
|
||||
|
||||
msgid "Instagram / Meta (TLS 1.3)"
|
||||
msgstr "Instagram / Meta (TLS 1.3)"
|
||||
|
||||
msgid "Install"
|
||||
msgstr "Установить"
|
||||
|
||||
@@ -2180,6 +2252,9 @@ msgstr "Некорректный VMess URL: ошибка разбора"
|
||||
msgid "IP Addresses (IP CIDR)"
|
||||
msgstr "IP-адреса (IP CIDR)"
|
||||
|
||||
msgid "IP Frag Bounds (--ip-frag)"
|
||||
msgstr ""
|
||||
|
||||
msgid "IPs"
|
||||
msgstr "IP"
|
||||
|
||||
@@ -2282,9 +2357,6 @@ msgstr "Путь к ключу"
|
||||
msgid "Keyword must not contain spaces or commas"
|
||||
msgstr "Ключевое слово не должно содержать пробелов или запятых"
|
||||
|
||||
msgid "Knowledge Base + Live Probe Context"
|
||||
msgstr "База знаний + Контекст сетевого зонда"
|
||||
|
||||
msgid "LAN Devices"
|
||||
msgstr "Устройства LAN"
|
||||
|
||||
@@ -2492,6 +2564,12 @@ msgstr "Должен быть список числовых ID через зап
|
||||
msgid "Must be a number in the range of 0 - 10000"
|
||||
msgstr "Должно быть числом в диапазоне 0 - 10000"
|
||||
|
||||
msgid "My Strategies"
|
||||
msgstr ""
|
||||
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Name displayed on the dashboard"
|
||||
msgstr "Имя, отображаемое на дашборде"
|
||||
|
||||
@@ -2555,8 +2633,8 @@ msgstr "Активные устройства в локальной сети н
|
||||
msgid "No active routing sections found."
|
||||
msgstr "Активные секции маршрутизации не найдены."
|
||||
|
||||
msgid "No benchmark results yet. Select engine and click \"Start Benchmark\" or \"Synthesize with AI\"."
|
||||
msgstr "Нет результатов бенчмарка. Выберите движок и нажмите «Начать бенчмарк» или «Сгенерировать через ИИ»."
|
||||
msgid "No benchmark results yet. Configure options and click \"Start Benchmark\"."
|
||||
msgstr ""
|
||||
|
||||
msgid "No check targets found in the configuration."
|
||||
msgstr "Цели для проверки не найдены в конфигурации."
|
||||
@@ -2570,6 +2648,9 @@ msgstr "Конфликт не обнаружен"
|
||||
msgid "No Custom Rules Matched"
|
||||
msgstr "Нет совпадений с пользовательскими правилами"
|
||||
|
||||
msgid "No custom strategies added yet."
|
||||
msgstr ""
|
||||
|
||||
msgid "No DHCP clients detected"
|
||||
msgstr "DHCP-клиенты не обнаружены"
|
||||
|
||||
@@ -2612,6 +2693,9 @@ msgstr "Секции не выбраны"
|
||||
msgid "No snapshots yet"
|
||||
msgstr "Снапшотов пока нет"
|
||||
|
||||
msgid "No strategies match the active filter."
|
||||
msgstr ""
|
||||
|
||||
msgid "Node list is empty"
|
||||
msgstr "Список узлов пуст"
|
||||
|
||||
@@ -2723,6 +2807,9 @@ msgstr "Только серверы с одним из выбранных тра
|
||||
msgid "Only the specified servers."
|
||||
msgstr "Только указанные серверы."
|
||||
|
||||
msgid "OOB Values (-o)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open"
|
||||
msgstr "Открыть"
|
||||
|
||||
@@ -2768,12 +2855,12 @@ msgstr "Параметр \"%s\" содержит недопустимое зна
|
||||
msgid "Optional — leave empty for default"
|
||||
msgstr "Опционально — оставьте пустым для значения по умолчанию"
|
||||
|
||||
msgid "Optional context (e.g. \"Rostelecom, YouTube 4K buffering is slow\")..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Optional for local LLM"
|
||||
msgstr "Опционально для локальных LLM"
|
||||
|
||||
msgid "Optional notes for AI (e.g. \"Rostelecom, YouTube 4K stream is slow\")..."
|
||||
msgstr "Дополнительные заметки для ИИ (напр. «Ростелеком, тормозит 4K на YouTube»)..."
|
||||
|
||||
msgid "Optional tls-auth or tls-crypt key"
|
||||
msgstr "Опциональный ключ tls-auth или tls-crypt"
|
||||
|
||||
@@ -2837,6 +2924,21 @@ msgstr "Путь должен содержать как минимум одну
|
||||
msgid "Path must end with cache.db"
|
||||
msgstr "Путь должен заканчиваться на cache.db"
|
||||
|
||||
msgid "Pattern Builder"
|
||||
msgstr ""
|
||||
|
||||
msgid "Patterns reset to defaults!"
|
||||
msgstr ""
|
||||
|
||||
msgid "Patterns reset to factory defaults"
|
||||
msgstr ""
|
||||
|
||||
msgid "Patterns saved successfully"
|
||||
msgstr ""
|
||||
|
||||
msgid "Patterns saved successfully!"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pause updates"
|
||||
msgstr "Приостановить обновление"
|
||||
|
||||
@@ -2888,6 +2990,9 @@ msgstr "Закрепить на дашборде"
|
||||
msgid "Pin P2P isolation to the torrent client's own ports, comma separated. Each entry is \"proto\", \"proto:port\" or \"proto:port-port\" (tcp/udp). Without a port the whole protocol is routed direct."
|
||||
msgstr "Закрепить изоляцию P2P за портами торрент-клиента, через запятую. Каждая запись — \"протокол\", \"протокол:порт\" или \"протокол:порт-порт\" (tcp/udp). Без порта весь протокол уходит напрямую."
|
||||
|
||||
msgid "Please specify strategy name and arguments"
|
||||
msgstr ""
|
||||
|
||||
msgid "Polling Interval (seconds)"
|
||||
msgstr "Интервал опроса (секунды)"
|
||||
|
||||
@@ -3014,6 +3119,9 @@ msgstr "QR-код слишком большой"
|
||||
msgid "QUIC (HTTP/3)"
|
||||
msgstr "QUIC (HTTP/3)"
|
||||
|
||||
msgid "RAG Knowledge Base + Live ISP Probe Context"
|
||||
msgstr ""
|
||||
|
||||
msgid "RDP"
|
||||
msgstr "RDP"
|
||||
|
||||
@@ -3290,18 +3398,15 @@ msgstr "Запустить восстановление"
|
||||
msgid "Running"
|
||||
msgstr "Запущен"
|
||||
|
||||
msgid "Running benchmarks..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Running diagnostics…"
|
||||
msgstr "Выполняется диагностика…"
|
||||
|
||||
msgid "Running initial strategy probe..."
|
||||
msgstr "Запуск первого зонда стратегии..."
|
||||
|
||||
msgid "Russia (ru)"
|
||||
msgstr "Россия (ru)"
|
||||
|
||||
msgid "RuTracker (HTTP/HTTPS)"
|
||||
msgstr "RuTracker (HTTP/HTTPS)"
|
||||
|
||||
msgid "Sat"
|
||||
msgstr "Сб"
|
||||
|
||||
@@ -3365,8 +3470,8 @@ msgstr "Действие секции"
|
||||
msgid "Section name"
|
||||
msgstr "Имя секции"
|
||||
|
||||
msgid "Section name for WARP registration proxy. Leave empty to use the default service mixed proxy."
|
||||
msgstr "Секция для прокси регистрации WARP. Оставьте пустым для использования сервисного смешанного прокси по умолчанию."
|
||||
msgid "Section or tunnel interface used for Cloudflare WARP API registration. Supports Connection, WireGuard, AmneziaWG, and Interface sections. Leave empty to use direct WAN / default mixed proxy."
|
||||
msgstr ""
|
||||
|
||||
msgid "Section Rules Content"
|
||||
msgstr "Содержимое правил секции"
|
||||
@@ -3503,6 +3608,9 @@ msgstr "Отправлять уведомление в Telegram при пере
|
||||
msgid "Send a Telegram notification when proxy subscriptions are successfully updated."
|
||||
msgstr "Отправлять уведомление в Telegram при успешном обновлении подписок прокси."
|
||||
|
||||
msgid "Sequence Overlaps (seqovl)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Server"
|
||||
msgstr "Сервер"
|
||||
|
||||
@@ -3722,6 +3830,18 @@ msgstr "Укажите разные файлы"
|
||||
msgid "Speed"
|
||||
msgstr "Скорость"
|
||||
|
||||
msgid "Split Modes (dpi-desync)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Split Positions (dpi-desync-split-pos)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Split Positions (pos)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Split Values (-s)"
|
||||
msgstr ""
|
||||
|
||||
msgid "SSH"
|
||||
msgstr "SSH"
|
||||
|
||||
@@ -3788,6 +3908,9 @@ msgstr ""
|
||||
msgid "Status"
|
||||
msgstr "Статус"
|
||||
|
||||
msgid "Status / Suite"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stop"
|
||||
msgstr "Стоп"
|
||||
|
||||
@@ -3815,6 +3938,12 @@ msgstr "Стратегия и параметры"
|
||||
msgid "Strategy benchmark started"
|
||||
msgstr "Бенчмарк стратегий запущен"
|
||||
|
||||
msgid "Strategy deleted"
|
||||
msgstr ""
|
||||
|
||||
msgid "Strategy Name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Strict ECH + DoQ DNS Enforcer"
|
||||
msgstr "Строгий ECH + DoQ DNS Enforcer"
|
||||
|
||||
@@ -3965,8 +4094,11 @@ msgstr "Целевые устройства (IP / MAC)"
|
||||
msgid "Target Scope"
|
||||
msgstr "Область действия"
|
||||
|
||||
msgid "Target Service"
|
||||
msgstr "Целевой сервис"
|
||||
msgid "Target Service / Suite"
|
||||
msgstr ""
|
||||
|
||||
msgid "TCP Window Sizes (wsize)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Telegram Bot"
|
||||
msgstr "Telegram Бот"
|
||||
@@ -3977,9 +4109,6 @@ msgstr "Токен Telegram-бота"
|
||||
msgid "Telegram Channel"
|
||||
msgstr "Telegram канал"
|
||||
|
||||
msgid "Telegram Web"
|
||||
msgstr "Telegram Web"
|
||||
|
||||
msgid "Test Connection"
|
||||
msgstr "Проверить подключение"
|
||||
|
||||
@@ -4106,6 +4235,9 @@ msgstr "Ключ TLS Auth/Crypt"
|
||||
msgid "TLS SNI"
|
||||
msgstr "TLS SNI"
|
||||
|
||||
msgid "TLS-Rec Bounds (--tlsrec)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Token is required when the bot is enabled"
|
||||
msgstr "Токен обязателен, когда бот включён"
|
||||
|
||||
@@ -4187,6 +4319,12 @@ msgstr "TTL должен быть положительным числом"
|
||||
msgid "TTL value cannot be empty"
|
||||
msgstr "Значение TTL не может быть пустым"
|
||||
|
||||
msgid "TTL Values (dpi-desync-ttl)"
|
||||
msgstr ""
|
||||
|
||||
msgid "TTL Values (ttl)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tue"
|
||||
msgstr "Вт"
|
||||
|
||||
@@ -4421,6 +4559,9 @@ msgstr "Использовать exit-node тейлнета для LAN"
|
||||
msgid "Used by"
|
||||
msgstr "Используется"
|
||||
|
||||
msgid "User custom strategy"
|
||||
msgstr ""
|
||||
|
||||
msgid "User-Agent"
|
||||
msgstr "User-Agent"
|
||||
|
||||
@@ -4550,12 +4691,6 @@ msgstr "Да"
|
||||
msgid "You can select Output Network Interface, by default autodetect"
|
||||
msgstr "Вы можете выбрать выходной сетевой интерфейс, по умолчанию автоопределение"
|
||||
|
||||
msgid "YouTube (GoogleVideo 4K stream)"
|
||||
msgstr "YouTube (4K видеопоток GoogleVideo)"
|
||||
|
||||
msgid "YouTube Web (Interface)"
|
||||
msgstr "YouTube Web (Интерфейс)"
|
||||
|
||||
msgid "Zapret hostlist templates are not supported here because Tachyon does not expand them for per-rule NFQWS strategies."
|
||||
msgstr "Шаблоны hostlist Zapret не поддерживаются здесь, потому что Tachyon не расширяет их для стратегий NFQWS по правилам."
|
||||
|
||||
@@ -4604,6 +4739,66 @@ msgstr "sing-box outbound для Zapret2 настроен"
|
||||
msgid "Zapret2 sing-box outbound is not configured"
|
||||
msgstr "sing-box outbound для Zapret2 не настроен"
|
||||
|
||||
msgid "🏆 Apply Best Strategy"
|
||||
msgstr "🏆 Применить лучшую стратегию"
|
||||
|
||||
msgid "🔍 Combinatorial Deep Fuzzing (~40-60)"
|
||||
msgstr "🔍 Комбинаторный глубокий перебор (~40-60)"
|
||||
|
||||
msgid "🚀 Run Benchmark Again"
|
||||
msgstr "🚀 Запустить бенчмарк снова"
|
||||
|
||||
msgid "AI DPI Engineer & Strategy Synthesizer (RAG-Powered)"
|
||||
msgstr "ИИ-инженер DPI и генератор стратегий (на базе RAG)"
|
||||
|
||||
msgid "Automated DPI Strategy Fuzzer & Auto-Tuner"
|
||||
msgstr "Автоматический подборщик и оптимизатор стратегий DPI"
|
||||
|
||||
msgid "Benchmarks a suite of packet desynchronization strategies in an isolated sandbox without disrupting active traffic, ranking them by latency, TTFB, and throughput."
|
||||
msgstr "Тестирует набор стратегий десинхронизации пакетов в изолированном сэндбоксе без влияния на активный трафик и ранжирует их по задержке, TTFB и скорости."
|
||||
|
||||
msgid "Custom Target URL..."
|
||||
msgstr "Свой URL для теста..."
|
||||
|
||||
msgid "default (service mixed proxy)"
|
||||
msgstr "по умолчанию (сервисный смешанный прокси)"
|
||||
|
||||
msgid "Discord (Gateway / API / Voice)"
|
||||
msgstr "Discord (Шлюз / API / Голосовые каналы)"
|
||||
|
||||
msgid "Instagram / Meta (TLS 1.3)"
|
||||
msgstr "Instagram / Meta (TLS 1.3)"
|
||||
|
||||
msgid "Knowledge Base + Live Probe Context"
|
||||
msgstr "База знаний + Контекст сетевого зонда"
|
||||
|
||||
msgid "No benchmark results yet. Select engine and click \"Start Benchmark\" or \"Synthesize with AI\"."
|
||||
msgstr "Нет результатов бенчмарка. Выберите движок и нажмите «Начать бенчмарк» или «Сгенерировать через ИИ»."
|
||||
|
||||
msgid "Optional notes for AI (e.g. \"Rostelecom, YouTube 4K stream is slow\")..."
|
||||
msgstr "Дополнительные заметки для ИИ (напр. «Ростелеком, тормозит 4K на YouTube»)..."
|
||||
|
||||
msgid "Running initial strategy probe..."
|
||||
msgstr "Запуск первого зонда стратегии..."
|
||||
|
||||
msgid "RuTracker (HTTP/HTTPS)"
|
||||
msgstr "RuTracker (HTTP/HTTPS)"
|
||||
|
||||
msgid "Section name for WARP registration proxy. Leave empty to use the default service mixed proxy."
|
||||
msgstr "Секция для прокси регистрации WARP. Оставьте пустым для использования сервисного смешанного прокси по умолчанию."
|
||||
|
||||
msgid "Target Service"
|
||||
msgstr "Целевой сервис"
|
||||
|
||||
msgid "Telegram Web"
|
||||
msgstr "Telegram Web"
|
||||
|
||||
msgid "YouTube (GoogleVideo 4K stream)"
|
||||
msgstr "YouTube (4K видеопоток GoogleVideo)"
|
||||
|
||||
msgid "YouTube Web (Interface)"
|
||||
msgstr "YouTube Web (Интерфейс)"
|
||||
|
||||
msgid "No benchmark results yet. Select engine and click \"Start Benchmark\"."
|
||||
msgstr "Нет результатов бенчмарка. Выберите движок и нажмите «Начать бенчмарк»."
|
||||
|
||||
|
||||
@@ -1246,4 +1246,110 @@ export const TachyonShellMethods = {
|
||||
_('Failed to synthesize AI strategies'),
|
||||
};
|
||||
},
|
||||
|
||||
getFuzzerPatterns: async (): Promise<
|
||||
Tachyon.MethodResponse<{ patterns: Tachyon.FuzzerPatternsConfig }>
|
||||
> => {
|
||||
const response = await executeShellCommand({
|
||||
command: '/usr/bin/tachyon',
|
||||
args: [Tachyon.AvailableMethods.FUZZER_GET_PATTERNS],
|
||||
timeout: 8000,
|
||||
});
|
||||
|
||||
let parsed: {
|
||||
success: boolean;
|
||||
patterns: Tachyon.FuzzerPatternsConfig;
|
||||
} | null = null;
|
||||
try {
|
||||
parsed = JSON.parse(response.stdout?.trim() || '{}');
|
||||
} catch {
|
||||
parsed = null;
|
||||
}
|
||||
|
||||
if ((response.code ?? 1) === 0 && parsed && parsed.success) {
|
||||
return {
|
||||
success: true,
|
||||
data: parsed,
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
error: response.stderr || _('Failed to get fuzzer patterns'),
|
||||
};
|
||||
},
|
||||
|
||||
saveFuzzerPatterns: async (
|
||||
patterns: Tachyon.FuzzerPatternsConfig,
|
||||
): Promise<Tachyon.MethodResponse<{ message: string }>> => {
|
||||
const response = await executeShellCommand({
|
||||
command: '/usr/bin/tachyon',
|
||||
args: [
|
||||
Tachyon.AvailableMethods.FUZZER_SAVE_PATTERNS,
|
||||
JSON.stringify(patterns),
|
||||
],
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
let parsed: { success: boolean; message?: string; error?: string } | null =
|
||||
null;
|
||||
try {
|
||||
parsed = JSON.parse(response.stdout?.trim() || '{}');
|
||||
} catch {
|
||||
parsed = null;
|
||||
}
|
||||
|
||||
if ((response.code ?? 1) === 0 && parsed && parsed.success) {
|
||||
return {
|
||||
success: true,
|
||||
data: { message: parsed.message || _('Patterns saved successfully') },
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
parsed?.error || response.stderr || _('Failed to save fuzzer patterns'),
|
||||
};
|
||||
},
|
||||
|
||||
resetFuzzerPatterns: async (): Promise<
|
||||
Tachyon.MethodResponse<{
|
||||
patterns: Tachyon.FuzzerPatternsConfig;
|
||||
message: string;
|
||||
}>
|
||||
> => {
|
||||
const response = await executeShellCommand({
|
||||
command: '/usr/bin/tachyon',
|
||||
args: [Tachyon.AvailableMethods.FUZZER_RESET_PATTERNS],
|
||||
timeout: 8000,
|
||||
});
|
||||
|
||||
let parsed: {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
patterns?: Tachyon.FuzzerPatternsConfig;
|
||||
error?: string;
|
||||
} | null = null;
|
||||
try {
|
||||
parsed = JSON.parse(response.stdout?.trim() || '{}');
|
||||
} catch {
|
||||
parsed = null;
|
||||
}
|
||||
|
||||
if ((response.code ?? 1) === 0 && parsed && parsed.success) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
message: parsed.message || _('Patterns reset to factory defaults'),
|
||||
patterns: parsed.patterns as Tachyon.FuzzerPatternsConfig,
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
parsed?.error ||
|
||||
response.stderr ||
|
||||
_('Failed to reset fuzzer patterns'),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -182,4 +182,72 @@ describe('TachyonShellMethods Fuzzer Actions', () => {
|
||||
expect(res.data.strategies).toHaveLength(1);
|
||||
}
|
||||
});
|
||||
|
||||
it('gets fuzzer patterns configuration', async () => {
|
||||
mocks.executeShellCommand.mockResolvedValueOnce({
|
||||
stdout: JSON.stringify({
|
||||
success: true,
|
||||
patterns: {
|
||||
zapret2: { splits: ['1', '2', 'midsld'] },
|
||||
zapret: { splits: ['1', '2'] },
|
||||
byedpi: { splits: ['1'] },
|
||||
custom_strategies: [],
|
||||
},
|
||||
}),
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const res = await TachyonShellMethods.getFuzzerPatterns();
|
||||
expect(res.success).toBe(true);
|
||||
if (res.success) {
|
||||
expect(res.data.patterns.zapret2.splits).toEqual(['1', '2', 'midsld']);
|
||||
}
|
||||
});
|
||||
|
||||
it('saves fuzzer patterns configuration', async () => {
|
||||
mocks.executeShellCommand.mockResolvedValueOnce({
|
||||
stdout: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Patterns saved successfully',
|
||||
}),
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const patternsPayload: any = {
|
||||
zapret2: { splits: ['1', '2', 'midsld'] },
|
||||
zapret: { splits: ['1'] },
|
||||
byedpi: { splits: ['1'] },
|
||||
custom_strategies: [],
|
||||
};
|
||||
|
||||
const res = await TachyonShellMethods.saveFuzzerPatterns(patternsPayload);
|
||||
expect(res.success).toBe(true);
|
||||
expect(mocks.executeShellCommand).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
args: ['fuzzer_save_patterns', JSON.stringify(patternsPayload)],
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('resets fuzzer patterns configuration', async () => {
|
||||
mocks.executeShellCommand.mockResolvedValueOnce({
|
||||
stdout: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Patterns reset to factory defaults',
|
||||
patterns: {
|
||||
zapret2: { splits: ['1', '2', '3', 'midsld'] },
|
||||
},
|
||||
}),
|
||||
stderr: '',
|
||||
code: 0,
|
||||
});
|
||||
|
||||
const res = await TachyonShellMethods.resetFuzzerPatterns();
|
||||
expect(res.success).toBe(true);
|
||||
if (res.success) {
|
||||
expect(res.data.message).toBe('Patterns reset to factory defaults');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
+907
-257
File diff suppressed because it is too large
Load Diff
@@ -104,6 +104,9 @@ export namespace Tachyon {
|
||||
FUZZER_APPLY = 'fuzzer_apply',
|
||||
FUZZER_STRATEGIES = 'fuzzer_strategies',
|
||||
FUZZER_AI_SYNTHESIZE = 'fuzzer_ai_synthesize',
|
||||
FUZZER_GET_PATTERNS = 'fuzzer_get_patterns',
|
||||
FUZZER_SAVE_PATTERNS = 'fuzzer_save_patterns',
|
||||
FUZZER_RESET_PATTERNS = 'fuzzer_reset_patterns',
|
||||
}
|
||||
|
||||
export enum AvailableClashAPIMethods {
|
||||
@@ -831,15 +834,21 @@ export namespace Tachyon {
|
||||
|
||||
export type FuzzerEngine = 'zapret2' | 'zapret' | 'byedpi' | 'all';
|
||||
export type FuzzerTarget =
|
||||
| 'youtube_suite'
|
||||
| 'youtube'
|
||||
| 'youtube_web'
|
||||
| 'discord_suite'
|
||||
| 'discord'
|
||||
| 'instagram_suite'
|
||||
| 'instagram'
|
||||
| 'rutracker_suite'
|
||||
| 'rutracker'
|
||||
| 'telegram_suite'
|
||||
| 'telegram'
|
||||
| 'quic_http3'
|
||||
| 'custom';
|
||||
|
||||
export type FuzzerMode = 'presets' | 'combinatorial';
|
||||
export type FuzzerMode = 'presets' | 'combinatorial' | 'custom';
|
||||
|
||||
export interface FuzzerStrategyItem {
|
||||
id: string;
|
||||
@@ -851,6 +860,17 @@ export namespace Tachyon {
|
||||
|
||||
export type FuzzerStrategyDefinition = FuzzerStrategyItem;
|
||||
|
||||
export interface FuzzerSubProbeResult {
|
||||
target_name?: string;
|
||||
url?: string;
|
||||
http_code: number;
|
||||
handshake_ms: number;
|
||||
ttfb_ms: number;
|
||||
speed_kbps: number;
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface FuzzerStrategyResult {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -865,6 +885,7 @@ export namespace Tachyon {
|
||||
score: number;
|
||||
error?: string;
|
||||
badge?: string;
|
||||
sub_probes?: FuzzerSubProbeResult[];
|
||||
}
|
||||
|
||||
export interface FuzzerState {
|
||||
@@ -911,4 +932,50 @@ export namespace Tachyon {
|
||||
strategies?: FuzzerStrategyItem[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface FuzzerCustomStrategy {
|
||||
id?: string;
|
||||
name: string;
|
||||
engine: 'zapret2' | 'zapret' | 'byedpi';
|
||||
args: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface FuzzerPatternsConfig {
|
||||
zapret2: {
|
||||
splits: string[];
|
||||
foolings: string[];
|
||||
ttls: number[];
|
||||
seqovls: string[];
|
||||
wsizes: string[];
|
||||
payloads: string[];
|
||||
};
|
||||
zapret: {
|
||||
splits: string[];
|
||||
foolings: string[];
|
||||
ttls: number[];
|
||||
split_modes: string[];
|
||||
};
|
||||
byedpi: {
|
||||
splits: string[];
|
||||
disorders: string[];
|
||||
ttls: number[];
|
||||
oobs: string[];
|
||||
autos: string[];
|
||||
tlsrecs: string[];
|
||||
ipfrags: string[];
|
||||
};
|
||||
custom_strategies: FuzzerCustomStrategy[];
|
||||
}
|
||||
|
||||
export interface FuzzerTargetSuiteItem {
|
||||
name: string;
|
||||
url: string;
|
||||
weight: number;
|
||||
}
|
||||
|
||||
export interface FuzzerTargetSuite {
|
||||
name: string;
|
||||
urls: FuzzerTargetSuiteItem[];
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: TACHYON\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-08-27 07:39+0300\n"
|
||||
"PO-Revision-Date: 2026-08-27 07:39+0300\n"
|
||||
"POT-Creation-Date: 2026-08-27 13:54+0300\n"
|
||||
"PO-Revision-Date: 2026-08-27 13:54+0300\n"
|
||||
"Last-Translator: Dushnilin\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: ru\n"
|
||||
@@ -35,6 +35,9 @@ msgstr "+ Добавить уровень"
|
||||
msgid "+ Add priority"
|
||||
msgstr "+ Добавить приоритет"
|
||||
|
||||
msgid "+ Add Strategy"
|
||||
msgstr ""
|
||||
|
||||
msgid "+ Add URLTest"
|
||||
msgstr "+ Добавить URLTest"
|
||||
|
||||
@@ -59,6 +62,12 @@ msgstr "⚠️ Если все основные DNS завершатся с ош
|
||||
msgid "⚡ DPI Strategy Fuzzer"
|
||||
msgstr "⚡ DPI Strategy Fuzzer"
|
||||
|
||||
msgid "⚡ Fast (>1MB/s)"
|
||||
msgstr ""
|
||||
|
||||
msgid "⚡ QUIC / HTTP/3 (UDP 443)"
|
||||
msgstr ""
|
||||
|
||||
msgid "⚡ Quick Benchmark (Presets ~12-14)"
|
||||
msgstr "⚡ Быстрый бенчмарк (Пресеты ~12-14)"
|
||||
|
||||
@@ -68,6 +77,12 @@ msgstr "⚡ Подборщик стратегий и авто-тюнер"
|
||||
msgid "✅ Benchmark completed! Optimal strategy identified."
|
||||
msgstr "✅ Бенчмарк завершен! Оптимальная стратегия определена."
|
||||
|
||||
msgid "✅ Working only"
|
||||
msgstr ""
|
||||
|
||||
msgid "✈️ Telegram Suite (Web + Bot API)"
|
||||
msgstr ""
|
||||
|
||||
msgid "✔ Online"
|
||||
msgstr ""
|
||||
|
||||
@@ -80,11 +95,32 @@ msgstr ""
|
||||
msgid "✘ Stopped"
|
||||
msgstr "✘ Остановлено"
|
||||
|
||||
msgid "🏆 Apply Best Strategy"
|
||||
msgstr "🏆 Применить лучшую стратегию"
|
||||
msgid "🌐 Custom Target URL..."
|
||||
msgstr ""
|
||||
|
||||
msgid "🔍 Combinatorial Deep Fuzzing (~40-60)"
|
||||
msgstr "🔍 Комбинаторный глубокий перебор (~40-60)"
|
||||
msgid "🎬 YouTube Suite (Web + 4K Stream)"
|
||||
msgstr ""
|
||||
|
||||
msgid "🏆 Apply Best Match"
|
||||
msgstr ""
|
||||
|
||||
msgid "🏴☠️ RuTracker Suite"
|
||||
msgstr ""
|
||||
|
||||
msgid "💬 Discord Suite (API + WSS + CDN)"
|
||||
msgstr ""
|
||||
|
||||
msgid "💾 Save Custom Patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "📸 Instagram / Meta (Web + CDN)"
|
||||
msgstr ""
|
||||
|
||||
msgid "🔄 Reset to Factory Defaults"
|
||||
msgstr ""
|
||||
|
||||
msgid "🔍 Combinatorial Deep Fuzzing (~40-80+)"
|
||||
msgstr ""
|
||||
|
||||
msgid "🔑 Generate"
|
||||
msgstr "🔑 Сгенерировать"
|
||||
@@ -95,15 +131,15 @@ msgstr "🧠 Сгенерировать через ИИ"
|
||||
msgid "🧠 Synthesizing..."
|
||||
msgstr "🧠 Генерация..."
|
||||
|
||||
msgid "🚀 Run Benchmark Again"
|
||||
msgstr "🚀 Запустить бенчмарк снова"
|
||||
|
||||
msgid "🚀 Start Benchmark"
|
||||
msgstr "🚀 Начать бенчмарк"
|
||||
|
||||
msgid "🛑 Stop Benchmark"
|
||||
msgstr "🛑 Остановить бенчмарк"
|
||||
|
||||
msgid "🛠️ My Custom Strategies Only"
|
||||
msgstr ""
|
||||
|
||||
msgid "Accept external proxy connections and route them with sing-box."
|
||||
msgstr "Принимать внешние прокси-подключения и маршрутизировать их через sing-box."
|
||||
|
||||
@@ -119,6 +155,9 @@ msgstr "Действие не выполнено"
|
||||
msgid "Action Mode"
|
||||
msgstr "Режим действия"
|
||||
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Active"
|
||||
msgstr "Активные"
|
||||
|
||||
@@ -155,6 +194,9 @@ msgstr "Добавить серверный инбаунд"
|
||||
msgid "Add at least one DNS server"
|
||||
msgstr "Добавьте как минимум один DNS-сервер"
|
||||
|
||||
msgid "Add Custom DPI Strategy"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add prefix to nodes"
|
||||
msgstr "Добавить префикс к узлам"
|
||||
|
||||
@@ -245,8 +287,11 @@ msgstr "Ошибка ИИ-доктора"
|
||||
msgid "AI Doctor Language"
|
||||
msgstr "Язык ИИ-доктора"
|
||||
|
||||
msgid "AI DPI Engineer & Strategy Synthesizer (RAG-Powered)"
|
||||
msgstr "ИИ-инженер DPI и генератор стратегий (на базе RAG)"
|
||||
msgid "AI Doctor RAG"
|
||||
msgstr ""
|
||||
|
||||
msgid "AI DPI Engineer & Strategy Synthesizer"
|
||||
msgstr ""
|
||||
|
||||
msgid "AI Model"
|
||||
msgstr "Модель ИИ"
|
||||
@@ -386,6 +431,9 @@ msgstr "Применение исправления"
|
||||
msgid "Applying..."
|
||||
msgstr "Применение..."
|
||||
|
||||
msgid "Arguments"
|
||||
msgstr ""
|
||||
|
||||
msgid "Ask Tachyon AI Assistant a question..."
|
||||
msgstr "Задайте вопрос ИИ-ассистенту..."
|
||||
|
||||
@@ -404,6 +452,9 @@ msgstr "Auth Digest"
|
||||
msgid "Auto"
|
||||
msgstr "Авто"
|
||||
|
||||
msgid "Auto Modes (--auto)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Auto refresh"
|
||||
msgstr "Автообновление"
|
||||
|
||||
@@ -431,9 +482,6 @@ msgstr "Автолечение сетевого стека"
|
||||
msgid "Auto-update Hosts Lists"
|
||||
msgstr "Автообновление списков Hosts"
|
||||
|
||||
msgid "Automated DPI Strategy Fuzzer & Auto-Tuner"
|
||||
msgstr "Автоматический подборщик и оптимизатор стратегий DPI"
|
||||
|
||||
msgid "Automatic component update checks"
|
||||
msgstr "Автоматическая проверка обновлений компонентов"
|
||||
|
||||
@@ -452,6 +500,9 @@ msgstr "Автоматически создать аккаунт Cloudflare WARP
|
||||
msgid "Automatically increase check intervals when healthy (to 5 min) and decrease on problems (to 120s)."
|
||||
msgstr "Автоматически увеличивать интервалы проверки при нормальном состоянии (до 5 мин) и уменьшать при проблемах (до 120с)."
|
||||
|
||||
msgid "Automatically runs a diagnostic probe against the target service, queries the built-in DPI Knowledge Base, and synthesizes 3-5 custom bypass strategies tailored to your ISP."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically select the fastest node in the current level"
|
||||
msgstr "Автовыбор самого быстрого узла уровня"
|
||||
|
||||
@@ -482,15 +533,15 @@ msgstr "Начало интервала расписания (например,
|
||||
msgid "Belarus (by)"
|
||||
msgstr "Беларусь (by)"
|
||||
|
||||
msgid "Benchmark & Test"
|
||||
msgstr ""
|
||||
|
||||
msgid "Benchmark stopped"
|
||||
msgstr "Бенчмарк остановлен"
|
||||
|
||||
msgid "Benchmarking in progress..."
|
||||
msgstr "Выполняется бенчмарк..."
|
||||
|
||||
msgid "Benchmarks a suite of packet desynchronization strategies in an isolated sandbox without disrupting active traffic, ranking them by latency, TTFB, and throughput."
|
||||
msgstr "Тестирует набор стратегий десинхронизации пакетов в изолированном сэндбоксе без влияния на активный трафик и ранжирует их по задержке, TTFB и скорости."
|
||||
|
||||
msgid "BitTorrent / P2P"
|
||||
msgstr "BitTorrent / P2P"
|
||||
|
||||
@@ -782,6 +833,9 @@ msgstr "Токен доступа Cloudflare WARP API"
|
||||
msgid "Comma-separated list of Telegram user IDs authorized to control the bot."
|
||||
msgstr "Список Telegram user ID через запятую, авторизованных для управления ботом."
|
||||
|
||||
msgid "Command-line arguments string..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Community Lists"
|
||||
msgstr "Community-списки"
|
||||
|
||||
@@ -908,6 +962,9 @@ msgstr "Пользовательский заголовок для инициа
|
||||
msgid "Custom header for handshake response"
|
||||
msgstr "Пользовательский заголовок для ответа рукопожатия"
|
||||
|
||||
msgid "Custom interface/section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Custom OpenAI-Compatible API"
|
||||
msgstr "Пользовательский OpenAI-совместимый API"
|
||||
|
||||
@@ -917,8 +974,8 @@ msgstr "Пользовательский URL эндпоинта OpenAI-совм
|
||||
msgid "Custom outbound configurations in JSON format"
|
||||
msgstr "Пользовательские конфигурации outbound в формате JSON"
|
||||
|
||||
msgid "Custom Target URL..."
|
||||
msgstr "Свой URL для теста..."
|
||||
msgid "Custom strategy added!"
|
||||
msgstr ""
|
||||
|
||||
msgid "Daily Quota"
|
||||
msgstr "Дневная квота"
|
||||
@@ -941,9 +998,6 @@ msgstr "По умолчанию (авто)"
|
||||
msgid "Default (Direct WAN / Default mixed proxy)"
|
||||
msgstr "По умолчанию (WAN / стандартный смешанный прокси)"
|
||||
|
||||
msgid "default (service mixed proxy)"
|
||||
msgstr "по умолчанию (сервисный смешанный прокси)"
|
||||
|
||||
msgid "Default address for checking server availability and latency. URLTest uses its own address."
|
||||
msgstr "Адрес по умолчанию для проверки доступности и задержки сервера. URLTest использует свой собственный адрес."
|
||||
|
||||
@@ -1031,8 +1085,8 @@ msgstr "Отключено"
|
||||
msgid "Disabling interception is incompatible with action=zapret2 because Tachyon sends matched traffic through NFQUEUE."
|
||||
msgstr "Отключение перехвата несовместимо с action=zapret2, потому что Tachyon направляет совпавший трафик через NFQUEUE."
|
||||
|
||||
msgid "Discord (Gateway / API / Voice)"
|
||||
msgstr "Discord (Шлюз / API / Голосовые каналы)"
|
||||
msgid "Disorder Values (-d)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Display name"
|
||||
msgstr "Отображаемое имя"
|
||||
@@ -1481,6 +1535,9 @@ msgstr "Не удалось создать отчёт об ошибке"
|
||||
msgid "Failed to generate WARP config:"
|
||||
msgstr "Не удалось сгенерировать конфигурацию WARP:"
|
||||
|
||||
msgid "Failed to get fuzzer patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to get fuzzer status"
|
||||
msgstr ""
|
||||
|
||||
@@ -1505,6 +1562,9 @@ msgstr "Не удалось прочитать лог операции"
|
||||
msgid "Failed to receive response from AI service."
|
||||
msgstr "Не удалось получить ответ от ИИ-сервиса."
|
||||
|
||||
msgid "Failed to reset fuzzer patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to reset settings"
|
||||
msgstr "Не удалось сбросить настройки"
|
||||
|
||||
@@ -1526,6 +1586,12 @@ msgstr "Ошибка сохранения IP устройств"
|
||||
msgid "Failed to save DNS Turbo Cache"
|
||||
msgstr "Не удалось сохранить DNS Turbo Cache"
|
||||
|
||||
msgid "Failed to save fuzzer patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to save patterns"
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to save Smart Detect settings"
|
||||
msgstr "Ошибка сохранения настроек Smart Detect"
|
||||
|
||||
@@ -1601,6 +1667,9 @@ msgstr "Фильтр по сервису:"
|
||||
msgid "Filter the servers that will be displayed on the dashboard."
|
||||
msgstr "Фильтровать серверы, отображаемые на дашборде."
|
||||
|
||||
msgid "Filter:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Finland (fi)"
|
||||
msgstr "Финляндия (fi)"
|
||||
|
||||
@@ -1622,6 +1691,12 @@ msgstr "Исправлено"
|
||||
msgid "Flush Conntrack Table"
|
||||
msgstr "Очистить таблицу соед. (conntrack)"
|
||||
|
||||
msgid "Fooling Methods (dpi-desync-fooling)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Fooling Methods (fooling)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Force immediate download and refresh of all remote lists and rule sets"
|
||||
msgstr "Принудительно скачать и обновить все удаленные списки и наборы правил"
|
||||
|
||||
@@ -1925,9 +2000,6 @@ msgstr "Полезный груз init (I1)"
|
||||
msgid "Init timeout (Itime)"
|
||||
msgstr "Таймаут init (Itime)"
|
||||
|
||||
msgid "Instagram / Meta (TLS 1.3)"
|
||||
msgstr "Instagram / Meta (TLS 1.3)"
|
||||
|
||||
msgid "Install"
|
||||
msgstr "Установить"
|
||||
|
||||
@@ -2180,6 +2252,9 @@ msgstr "Некорректный VMess URL: ошибка разбора"
|
||||
msgid "IP Addresses (IP CIDR)"
|
||||
msgstr "IP-адреса (IP CIDR)"
|
||||
|
||||
msgid "IP Frag Bounds (--ip-frag)"
|
||||
msgstr ""
|
||||
|
||||
msgid "IPs"
|
||||
msgstr "IP"
|
||||
|
||||
@@ -2282,9 +2357,6 @@ msgstr "Путь к ключу"
|
||||
msgid "Keyword must not contain spaces or commas"
|
||||
msgstr "Ключевое слово не должно содержать пробелов или запятых"
|
||||
|
||||
msgid "Knowledge Base + Live Probe Context"
|
||||
msgstr "База знаний + Контекст сетевого зонда"
|
||||
|
||||
msgid "LAN Devices"
|
||||
msgstr "Устройства LAN"
|
||||
|
||||
@@ -2492,6 +2564,12 @@ msgstr "Должен быть список числовых ID через зап
|
||||
msgid "Must be a number in the range of 0 - 10000"
|
||||
msgstr "Должно быть числом в диапазоне 0 - 10000"
|
||||
|
||||
msgid "My Strategies"
|
||||
msgstr ""
|
||||
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Name displayed on the dashboard"
|
||||
msgstr "Имя, отображаемое на дашборде"
|
||||
|
||||
@@ -2555,8 +2633,8 @@ msgstr "Активные устройства в локальной сети н
|
||||
msgid "No active routing sections found."
|
||||
msgstr "Активные секции маршрутизации не найдены."
|
||||
|
||||
msgid "No benchmark results yet. Select engine and click \"Start Benchmark\" or \"Synthesize with AI\"."
|
||||
msgstr "Нет результатов бенчмарка. Выберите движок и нажмите «Начать бенчмарк» или «Сгенерировать через ИИ»."
|
||||
msgid "No benchmark results yet. Configure options and click \"Start Benchmark\"."
|
||||
msgstr ""
|
||||
|
||||
msgid "No check targets found in the configuration."
|
||||
msgstr "Цели для проверки не найдены в конфигурации."
|
||||
@@ -2570,6 +2648,9 @@ msgstr "Конфликт не обнаружен"
|
||||
msgid "No Custom Rules Matched"
|
||||
msgstr "Нет совпадений с пользовательскими правилами"
|
||||
|
||||
msgid "No custom strategies added yet."
|
||||
msgstr ""
|
||||
|
||||
msgid "No DHCP clients detected"
|
||||
msgstr "DHCP-клиенты не обнаружены"
|
||||
|
||||
@@ -2612,6 +2693,9 @@ msgstr "Секции не выбраны"
|
||||
msgid "No snapshots yet"
|
||||
msgstr "Снапшотов пока нет"
|
||||
|
||||
msgid "No strategies match the active filter."
|
||||
msgstr ""
|
||||
|
||||
msgid "Node list is empty"
|
||||
msgstr "Список узлов пуст"
|
||||
|
||||
@@ -2723,6 +2807,9 @@ msgstr "Только серверы с одним из выбранных тра
|
||||
msgid "Only the specified servers."
|
||||
msgstr "Только указанные серверы."
|
||||
|
||||
msgid "OOB Values (-o)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open"
|
||||
msgstr "Открыть"
|
||||
|
||||
@@ -2768,12 +2855,12 @@ msgstr "Параметр \"%s\" содержит недопустимое зна
|
||||
msgid "Optional — leave empty for default"
|
||||
msgstr "Опционально — оставьте пустым для значения по умолчанию"
|
||||
|
||||
msgid "Optional context (e.g. \"Rostelecom, YouTube 4K buffering is slow\")..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Optional for local LLM"
|
||||
msgstr "Опционально для локальных LLM"
|
||||
|
||||
msgid "Optional notes for AI (e.g. \"Rostelecom, YouTube 4K stream is slow\")..."
|
||||
msgstr "Дополнительные заметки для ИИ (напр. «Ростелеком, тормозит 4K на YouTube»)..."
|
||||
|
||||
msgid "Optional tls-auth or tls-crypt key"
|
||||
msgstr "Опциональный ключ tls-auth или tls-crypt"
|
||||
|
||||
@@ -2837,6 +2924,21 @@ msgstr "Путь должен содержать как минимум одну
|
||||
msgid "Path must end with cache.db"
|
||||
msgstr "Путь должен заканчиваться на cache.db"
|
||||
|
||||
msgid "Pattern Builder"
|
||||
msgstr ""
|
||||
|
||||
msgid "Patterns reset to defaults!"
|
||||
msgstr ""
|
||||
|
||||
msgid "Patterns reset to factory defaults"
|
||||
msgstr ""
|
||||
|
||||
msgid "Patterns saved successfully"
|
||||
msgstr ""
|
||||
|
||||
msgid "Patterns saved successfully!"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pause updates"
|
||||
msgstr "Приостановить обновление"
|
||||
|
||||
@@ -2888,6 +2990,9 @@ msgstr "Закрепить на дашборде"
|
||||
msgid "Pin P2P isolation to the torrent client's own ports, comma separated. Each entry is \"proto\", \"proto:port\" or \"proto:port-port\" (tcp/udp). Without a port the whole protocol is routed direct."
|
||||
msgstr "Закрепить изоляцию P2P за портами торрент-клиента, через запятую. Каждая запись — \"протокол\", \"протокол:порт\" или \"протокол:порт-порт\" (tcp/udp). Без порта весь протокол уходит напрямую."
|
||||
|
||||
msgid "Please specify strategy name and arguments"
|
||||
msgstr ""
|
||||
|
||||
msgid "Polling Interval (seconds)"
|
||||
msgstr "Интервал опроса (секунды)"
|
||||
|
||||
@@ -3014,6 +3119,9 @@ msgstr "QR-код слишком большой"
|
||||
msgid "QUIC (HTTP/3)"
|
||||
msgstr "QUIC (HTTP/3)"
|
||||
|
||||
msgid "RAG Knowledge Base + Live ISP Probe Context"
|
||||
msgstr ""
|
||||
|
||||
msgid "RDP"
|
||||
msgstr "RDP"
|
||||
|
||||
@@ -3290,18 +3398,15 @@ msgstr "Запустить восстановление"
|
||||
msgid "Running"
|
||||
msgstr "Запущен"
|
||||
|
||||
msgid "Running benchmarks..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Running diagnostics…"
|
||||
msgstr "Выполняется диагностика…"
|
||||
|
||||
msgid "Running initial strategy probe..."
|
||||
msgstr "Запуск первого зонда стратегии..."
|
||||
|
||||
msgid "Russia (ru)"
|
||||
msgstr "Россия (ru)"
|
||||
|
||||
msgid "RuTracker (HTTP/HTTPS)"
|
||||
msgstr "RuTracker (HTTP/HTTPS)"
|
||||
|
||||
msgid "Sat"
|
||||
msgstr "Сб"
|
||||
|
||||
@@ -3365,8 +3470,8 @@ msgstr "Действие секции"
|
||||
msgid "Section name"
|
||||
msgstr "Имя секции"
|
||||
|
||||
msgid "Section name for WARP registration proxy. Leave empty to use the default service mixed proxy."
|
||||
msgstr "Секция для прокси регистрации WARP. Оставьте пустым для использования сервисного смешанного прокси по умолчанию."
|
||||
msgid "Section or tunnel interface used for Cloudflare WARP API registration. Supports Connection, WireGuard, AmneziaWG, and Interface sections. Leave empty to use direct WAN / default mixed proxy."
|
||||
msgstr ""
|
||||
|
||||
msgid "Section Rules Content"
|
||||
msgstr "Содержимое правил секции"
|
||||
@@ -3503,6 +3608,9 @@ msgstr "Отправлять уведомление в Telegram при пере
|
||||
msgid "Send a Telegram notification when proxy subscriptions are successfully updated."
|
||||
msgstr "Отправлять уведомление в Telegram при успешном обновлении подписок прокси."
|
||||
|
||||
msgid "Sequence Overlaps (seqovl)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Server"
|
||||
msgstr "Сервер"
|
||||
|
||||
@@ -3722,6 +3830,18 @@ msgstr "Укажите разные файлы"
|
||||
msgid "Speed"
|
||||
msgstr "Скорость"
|
||||
|
||||
msgid "Split Modes (dpi-desync)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Split Positions (dpi-desync-split-pos)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Split Positions (pos)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Split Values (-s)"
|
||||
msgstr ""
|
||||
|
||||
msgid "SSH"
|
||||
msgstr "SSH"
|
||||
|
||||
@@ -3788,6 +3908,9 @@ msgstr ""
|
||||
msgid "Status"
|
||||
msgstr "Статус"
|
||||
|
||||
msgid "Status / Suite"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stop"
|
||||
msgstr "Стоп"
|
||||
|
||||
@@ -3815,6 +3938,12 @@ msgstr "Стратегия и параметры"
|
||||
msgid "Strategy benchmark started"
|
||||
msgstr "Бенчмарк стратегий запущен"
|
||||
|
||||
msgid "Strategy deleted"
|
||||
msgstr ""
|
||||
|
||||
msgid "Strategy Name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Strict ECH + DoQ DNS Enforcer"
|
||||
msgstr "Строгий ECH + DoQ DNS Enforcer"
|
||||
|
||||
@@ -3965,8 +4094,11 @@ msgstr "Целевые устройства (IP / MAC)"
|
||||
msgid "Target Scope"
|
||||
msgstr "Область действия"
|
||||
|
||||
msgid "Target Service"
|
||||
msgstr "Целевой сервис"
|
||||
msgid "Target Service / Suite"
|
||||
msgstr ""
|
||||
|
||||
msgid "TCP Window Sizes (wsize)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Telegram Bot"
|
||||
msgstr "Telegram Бот"
|
||||
@@ -3977,9 +4109,6 @@ msgstr "Токен Telegram-бота"
|
||||
msgid "Telegram Channel"
|
||||
msgstr "Telegram канал"
|
||||
|
||||
msgid "Telegram Web"
|
||||
msgstr "Telegram Web"
|
||||
|
||||
msgid "Test Connection"
|
||||
msgstr "Проверить подключение"
|
||||
|
||||
@@ -4106,6 +4235,9 @@ msgstr "Ключ TLS Auth/Crypt"
|
||||
msgid "TLS SNI"
|
||||
msgstr "TLS SNI"
|
||||
|
||||
msgid "TLS-Rec Bounds (--tlsrec)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Token is required when the bot is enabled"
|
||||
msgstr "Токен обязателен, когда бот включён"
|
||||
|
||||
@@ -4187,6 +4319,12 @@ msgstr "TTL должен быть положительным числом"
|
||||
msgid "TTL value cannot be empty"
|
||||
msgstr "Значение TTL не может быть пустым"
|
||||
|
||||
msgid "TTL Values (dpi-desync-ttl)"
|
||||
msgstr ""
|
||||
|
||||
msgid "TTL Values (ttl)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tue"
|
||||
msgstr "Вт"
|
||||
|
||||
@@ -4421,6 +4559,9 @@ msgstr "Использовать exit-node тейлнета для LAN"
|
||||
msgid "Used by"
|
||||
msgstr "Используется"
|
||||
|
||||
msgid "User custom strategy"
|
||||
msgstr ""
|
||||
|
||||
msgid "User-Agent"
|
||||
msgstr "User-Agent"
|
||||
|
||||
@@ -4550,12 +4691,6 @@ msgstr "Да"
|
||||
msgid "You can select Output Network Interface, by default autodetect"
|
||||
msgstr "Вы можете выбрать выходной сетевой интерфейс, по умолчанию автоопределение"
|
||||
|
||||
msgid "YouTube (GoogleVideo 4K stream)"
|
||||
msgstr "YouTube (4K видеопоток GoogleVideo)"
|
||||
|
||||
msgid "YouTube Web (Interface)"
|
||||
msgstr "YouTube Web (Интерфейс)"
|
||||
|
||||
msgid "Zapret hostlist templates are not supported here because Tachyon does not expand them for per-rule NFQWS strategies."
|
||||
msgstr "Шаблоны hostlist Zapret не поддерживаются здесь, потому что Tachyon не расширяет их для стратегий NFQWS по правилам."
|
||||
|
||||
@@ -4604,6 +4739,66 @@ msgstr "sing-box outbound для Zapret2 настроен"
|
||||
msgid "Zapret2 sing-box outbound is not configured"
|
||||
msgstr "sing-box outbound для Zapret2 не настроен"
|
||||
|
||||
msgid "🏆 Apply Best Strategy"
|
||||
msgstr "🏆 Применить лучшую стратегию"
|
||||
|
||||
msgid "🔍 Combinatorial Deep Fuzzing (~40-60)"
|
||||
msgstr "🔍 Комбинаторный глубокий перебор (~40-60)"
|
||||
|
||||
msgid "🚀 Run Benchmark Again"
|
||||
msgstr "🚀 Запустить бенчмарк снова"
|
||||
|
||||
msgid "AI DPI Engineer & Strategy Synthesizer (RAG-Powered)"
|
||||
msgstr "ИИ-инженер DPI и генератор стратегий (на базе RAG)"
|
||||
|
||||
msgid "Automated DPI Strategy Fuzzer & Auto-Tuner"
|
||||
msgstr "Автоматический подборщик и оптимизатор стратегий DPI"
|
||||
|
||||
msgid "Benchmarks a suite of packet desynchronization strategies in an isolated sandbox without disrupting active traffic, ranking them by latency, TTFB, and throughput."
|
||||
msgstr "Тестирует набор стратегий десинхронизации пакетов в изолированном сэндбоксе без влияния на активный трафик и ранжирует их по задержке, TTFB и скорости."
|
||||
|
||||
msgid "Custom Target URL..."
|
||||
msgstr "Свой URL для теста..."
|
||||
|
||||
msgid "default (service mixed proxy)"
|
||||
msgstr "по умолчанию (сервисный смешанный прокси)"
|
||||
|
||||
msgid "Discord (Gateway / API / Voice)"
|
||||
msgstr "Discord (Шлюз / API / Голосовые каналы)"
|
||||
|
||||
msgid "Instagram / Meta (TLS 1.3)"
|
||||
msgstr "Instagram / Meta (TLS 1.3)"
|
||||
|
||||
msgid "Knowledge Base + Live Probe Context"
|
||||
msgstr "База знаний + Контекст сетевого зонда"
|
||||
|
||||
msgid "No benchmark results yet. Select engine and click \"Start Benchmark\" or \"Synthesize with AI\"."
|
||||
msgstr "Нет результатов бенчмарка. Выберите движок и нажмите «Начать бенчмарк» или «Сгенерировать через ИИ»."
|
||||
|
||||
msgid "Optional notes for AI (e.g. \"Rostelecom, YouTube 4K stream is slow\")..."
|
||||
msgstr "Дополнительные заметки для ИИ (напр. «Ростелеком, тормозит 4K на YouTube»)..."
|
||||
|
||||
msgid "Running initial strategy probe..."
|
||||
msgstr "Запуск первого зонда стратегии..."
|
||||
|
||||
msgid "RuTracker (HTTP/HTTPS)"
|
||||
msgstr "RuTracker (HTTP/HTTPS)"
|
||||
|
||||
msgid "Section name for WARP registration proxy. Leave empty to use the default service mixed proxy."
|
||||
msgstr "Секция для прокси регистрации WARP. Оставьте пустым для использования сервисного смешанного прокси по умолчанию."
|
||||
|
||||
msgid "Target Service"
|
||||
msgstr "Целевой сервис"
|
||||
|
||||
msgid "Telegram Web"
|
||||
msgstr "Telegram Web"
|
||||
|
||||
msgid "YouTube (GoogleVideo 4K stream)"
|
||||
msgstr "YouTube (4K видеопоток GoogleVideo)"
|
||||
|
||||
msgid "YouTube Web (Interface)"
|
||||
msgstr "YouTube Web (Интерфейс)"
|
||||
|
||||
msgid "No benchmark results yet. Select engine and click \"Start Benchmark\"."
|
||||
msgstr "Нет результатов бенчмарка. Выберите движок и нажмите «Начать бенчмарк»."
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -265,6 +265,9 @@ function command_spec(command) {
|
||||
fuzzer_strategies: [ "diagnostics/fuzzer.uc", "strategies", 1 ],
|
||||
fuzzer_generate: [ "diagnostics/fuzzer.uc", "generate", 2 ],
|
||||
fuzzer_ai_synthesize: [ "diagnostics/fuzzer.uc", "ai_synthesize", 4 ],
|
||||
fuzzer_get_patterns: [ "diagnostics/fuzzer.uc", "get_patterns", 0 ],
|
||||
fuzzer_save_patterns: [ "diagnostics/fuzzer.uc", "save_patterns", 1 ],
|
||||
fuzzer_reset_patterns: [ "diagnostics/fuzzer.uc", "reset_patterns", 0 ],
|
||||
generate_warp: [ "service/warp_generator.uc", "", 1 ],
|
||||
package_prerm: [ "service/package.uc", "prerm", 1 ],
|
||||
package_postinst: [ "service/package.uc", "postinst", 0 ],
|
||||
|
||||
@@ -84,14 +84,117 @@ function validate_strategy_args(engine, args_val) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Target definitions
|
||||
const PATTERNS_FILE = "/etc/tachyon/fuzzer_patterns.json";
|
||||
|
||||
const DEFAULT_PATTERNS = {
|
||||
zapret2: {
|
||||
splits: [ "1", "2", "3", "midsld", "sniext+4", "1,midsld", "1,sniext+2" ],
|
||||
foolings: [ "badseq", "md5sig", "badack", "datanoack", "fakeddrop" ],
|
||||
ttls: [ 2, 3, 4, 5, 6, 8 ],
|
||||
seqovls: [ "1", "2" ],
|
||||
wsizes: [ "1" ],
|
||||
payloads: [ "tls_client_hello", "http_req", "quic_initial" ]
|
||||
},
|
||||
zapret: {
|
||||
splits: [ "1", "2", "midsld", "sniext+4", "1,midsld" ],
|
||||
foolings: [ "badseq", "md5sig", "badack", "datanoack" ],
|
||||
ttls: [ 2, 3, 4, 6, 8 ],
|
||||
split_modes: [ "split2", "disorder2", "fake,split2", "fake,disorder2" ]
|
||||
},
|
||||
byedpi: {
|
||||
splits: [ "1", "2", "1+sniext", "midsld" ],
|
||||
disorders: [ "1", "2" ],
|
||||
ttls: [ 2, 3, 4, 6, 8 ],
|
||||
oobs: [ "1", "2" ],
|
||||
autos: [ "t,r,a,s", "r,s", "t,a" ],
|
||||
tlsrecs: [ "1+sniext" ],
|
||||
ipfrags: [ "24" ]
|
||||
},
|
||||
custom_strategies: []
|
||||
};
|
||||
|
||||
function get_patterns_config() {
|
||||
let custom = read_json_file(PATTERNS_FILE);
|
||||
if (custom && type(custom) == "object") {
|
||||
return {
|
||||
zapret2: custom.zapret2 || DEFAULT_PATTERNS.zapret2,
|
||||
zapret: custom.zapret || DEFAULT_PATTERNS.zapret,
|
||||
byedpi: custom.byedpi || DEFAULT_PATTERNS.byedpi,
|
||||
custom_strategies: custom.custom_strategies || []
|
||||
};
|
||||
}
|
||||
return DEFAULT_PATTERNS;
|
||||
}
|
||||
|
||||
function save_patterns_config(cfg_obj) {
|
||||
if (!cfg_obj || type(cfg_obj) != "object") {
|
||||
print(sprintf("%J\n", { success: false, error: "Invalid patterns configuration object" }));
|
||||
return;
|
||||
}
|
||||
common.ensure_dir("/etc/tachyon");
|
||||
write_json_file(PATTERNS_FILE, cfg_obj);
|
||||
print(sprintf("%J\n", { success: true, message: "Patterns configuration saved successfully" }));
|
||||
}
|
||||
|
||||
function reset_patterns_config() {
|
||||
try { fs.unlink(PATTERNS_FILE); } catch(e) {}
|
||||
print(sprintf("%J\n", { success: true, message: "Patterns configuration reset to factory defaults", patterns: DEFAULT_PATTERNS }));
|
||||
}
|
||||
|
||||
// Target Suites & Definitions
|
||||
const TARGET_SUITES = {
|
||||
youtube_suite: {
|
||||
name: "YouTube Full Suite (Web + Static CDN + 4K Stream)",
|
||||
urls: [
|
||||
{ name: "Web Interface", url: "https://www.youtube.com", weight: 30 },
|
||||
{ name: "Static Assets (i.ytimg)", url: "https://i.ytimg.com/generate_204", weight: 20 },
|
||||
{ name: "GoogleVideo Stream Chunk", url: "https://rr1---sn-4g5ednss.googlevideo.com/generate_204", weight: 50 }
|
||||
]
|
||||
},
|
||||
discord_suite: {
|
||||
name: "Discord Full Suite (API + WSS Gateway + CDN)",
|
||||
urls: [
|
||||
{ name: "API Gateway", url: "https://discord.com/api/v9/gateway", weight: 40 },
|
||||
{ name: "Media Attachments CDN", url: "https://media.discordapp.net/", weight: 30 },
|
||||
{ name: "Global Assets CDN", url: "https://cdn.discordapp.com/generate_204", weight: 30 }
|
||||
]
|
||||
},
|
||||
instagram_suite: {
|
||||
name: "Instagram / Meta Suite (Web + Static CDN)",
|
||||
urls: [
|
||||
{ name: "Web Interface", url: "https://www.instagram.com", weight: 50 },
|
||||
{ name: "CDN Static Assets", url: "https://static.cdninstagram.com/rsrc.php/v3/y4/r/dukNmT7A9dd.webp", weight: 50 }
|
||||
]
|
||||
},
|
||||
telegram_suite: {
|
||||
name: "Telegram Suite (Web + API)",
|
||||
urls: [
|
||||
{ name: "Web App", url: "https://web.telegram.org", weight: 50 },
|
||||
{ name: "Bot API", url: "https://api.telegram.org", weight: 50 }
|
||||
]
|
||||
},
|
||||
rutracker_suite: {
|
||||
name: "RuTracker Suite (HTTP / HTTPS)",
|
||||
urls: [
|
||||
{ name: "Main Portal", url: "https://rutracker.org", weight: 60 },
|
||||
{ name: "CDN Static Logo", url: "https://static.rutracker.cc/logo/logo-3.png", weight: 40 }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const TARGET_URLS = {
|
||||
youtube_suite: "https://www.youtube.com",
|
||||
youtube: "https://www.youtube.com",
|
||||
youtube_web: "https://www.youtube.com",
|
||||
discord_suite: "https://discord.com/api/v9/gateway",
|
||||
discord: "https://discord.com/api/v9/gateway",
|
||||
instagram_suite: "https://www.instagram.com",
|
||||
instagram: "https://www.instagram.com",
|
||||
rutracker_suite: "https://rutracker.org",
|
||||
rutracker: "https://rutracker.org",
|
||||
telegram: "https://web.telegram.org"
|
||||
telegram_suite: "https://web.telegram.org",
|
||||
telegram: "https://web.telegram.org",
|
||||
quic_http3: "https://www.google.com"
|
||||
};
|
||||
|
||||
// Strategy Matrices (Expanded Production Suite: 38 strategies across engines)
|
||||
@@ -385,6 +488,8 @@ const STRATEGIES_BYEDPI = [
|
||||
];
|
||||
|
||||
function generate_combinatorial_zapret2() {
|
||||
let cfg = get_patterns_config();
|
||||
let p = cfg.zapret2 || DEFAULT_PATTERNS.zapret2;
|
||||
let list = [];
|
||||
let seen = {};
|
||||
|
||||
@@ -394,7 +499,7 @@ function generate_combinatorial_zapret2() {
|
||||
if (!validate_strategy_args("zapret2", args)) return;
|
||||
seen[args] = true;
|
||||
push(list, {
|
||||
id: sprintf("z2_gen_%d", length(list) + 1),
|
||||
id: sprintf("z2_comb_%d", length(list) + 1),
|
||||
name: name,
|
||||
engine: "zapret2",
|
||||
args: args,
|
||||
@@ -404,24 +509,41 @@ function generate_combinatorial_zapret2() {
|
||||
|
||||
for (let s in STRATEGIES_ZAPRET2) add(s.name, s.args, s.description);
|
||||
|
||||
let positions = ["1", "midsld", "sniext+4", "1,midsld", "1,sniext+2"];
|
||||
let foolings = ["badseq", "md5sig", "badack"];
|
||||
let ttls = [3, 4, 5, 8];
|
||||
if (cfg.custom_strategies && length(cfg.custom_strategies) > 0) {
|
||||
for (let cs in cfg.custom_strategies) {
|
||||
if (cs && cs.engine == "zapret2" && cs.args) {
|
||||
add(cs.name || "Custom Zapret v2", cs.args, cs.description || "User custom strategy");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let pos in positions) {
|
||||
let splits = p.splits || [ "1", "2", "3", "midsld", "sniext+4", "1,midsld", "1,sniext+2" ];
|
||||
let foolings = p.foolings || [ "badseq", "md5sig", "badack", "datanoack", "fakeddrop" ];
|
||||
let ttls = p.ttls || [ 2, 3, 4, 5, 6, 8 ];
|
||||
let seqovls = p.seqovls || [ "1", "2" ];
|
||||
let wsizes = p.wsizes || [ "1" ];
|
||||
|
||||
for (let pos in splits) {
|
||||
for (let fooling in foolings) {
|
||||
add(sprintf("Multisplit (pos=%s, %s)", pos, fooling),
|
||||
sprintf("--lua-desync=multisplit:pos=%s:fooling=%s", pos, fooling),
|
||||
"Multisplit position and fooling method");
|
||||
add(sprintf("Multisplit + SeqOvl (pos=%s, %s)", pos, fooling),
|
||||
sprintf("--lua-desync=multisplit:pos=%s:seqovl=1:fooling=%s", pos, fooling),
|
||||
"Multisplit with sequence overlap");
|
||||
for (let sq in seqovls) {
|
||||
add(sprintf("Multisplit + SeqOvl %s (pos=%s, %s)", sq, pos, fooling),
|
||||
sprintf("--lua-desync=multisplit:pos=%s:seqovl=%s:fooling=%s", pos, sq, fooling),
|
||||
"Multisplit with sequence overlap");
|
||||
}
|
||||
for (let w in wsizes) {
|
||||
add(sprintf("Multisplit + Window %s (pos=%s, %s)", w, pos, fooling),
|
||||
sprintf("--lua-desync=multisplit:pos=%s:wsize=%s:fooling=%s", pos, w, fooling),
|
||||
"Multisplit with TCP window size clamping");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let ttl in ttls) {
|
||||
for (let fooling in ["badseq", "md5sig", "badack"]) {
|
||||
for (let pos in ["1", "midsld", "1,midsld"]) {
|
||||
for (let fooling in foolings) {
|
||||
for (let pos in splits) {
|
||||
add(sprintf("Fake (TTL=%d, %s) + Multisplit (pos=%s)", ttl, fooling, pos),
|
||||
sprintf("--lua-desync=fake:ttl=%d:fooling=%s --lua-desync=multisplit:pos=%s", ttl, fooling, pos),
|
||||
"Low-TTL fake injection followed by multisplit payload");
|
||||
@@ -436,6 +558,8 @@ function generate_combinatorial_zapret2() {
|
||||
}
|
||||
|
||||
function generate_combinatorial_zapret() {
|
||||
let cfg = get_patterns_config();
|
||||
let p = cfg.zapret || DEFAULT_PATTERNS.zapret;
|
||||
let list = [];
|
||||
let seen = {};
|
||||
|
||||
@@ -455,10 +579,18 @@ function generate_combinatorial_zapret() {
|
||||
|
||||
for (let s in STRATEGIES_ZAPRET) add(s.name, s.args, s.description);
|
||||
|
||||
let modes = ["split2", "disorder2", "fake,split2", "fake,disorder2"];
|
||||
let positions = ["1", "2", "midsld"];
|
||||
let foolings = ["badseq", "md5sig", "badack"];
|
||||
let ttls = [4, 6, 8];
|
||||
if (cfg.custom_strategies && length(cfg.custom_strategies) > 0) {
|
||||
for (let cs in cfg.custom_strategies) {
|
||||
if (cs && cs.engine == "zapret" && cs.args) {
|
||||
add(cs.name || "Custom Zapret v1", cs.args, cs.description || "User custom strategy");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let modes = p.split_modes || [ "split2", "disorder2", "fake,split2", "fake,disorder2" ];
|
||||
let positions = p.splits || [ "1", "2", "midsld" ];
|
||||
let foolings = p.foolings || [ "badseq", "md5sig", "badack", "datanoack" ];
|
||||
let ttls = p.ttls || [ 2, 3, 4, 6, 8 ];
|
||||
|
||||
for (let mode in modes) {
|
||||
for (let pos in positions) {
|
||||
@@ -485,6 +617,8 @@ function generate_combinatorial_zapret() {
|
||||
}
|
||||
|
||||
function generate_combinatorial_byedpi() {
|
||||
let cfg = get_patterns_config();
|
||||
let p = cfg.byedpi || DEFAULT_PATTERNS.byedpi;
|
||||
let list = [];
|
||||
let seen = {};
|
||||
|
||||
@@ -504,11 +638,21 @@ function generate_combinatorial_byedpi() {
|
||||
|
||||
for (let s in STRATEGIES_BYEDPI) add(s.name, s.args, s.description);
|
||||
|
||||
let splits = ["1", "2", "1+sniext", "midsld"];
|
||||
let disorders = ["1", "2"];
|
||||
let ttls = [3, 4, 6, 8];
|
||||
let oobs = ["1", "2"];
|
||||
let autos = ["t,r,a,s", "r,s", "t,a"];
|
||||
if (cfg.custom_strategies && length(cfg.custom_strategies) > 0) {
|
||||
for (let cs in cfg.custom_strategies) {
|
||||
if (cs && cs.engine == "byedpi" && cs.args) {
|
||||
add(cs.name || "Custom ByeDPI", cs.args, cs.description || "User custom strategy");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let splits = p.splits || [ "1", "2", "1+sniext", "midsld" ];
|
||||
let disorders = p.disorders || [ "1", "2" ];
|
||||
let ttls = p.ttls || [ 2, 3, 4, 6, 8 ];
|
||||
let oobs = p.oobs || [ "1", "2" ];
|
||||
let autos = p.autos || [ "t,r,a,s", "r,s", "t,a" ];
|
||||
let tlsrecs = p.tlsrecs || [ "1+sniext" ];
|
||||
let ipfrags = p.ipfrags || [ "24" ];
|
||||
|
||||
for (let a in autos) {
|
||||
for (let o in oobs) {
|
||||
@@ -536,12 +680,16 @@ function generate_combinatorial_byedpi() {
|
||||
}
|
||||
|
||||
for (let s in splits) {
|
||||
add(sprintf("TLS-Rec (1+sniext) + Split=%s", s),
|
||||
sprintf("--tlsrec 1+sniext --split %s", s),
|
||||
"TLS record boundary fragmentation");
|
||||
add(sprintf("IP-Frag (24) + Split=%s", s),
|
||||
sprintf("--ip-frag 24 --split %s", s),
|
||||
"IP packet fragmentation");
|
||||
for (let tr in tlsrecs) {
|
||||
add(sprintf("TLS-Rec (%s) + Split=%s", tr, s),
|
||||
sprintf("--tlsrec %s --split %s", tr, s),
|
||||
"TLS record boundary fragmentation");
|
||||
}
|
||||
for (let ipf in ipfrags) {
|
||||
add(sprintf("IP-Frag (%s) + Split=%s", ipf, s),
|
||||
sprintf("--ip-frag %s --split %s", ipf, s),
|
||||
"IP packet fragmentation");
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
@@ -550,17 +698,62 @@ function generate_combinatorial_byedpi() {
|
||||
function get_strategies_for_engine(engine, mode) {
|
||||
engine = lc(as_string(engine));
|
||||
mode = lc(trim(as_string(mode || "presets")));
|
||||
let cfg = get_patterns_config();
|
||||
|
||||
if (mode == "custom" || mode == "user") {
|
||||
let custom_list = [];
|
||||
for (let cs in cfg.custom_strategies) {
|
||||
if (cs && (engine == "all" || cs.engine == engine) && cs.args) {
|
||||
push(custom_list, {
|
||||
id: cs.id || sprintf("custom_%d", length(custom_list) + 1),
|
||||
name: cs.name || "Custom Strategy",
|
||||
engine: cs.engine || engine,
|
||||
args: cs.args,
|
||||
description: cs.description || ""
|
||||
});
|
||||
}
|
||||
}
|
||||
return custom_list;
|
||||
}
|
||||
|
||||
if (mode == "combinatorial" || mode == "deep_fuzz" || mode == "deep") {
|
||||
if (engine == "zapret2") return generate_combinatorial_zapret2();
|
||||
if (engine == "zapret") return generate_combinatorial_zapret();
|
||||
if (engine == "byedpi") return generate_combinatorial_byedpi();
|
||||
if (engine == "all") {
|
||||
let combined = [];
|
||||
for (let s in generate_combinatorial_zapret2()) push(combined, s);
|
||||
for (let s in generate_combinatorial_zapret()) push(combined, s);
|
||||
for (let s in generate_combinatorial_byedpi()) push(combined, s);
|
||||
return combined;
|
||||
}
|
||||
}
|
||||
|
||||
if (engine == "zapret2") return STRATEGIES_ZAPRET2;
|
||||
if (engine == "zapret") return STRATEGIES_ZAPRET;
|
||||
if (engine == "byedpi") return STRATEGIES_BYEDPI;
|
||||
return [];
|
||||
let base = [];
|
||||
if (engine == "zapret2") base = STRATEGIES_ZAPRET2;
|
||||
else if (engine == "zapret") base = STRATEGIES_ZAPRET;
|
||||
else if (engine == "byedpi") base = STRATEGIES_BYEDPI;
|
||||
else if (engine == "all") {
|
||||
for (let s in STRATEGIES_ZAPRET2) push(base, s);
|
||||
for (let s in STRATEGIES_ZAPRET) push(base, s);
|
||||
for (let s in STRATEGIES_BYEDPI) push(base, s);
|
||||
}
|
||||
|
||||
let result = [];
|
||||
for (let s in base) push(result, s);
|
||||
for (let cs in cfg.custom_strategies) {
|
||||
if (cs && (engine == "all" || cs.engine == engine) && cs.args) {
|
||||
push(result, {
|
||||
id: cs.id || sprintf("custom_%d", length(result) + 1),
|
||||
name: cs.name || "Custom Strategy",
|
||||
engine: cs.engine || engine,
|
||||
args: cs.args,
|
||||
description: cs.description || "User custom strategy"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function resolve_target_url(target_key, custom_url) {
|
||||
@@ -569,6 +762,19 @@ function resolve_target_url(target_key, custom_url) {
|
||||
return TARGET_URLS[target_key] || TARGET_URLS.youtube;
|
||||
}
|
||||
|
||||
function resolve_target_urls_list(target_key, custom_url) {
|
||||
if (custom_url && custom_url != "") {
|
||||
return [ { name: "Custom Target", url: custom_url, weight: 100 } ];
|
||||
}
|
||||
target_key = as_string(target_key || "youtube_suite");
|
||||
let suite = TARGET_SUITES[target_key];
|
||||
if (suite && suite.urls && length(suite.urls) > 0) {
|
||||
return suite.urls;
|
||||
}
|
||||
let single = TARGET_URLS[target_key] || TARGET_URLS.youtube;
|
||||
return [ { name: target_key, url: single, weight: 100 } ];
|
||||
}
|
||||
|
||||
function ensure_state_dir() {
|
||||
common.ensure_dir(STATE_DIR);
|
||||
}
|
||||
@@ -578,6 +784,17 @@ function save_fuzzer_state(state) {
|
||||
common.write_json_file(STATE_FILE, state);
|
||||
}
|
||||
|
||||
function safe_json_parse(str) {
|
||||
if (!str || str == "") return null;
|
||||
let obj = null;
|
||||
try {
|
||||
obj = json(str);
|
||||
} catch (e) {
|
||||
obj = null;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function query_llm(provider, api_key, custom_url, prompt_text, model_override) {
|
||||
provider = lc(trim(as_string(provider || "openai")));
|
||||
model_override = trim(as_string(model_override || ""));
|
||||
@@ -599,7 +816,7 @@ function query_llm(provider, api_key, custom_url, prompt_text, model_override) {
|
||||
let pipe = fs.popen(cmd, "r");
|
||||
let output = pipe ? pipe.read("all") : "";
|
||||
if (pipe) pipe.close();
|
||||
let parsed = common.json_parse(output);
|
||||
let parsed = safe_json_parse(output);
|
||||
if (parsed && parsed.content && type(parsed.content) == "array" && length(parsed.content) > 0) {
|
||||
return parsed.content[0].text;
|
||||
}
|
||||
@@ -644,7 +861,7 @@ function query_llm(provider, api_key, custom_url, prompt_text, model_override) {
|
||||
let pipe = fs.popen(cmd, "r");
|
||||
let output = pipe ? pipe.read("all") : "";
|
||||
if (pipe) pipe.close();
|
||||
let parsed = common.json_parse(output);
|
||||
let parsed = safe_json_parse(output);
|
||||
if (parsed && parsed.choices && type(parsed.choices) == "array" && length(parsed.choices) > 0) {
|
||||
let msg = parsed.choices[0].message;
|
||||
if (msg && msg.content) {
|
||||
@@ -657,18 +874,18 @@ function query_llm(provider, api_key, custom_url, prompt_text, model_override) {
|
||||
function parse_llm_json(raw_text) {
|
||||
raw_text = trim(as_string(raw_text));
|
||||
if (raw_text == "") return null;
|
||||
let direct = common.json_parse(raw_text);
|
||||
let direct = safe_json_parse(raw_text);
|
||||
if (direct && type(direct) == "object") return direct;
|
||||
|
||||
let m = match(raw_text, /```json\s*([\s\S]*?)\s*```/);
|
||||
if (m && m[1]) {
|
||||
let parsed = common.json_parse(m[1]);
|
||||
let parsed = safe_json_parse(m[1]);
|
||||
if (parsed && type(parsed) == "object") return parsed;
|
||||
}
|
||||
|
||||
m = match(raw_text, /\{[\s\S]*\}/);
|
||||
if (m && m[0]) {
|
||||
let parsed = common.json_parse(m[0]);
|
||||
let parsed = safe_json_parse(m[0]);
|
||||
if (parsed && type(parsed) == "object") return parsed;
|
||||
}
|
||||
return null;
|
||||
@@ -682,11 +899,11 @@ function synthesize_ai_strategies(engine, target, custom_url, user_prompt) {
|
||||
}
|
||||
|
||||
engine = lc(as_string(engine || "zapret2"));
|
||||
target = trim(as_string(target || "youtube"));
|
||||
target = trim(as_string(target || "youtube_suite"));
|
||||
user_prompt = trim(as_string(user_prompt || ""));
|
||||
let target_url = resolve_target_url(target, custom_url);
|
||||
|
||||
let baseline = run_probe(engine, "", target_url);
|
||||
let baseline = run_probe(engine, "", target, custom_url);
|
||||
|
||||
let query_text = sprintf("%s %s %s", engine, target, user_prompt);
|
||||
let rag_docs = rag.retrieve(query_text, 4);
|
||||
@@ -800,7 +1017,7 @@ function get_fuzzer_state() {
|
||||
running: false,
|
||||
job_id: null,
|
||||
engine: "zapret2",
|
||||
target: "youtube",
|
||||
target: "youtube_suite",
|
||||
progress_pct: 0,
|
||||
current_index: 0,
|
||||
total_strategies: 0,
|
||||
@@ -834,14 +1051,24 @@ function cleanup_temp_daemons() {
|
||||
}
|
||||
|
||||
function parse_curl_output(output, result) {
|
||||
result = result || {};
|
||||
output = trim(as_string(output));
|
||||
if (output == "") {
|
||||
result.success = false;
|
||||
result.http_code = 0;
|
||||
result.handshake_ms = 0;
|
||||
result.ttfb_ms = 0;
|
||||
result.speed_kbps = 0;
|
||||
result.score = 0;
|
||||
result.error = "Probe timeout or connection refused";
|
||||
return result;
|
||||
}
|
||||
|
||||
let parts = split(output, "\t");
|
||||
if (length(parts) < 4) {
|
||||
result.success = false;
|
||||
result.http_code = 0;
|
||||
result.score = 0;
|
||||
result.error = "Malformed probe metrics output";
|
||||
return result;
|
||||
}
|
||||
@@ -862,6 +1089,7 @@ function parse_curl_output(output, result) {
|
||||
let latency_score = max(0, 1000 - result.ttfb_ms);
|
||||
let speed_score = int(result.speed_kbps / 10.0);
|
||||
result.score = base_score + latency_score + speed_score;
|
||||
result.error = "";
|
||||
} else {
|
||||
result.success = false;
|
||||
result.score = 0;
|
||||
@@ -871,9 +1099,12 @@ function parse_curl_output(output, result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function run_probe(engine, args_str, target_url) {
|
||||
function run_probe(engine, args_str, target_key, custom_url) {
|
||||
cleanup_temp_daemons();
|
||||
|
||||
let urls_list = resolve_target_urls_list(target_key, custom_url);
|
||||
let total_urls = length(urls_list);
|
||||
|
||||
let result = {
|
||||
success: false,
|
||||
http_code: 0,
|
||||
@@ -881,10 +1112,12 @@ function run_probe(engine, args_str, target_url) {
|
||||
ttfb_ms: 0,
|
||||
speed_kbps: 0,
|
||||
score: 0,
|
||||
error: ""
|
||||
error: "",
|
||||
sub_probes: []
|
||||
};
|
||||
|
||||
engine = lc(as_string(engine));
|
||||
let is_udp = index(args_str, "--filter-udp") >= 0 || index(args_str, "--dpi-desync-any-protocol") >= 0 || target_key == "quic_http3";
|
||||
|
||||
if (engine == "byedpi") {
|
||||
let bin = get_byedpi_bin();
|
||||
@@ -898,19 +1131,55 @@ function run_probe(engine, args_str, target_url) {
|
||||
system(common.background_command_with_pid(spawn_cmd, ">/dev/null", ">" + shell_quote(pid_path)));
|
||||
system("sleep 0.15");
|
||||
|
||||
let curl_cmd = sprintf(
|
||||
"curl -x socks5h://127.0.0.1:%d -so /dev/null -w '%%{http_code}\\t%%{time_appconnect}\\t%%{time_starttransfer}\\t%%{speed_download}' -L --connect-timeout 3 --max-time 4 %s 2>/dev/null",
|
||||
BYEDPI_PORT,
|
||||
shell_quote(target_url)
|
||||
);
|
||||
let passed_count = 0;
|
||||
let sum_handshake = 0;
|
||||
let sum_ttfb = 0;
|
||||
let max_speed = 0;
|
||||
let last_http = 0;
|
||||
|
||||
let pipe = fs.popen(curl_cmd, "r");
|
||||
let output = pipe ? pipe.read("all") : "";
|
||||
if (pipe) pipe.close();
|
||||
for (let target_item in urls_list) {
|
||||
let curl_cmd = sprintf(
|
||||
"curl -x socks5h://127.0.0.1:%d -so /dev/null -w '%%{http_code}\\t%%{time_appconnect}\\t%%{time_starttransfer}\\t%%{speed_download}' -L --connect-timeout 3 --max-time 4 %s 2>/dev/null",
|
||||
BYEDPI_PORT,
|
||||
shell_quote(target_item.url)
|
||||
);
|
||||
let pipe = fs.popen(curl_cmd, "r");
|
||||
let output = pipe ? pipe.read("all") : "";
|
||||
if (pipe) pipe.close();
|
||||
|
||||
let single_res = parse_curl_output(output, {});
|
||||
single_res.target_name = target_item.name;
|
||||
single_res.url = target_item.url;
|
||||
push(result.sub_probes, single_res);
|
||||
|
||||
if (single_res.success) {
|
||||
passed_count++;
|
||||
sum_handshake += single_res.handshake_ms;
|
||||
sum_ttfb += single_res.ttfb_ms;
|
||||
if (single_res.speed_kbps > max_speed) max_speed = single_res.speed_kbps;
|
||||
last_http = single_res.http_code;
|
||||
} else if (last_http == 0) {
|
||||
last_http = single_res.http_code;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup_temp_daemons();
|
||||
|
||||
return parse_curl_output(output, result);
|
||||
if (passed_count == total_urls) {
|
||||
result.success = true;
|
||||
result.http_code = last_http > 0 ? last_http : 200;
|
||||
result.handshake_ms = int(sum_handshake / double(total_urls));
|
||||
result.ttfb_ms = int(sum_ttfb / double(total_urls));
|
||||
result.speed_kbps = max_speed;
|
||||
result.score = 100 + max(0, 1000 - result.ttfb_ms) + int(result.speed_kbps / 10.0);
|
||||
} else {
|
||||
result.success = false;
|
||||
result.http_code = last_http;
|
||||
result.score = 0;
|
||||
result.error = sprintf("Failed %d of %d endpoints", total_urls - passed_count, total_urls);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (engine == "zapret" || engine == "zapret2") {
|
||||
@@ -933,30 +1202,71 @@ function run_probe(engine, args_str, target_url) {
|
||||
if (is_z2 && index(args_str, "--filter-tcp") < 0 && index(args_str, "--filter-l7") < 0) {
|
||||
filter_prefix = "--filter-tcp=443 --filter-l7=tls --payload=tls_client_hello ";
|
||||
}
|
||||
if (is_z2 && is_udp && index(args_str, "--filter-udp") < 0) {
|
||||
filter_prefix += "--filter-udp=443 --payload=quic_initial ";
|
||||
}
|
||||
|
||||
let spawn_cmd = sprintf("cd /tmp && %s --qnum=%d --fwmark=%s %s%s%s --pidfile=%s --daemon", bin, qnum, FUZZER_FWMARK, lua_init_flags, filter_prefix, args_str, pid_path);
|
||||
system(common.background_command(spawn_cmd));
|
||||
system("sleep 0.15");
|
||||
|
||||
// Setup temporary isolated nftables queue for probe with high priority (-200)
|
||||
system("nft add table inet tachyon_fuzzer 2>/dev/null");
|
||||
system("nft 'add chain inet tachyon_fuzzer output { type filter hook output priority -200 ; }' 2>/dev/null");
|
||||
system(sprintf("nft add rule inet tachyon_fuzzer output meta mark %s counter return 2>/dev/null", FUZZER_FWMARK));
|
||||
system(sprintf("nft 'add rule inet tachyon_fuzzer output meta l4proto tcp tcp dport { 80, 443 } counter queue num %d bypass' 2>/dev/null", qnum));
|
||||
if (is_udp) {
|
||||
system(sprintf("nft 'add rule inet tachyon_fuzzer output meta l4proto { tcp, udp } th dport { 80, 443, 50000-65535 } counter queue num %d bypass' 2>/dev/null", qnum));
|
||||
} else {
|
||||
system(sprintf("nft 'add rule inet tachyon_fuzzer output meta l4proto tcp tcp dport { 80, 443 } counter queue num %d bypass' 2>/dev/null", qnum));
|
||||
}
|
||||
|
||||
// Execute probe with direct curl
|
||||
let curl_cmd = sprintf(
|
||||
"curl -so /dev/null -w '%%{http_code}\\t%%{time_appconnect}\\t%%{time_starttransfer}\\t%%{speed_download}' -L --connect-timeout 3 --max-time 4 %s 2>/dev/null",
|
||||
shell_quote(target_url)
|
||||
);
|
||||
let passed_count = 0;
|
||||
let sum_handshake = 0;
|
||||
let sum_ttfb = 0;
|
||||
let max_speed = 0;
|
||||
let last_http = 0;
|
||||
|
||||
let pipe = fs.popen(curl_cmd, "r");
|
||||
let output = pipe ? pipe.read("all") : "";
|
||||
if (pipe) pipe.close();
|
||||
for (let target_item in urls_list) {
|
||||
let curl_cmd = sprintf(
|
||||
"curl -so /dev/null -w '%%{http_code}\\t%%{time_appconnect}\\t%%{time_starttransfer}\\t%%{speed_download}' -L --connect-timeout 3 --max-time 4 %s 2>/dev/null",
|
||||
shell_quote(target_item.url)
|
||||
);
|
||||
let pipe = fs.popen(curl_cmd, "r");
|
||||
let output = pipe ? pipe.read("all") : "";
|
||||
if (pipe) pipe.close();
|
||||
|
||||
let single_res = parse_curl_output(output, {});
|
||||
single_res.target_name = target_item.name;
|
||||
single_res.url = target_item.url;
|
||||
push(result.sub_probes, single_res);
|
||||
|
||||
if (single_res.success) {
|
||||
passed_count++;
|
||||
sum_handshake += single_res.handshake_ms;
|
||||
sum_ttfb += single_res.ttfb_ms;
|
||||
if (single_res.speed_kbps > max_speed) max_speed = single_res.speed_kbps;
|
||||
last_http = single_res.http_code;
|
||||
} else if (last_http == 0) {
|
||||
last_http = single_res.http_code;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup_temp_daemons();
|
||||
|
||||
return parse_curl_output(output, result);
|
||||
if (passed_count == total_urls) {
|
||||
result.success = true;
|
||||
result.http_code = last_http > 0 ? last_http : 200;
|
||||
result.handshake_ms = int(sum_handshake / double(total_urls));
|
||||
result.ttfb_ms = int(sum_ttfb / double(total_urls));
|
||||
result.speed_kbps = max_speed;
|
||||
result.score = 100 + max(0, 1000 - result.ttfb_ms) + int(result.speed_kbps / 10.0);
|
||||
} else {
|
||||
result.success = false;
|
||||
result.http_code = last_http;
|
||||
result.score = 0;
|
||||
result.error = sprintf("Failed %d of %d endpoints", total_urls - passed_count, total_urls);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result.error = "Unknown engine: " + engine;
|
||||
@@ -1007,7 +1317,7 @@ function run_fuzzer_worker(engine, target, custom_url, rule_section, custom_file
|
||||
state.progress_pct = int(((i) / double(total)) * 100.0);
|
||||
save_fuzzer_state(state);
|
||||
|
||||
let probe = run_probe(strat.engine || engine, strat.args, target_url);
|
||||
let probe = run_probe(strat.engine || engine, strat.args, target, custom_url);
|
||||
|
||||
let item_result = {
|
||||
id: strat.id || sprintf("strat_%d", i + 1),
|
||||
@@ -1023,6 +1333,7 @@ function run_fuzzer_worker(engine, target, custom_url, rule_section, custom_file
|
||||
speed_kbps: probe.speed_kbps,
|
||||
score: probe.score,
|
||||
error: probe.error,
|
||||
sub_probes: probe.sub_probes || [],
|
||||
badge: ""
|
||||
};
|
||||
|
||||
@@ -1082,7 +1393,7 @@ function start_fuzzer(engine, target, custom_url, rule_section, custom_file, mod
|
||||
let cmd = sprintf(
|
||||
"ucode -L /usr/lib/tachyon /usr/lib/tachyon/diagnostics/fuzzer.uc worker %s %s %s %s %s %s",
|
||||
shell_quote(engine || "zapret2"),
|
||||
shell_quote(target || "youtube"),
|
||||
shell_quote(target || "youtube_suite"),
|
||||
shell_quote(custom_url || ""),
|
||||
shell_quote(rule_section || ""),
|
||||
shell_quote(custom_file || ""),
|
||||
@@ -1091,7 +1402,7 @@ function start_fuzzer(engine, target, custom_url, rule_section, custom_file, mod
|
||||
|
||||
system(common.background_command_with_pid(cmd, ">/dev/null", ">" + shell_quote(PID_FILE)));
|
||||
|
||||
print(sprintf("%J\n", { success: true, job_id, engine: engine || "zapret2", target: target || "youtube", mode: mode || "presets" }));
|
||||
print(sprintf("%J\n", { success: true, job_id, engine: engine || "zapret2", target: target || "youtube_suite", mode: mode || "presets" }));
|
||||
}
|
||||
|
||||
function stop_fuzzer() {
|
||||
@@ -1128,7 +1439,6 @@ function apply_strategy(engine, args_val, target_rule) {
|
||||
let uci = uci_core.cursor();
|
||||
let applied = false;
|
||||
|
||||
// If target rule section is specified, update that rule
|
||||
if (target_rule != "" && target_rule != "global") {
|
||||
uci.set(CONFIG_NAME, target_rule, "action", engine);
|
||||
if (engine == "zapret2")
|
||||
@@ -1139,7 +1449,6 @@ function apply_strategy(engine, args_val, target_rule) {
|
||||
uci.set(CONFIG_NAME, target_rule, "byedpi_cmd_opts", args_val);
|
||||
applied = true;
|
||||
} else {
|
||||
// Apply as provider global setting
|
||||
let provider_sec = engine;
|
||||
let sec_obj = uci.get_all(CONFIG_NAME, provider_sec);
|
||||
if (sec_obj == null) {
|
||||
@@ -1156,8 +1465,6 @@ function apply_strategy(engine, args_val, target_rule) {
|
||||
}
|
||||
|
||||
uci.commit(CONFIG_NAME);
|
||||
|
||||
// Mark reload pending
|
||||
system(common.background_command("tachyon reload"));
|
||||
|
||||
print(sprintf("%J\n", {
|
||||
@@ -1181,6 +1488,13 @@ if (op == "start") {
|
||||
stop_fuzzer();
|
||||
} else if (op == "apply") {
|
||||
apply_strategy(ARGV[1], ARGV[2], ARGV[3]);
|
||||
} else if (op == "get_patterns" || op == "patterns") {
|
||||
print(sprintf("%J\n", { success: true, patterns: get_patterns_config() }));
|
||||
} else if (op == "save_patterns") {
|
||||
let cfg = safe_json_parse(ARGV[1]);
|
||||
save_patterns_config(cfg);
|
||||
} else if (op == "reset_patterns") {
|
||||
reset_patterns_config();
|
||||
} else if (op == "ai_synthesize" || op == "synthesize") {
|
||||
synthesize_ai_strategies(ARGV[1], ARGV[2], ARGV[3], ARGV[4]);
|
||||
} else if (op == "generate" || op == "strategies_generate") {
|
||||
@@ -1189,11 +1503,14 @@ if (op == "start") {
|
||||
let strat_mode = ARGV[1] || "presets";
|
||||
print(sprintf("%J\n", {
|
||||
available_engines: get_available_engines(),
|
||||
target_suites: TARGET_SUITES,
|
||||
patterns: get_patterns_config(),
|
||||
zapret2: get_strategies_for_engine("zapret2", strat_mode),
|
||||
zapret: get_strategies_for_engine("zapret", strat_mode),
|
||||
byedpi: get_strategies_for_engine("byedpi", strat_mode)
|
||||
}));
|
||||
} else {
|
||||
warn("Usage: fuzzer.uc [start|status|stop|apply|strategies|generate|ai_synthesize|worker] ...\n");
|
||||
warn("Usage: fuzzer.uc [start|status|stop|apply|strategies|generate|get_patterns|save_patterns|reset_patterns|ai_synthesize|worker] ...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user