diff --git a/fe-app-tachyon/locales/tachyon.ru.po b/fe-app-tachyon/locales/tachyon.ru.po index ab2bb5a8..f86fdc3c 100644 --- a/fe-app-tachyon/locales/tachyon.ru.po +++ b/fe-app-tachyon/locales/tachyon.ru.po @@ -1586,6 +1586,9 @@ msgstr "Скачивать эту подписку без проверки се msgid "Download through" msgstr "Загружать через" +msgid "(this rule, when active)" +msgstr "(эта же секция, при активном VPN)" + msgid "Downloaded" msgstr "Загружено" diff --git a/fe-app-tachyon/package.json b/fe-app-tachyon/package.json index 07b1acad..0288fec5 100644 --- a/fe-app-tachyon/package.json +++ b/fe-app-tachyon/package.json @@ -1,6 +1,6 @@ { "name": "fe-app-tachyon", - "version": "1.3.25", + "version": "1.3.26", "license": "MIT", "type": "module", "scripts": { diff --git a/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/parental.js b/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/parental.js index fd49815c..1be9c074 100644 --- a/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/parental.js +++ b/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/parental.js @@ -780,7 +780,7 @@ function createParentalContent(section) { o.rawhtml = true; o.modalonly = false; o.cfgvalue = function (sectionId) { - const target = uci.get(UCI_PACKAGE, sectionId, "target") || "all"; + const target = uci.get(UCI_PACKAGE, sectionId, "target") || "domains"; if (target === "all") { return ( '🚫 ' + @@ -788,11 +788,20 @@ function createParentalContent(section) { "" ); } + if (target === "domains") { + const rawDomains = normalizeListValues( + uci.get(UCI_PACKAGE, sectionId, "blocked_domains"), + ); + const count = rawDomains.length; + return ( + '🌐 ' + + _("Blocked Sites") + + (count > 0 ? " (" + count + ")" : "") + + "" + ); + } const rawSecs = uci.get(UCI_PACKAGE, sectionId, "sections"); const secNames = normalizeListValues(rawSecs); - if (secNames.length === 0 && target !== "sections") { - secNames.push(target); - } if (secNames.length === 0) { return ( '' + _("No sections selected") + "" @@ -814,8 +823,17 @@ function createParentalContent(section) { ); }; o.textvalue = function (sectionId) { - const target = uci.get(UCI_PACKAGE, sectionId, "target") || "all"; + const target = uci.get(UCI_PACKAGE, sectionId, "target") || "domains"; if (target === "all") return _("All Internet"); + if (target === "domains") { + const rawDomains = normalizeListValues( + uci.get(UCI_PACKAGE, sectionId, "blocked_domains"), + ); + return ( + _("Blocked Sites") + + (rawDomains.length > 0 ? " (" + rawDomains.length + ")" : "") + ); + } const secNames = normalizeListValues( uci.get(UCI_PACKAGE, sectionId, "sections"), ); @@ -1081,6 +1099,7 @@ function createParentalContent(section) { ), ); o.modalonly = true; + o.rmempty = false; o.default = "domains"; o.value("domains", _("Blocked Sites (Only block domains specified below)")); o.value("all", _("All Internet (Complete internet cutoff)")); @@ -1222,6 +1241,7 @@ function createParentalContent(section) { ), ); o.modalonly = true; + o.depends("target", "domains"); o.rmempty = true; o.rows = 6; o.wrap = "soft"; diff --git a/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js b/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js index c25de731..b122b791 100644 --- a/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js +++ b/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js @@ -2083,7 +2083,6 @@ function isDownloadThroughTargetSection(section, currentSectionId) { if ( !sectionName || - sectionName === currentSectionId || section.enabled === "0" ) { return false; @@ -2134,10 +2133,17 @@ function isDownloadThroughTargetSection(section, currentSectionId) { function subscriptionDownloadTargetChoices(section_id) { return (uci.sections(UCI_PACKAGE, "section") || []) .filter((section) => isDownloadThroughTargetSection(section, section_id)) - .map((section) => ({ - value: getUciSectionName(section), - label: getUciSectionLabel(section), - })); + .map((section) => { + const name = getUciSectionName(section); + let label = getUciSectionLabel(section); + if (name === section_id) { + label += " " + _("(this rule, when active)"); + } + return { + value: name, + label: label, + }; + }); } function dnsTypeChoices() { @@ -2745,9 +2751,6 @@ function addSubscriptionUrlItemOptions(itemSection, options = {}) { if (!value) { return _("Select a section for downloading this subscription"); } - if (value === sectionId) { - return _("Current section cannot download its own subscription"); - } return true; }; diff --git a/luci-app-tachyon/po/ru/tachyon.po b/luci-app-tachyon/po/ru/tachyon.po index ab2bb5a8..f86fdc3c 100644 --- a/luci-app-tachyon/po/ru/tachyon.po +++ b/luci-app-tachyon/po/ru/tachyon.po @@ -1586,6 +1586,9 @@ msgstr "Скачивать эту подписку без проверки се msgid "Download through" msgstr "Загружать через" +msgid "(this rule, when active)" +msgstr "(эта же секция, при активном VPN)" + msgid "Downloaded" msgstr "Загружено" diff --git a/tachyon/files/etc/hotplug.d/iface/99-tachyon-wan-monitor b/tachyon/files/etc/hotplug.d/iface/99-tachyon-wan-monitor index 1dbe089c..7b194212 100644 --- a/tachyon/files/etc/hotplug.d/iface/99-tachyon-wan-monitor +++ b/tachyon/files/etc/hotplug.d/iface/99-tachyon-wan-monitor @@ -86,8 +86,8 @@ done PREV_STATE="" [ -f "$STATE_FILE" ] && PREV_STATE="$(cat "$STATE_FILE" 2>/dev/null)" - TACHYON_BIN="/usr/bin/tachyon" - [ -x "$TACHYON_BIN" ] || TACHYON_BIN="$(command -v tachyon 2>/dev/null || echo /usr/bin/tachyon)" + TACHYON_BIN="$(command -v tachyon 2>/dev/null || echo /usr/bin/tachyon)" + [ -x "$TACHYON_BIN" ] || TACHYON_BIN="/usr/bin/tachyon" if [ "$CURRENT_STATE" = "up" ]; then if [ "$PREV_STATE" = "down" ]; then diff --git a/tachyon/files/usr/bin/tachyon b/tachyon/files/usr/bin/tachyon index 13dde1cd..be0ebed7 100755 --- a/tachyon/files/usr/bin/tachyon +++ b/tachyon/files/usr/bin/tachyon @@ -234,6 +234,7 @@ function command_spec(command) { get_tailscale_peers: [ "diagnostics/runtime.uc", "get-tailscale-peers", 0 ], tailscale_restart: [ "providers/tailscale/runtime.uc", "start-runtime", 0 ], parental_quota_tick: [ "service/parental_quota.uc", "tick", 0 ], + parental_quota_reset: [ "service/parental_quota.uc", "reset", 0 ], failover_check: [ "service/failover.uc", "check", 0 ], get_system_info: [ "diagnostics/runtime.uc", "get-system-info", 0 ], get_server_capabilities: [ "diagnostics/runtime.uc", "get-server-capabilities", 0 ], diff --git a/tachyon/files/usr/lib/config/connections.uc b/tachyon/files/usr/lib/config/connections.uc index e5c0f3c9..56c5d89d 100644 --- a/tachyon/files/usr/lib/config/connections.uc +++ b/tachyon/files/usr/lib/config/connections.uc @@ -1303,7 +1303,7 @@ function subscription_download_targets(sections) { for (let source in subscription_urls(section)) { let target = subscription_download_section(section, source); - if (target != "" && target != name) + if (target != "") append_unique(result, seen, target); } } diff --git a/tachyon/files/usr/lib/config/validator.uc b/tachyon/files/usr/lib/config/validator.uc index 78824d02..16cd4362 100644 --- a/tachyon/files/usr/lib/config/validator.uc +++ b/tachyon/files/usr/lib/config/validator.uc @@ -1710,9 +1710,6 @@ function validate_subscription_download_sections(sections, context) { if (target == "") continue; - if (target == name) - fail_validation("Subscription source in rule '" + name + "' cannot be downloaded through the same rule. Select another rule or disable download-through-section. Aborted."); - validate_download_section_rows( target, context.byedpi_installed, diff --git a/tachyon/files/usr/lib/nft/apply.uc b/tachyon/files/usr/lib/nft/apply.uc index 9610d74f..5cbc5dc2 100644 --- a/tachyon/files/usr/lib/nft/apply.uc +++ b/tachyon/files/usr/lib/nft/apply.uc @@ -1033,7 +1033,7 @@ function nft_add_schedule_rules_from_schedules(schedules, sections, table, profi let always_on = length(intervals) == 0; let target_sec_names = []; - if (target == "sections" || (target != "all" && target != "")) { + if (target == "sections" || (target != "all" && target != "domains" && target != "")) { let raw_secs = list_option(schedule, "sections"); if (length(raw_secs) == 0) { let single_sec = option(schedule, "sections", ""); @@ -1055,8 +1055,12 @@ function nft_add_schedule_rules_from_schedules(schedules, sections, table, profi [ "meta", "hour", sprintf("\"%s\"-\"%s\"", interval[0], interval[1]) ] : null; let base_match = nft_schedule_rule_base_match(dev_str, is_mac, family, days_args, time_args); + let quota_minutes = int(option(schedule, "daily_quota_minutes", 0)); let has_sched_domains = length(list_option(schedule, "blocked_domains")) > 0 || option(schedule, "blocked_domains", "") != ""; if ((target == "all" || (length(target_sec_names) == 0 && target != "sections" && target != "domains")) && !has_sched_domains && target != "domains") { + if (always_on && quota_minutes > 0) + continue; + let fwd_rule = []; append_array(fwd_rule, base_match); append_array(fwd_rule, [ "counter", verdict ]); @@ -1159,6 +1163,9 @@ function nft_add_dns_block_rules_from_schedules(schedules, table, profiles) { let intervals = nft_schedule_time_intervals(start_time, end_time); let days_args = nft_schedule_days_match_args(schedule); let always_on = length(intervals) == 0; + let quota_minutes = int(option(schedule, "daily_quota_minutes", 0)); + if (always_on && quota_minutes > 0) + continue; for (let raw_ip in raw_ips) { let dev_str = trim(as_string(raw_ip)); @@ -1473,6 +1480,8 @@ function nft_create_runtime_base(table, localv4_set, common_set, port_set, ip_po !nft_create_ipv6_port_set(table, ip_port6_set) || !nft_create_ipv4_set(table, DNS_SOURCE_SET) || !nft_create_ipv6_set(table, DNS_SOURCE6_SET) || + !nft_create_ether_set(table, "tachyon_quota_block") || + !nft_create_ipv4_set(table, "tachyon_quota_block_ip") || !nft_create_ifname_set(table, interface_set)) return false; @@ -1494,7 +1503,11 @@ function nft_create_runtime_base(table, localv4_set, common_set, port_set, ip_po if (!nft_add_rule(table, "parental_control", [ "ip", "daddr", "@" + as_string(localv4_set), "return" ]) || !nft_add_rule(table, "parental_control", [ "ip6", "daddr", "@" + as_string(localv6_set), "return" ]) || !nft_add_rule(table, "parental_forward", [ "ip", "daddr", "@" + as_string(localv4_set), "return" ]) || - !nft_add_rule(table, "parental_forward", [ "ip6", "daddr", "@" + as_string(localv6_set), "return" ])) + !nft_add_rule(table, "parental_forward", [ "ip6", "daddr", "@" + as_string(localv6_set), "return" ]) || + !nft_add_rule(table, "parental_control", [ "ether", "saddr", "@tachyon_quota_block", "counter", "drop", "comment", "\"tachyon-quota-ether\"" ]) || + !nft_add_rule(table, "parental_control", [ "ip", "saddr", "@tachyon_quota_block_ip", "counter", "drop", "comment", "\"tachyon-quota-ip\"" ]) || + !nft_add_rule(table, "parental_forward", [ "ether", "saddr", "@tachyon_quota_block", "counter", "drop", "comment", "\"tachyon-quota-ether\"" ]) || + !nft_add_rule(table, "parental_forward", [ "ip", "saddr", "@tachyon_quota_block_ip", "counter", "drop", "comment", "\"tachyon-quota-ip\"" ])) return false; if (!nft_add_rule(table, "dns_redirect", [ "iifname", "@" + as_string(interface_set), "ip", "saddr", "@" + DNS_SOURCE_SET, "tcp", "dport", "53", "counter", "redirect", "to", ":" + as_string(runtime_constants.SOURCE_DNS_INBOUND_PORT) ]) || diff --git a/tachyon/files/usr/lib/rag_index.json b/tachyon/files/usr/lib/rag_index.json index bc996e37..5d4ef7b4 100644 --- a/tachyon/files/usr/lib/rag_index.json +++ b/tachyon/files/usr/lib/rag_index.json @@ -1 +1 @@ -{"version":1,"chunk_size":2000,"chunk_overlap":200,"total_chunks":50,"files":["01_SYSTEM_ARCHITECTURE.md","02_UCODE_MODULE_REFERENCE.md","03_NETWORKING_NFTABLES_AND_ROUTING.md","04_DPI_BYPASS_ENGINES.md","05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md","06_FRONTEND_LUCI_TYPESCRIPT.md","07_BUILD_TESTS_AND_DEPLOYMENT.md","08_UCI_CONFIGURATION_SCHEMA.md","09_TELEGRAM_BOT_ARCHITECTURE.md","10_HOSTS_ENGINE_AND_BLOCKLISTS.md","11_TROUBLESHOOTING_AND_FIELD_MANUAL.md","12_UCODE_PROGRAMMING_PATTERNS.md","13_REST_API_AND_MCP_SPECIFICATION.md","14_ZAPRET2_DEEP_DIVE_MANUAL.md","15_ZAPRET1_NFQWS_FIELD_GUIDE.md","16_BYEDPI_CIADPI_REFERENCE.md","17_TSPU_DPI_SIGNATURES_AND_COUNTERS.md","INDEX.md"],"chunks":[{"id":0,"file":"01_SYSTEM_ARCHITECTURE.md","heading":"2.2. Deterministic State & Atomic Writes","text":"# 01. System Architecture & Core Concepts\n\n## 1. High-Level Overview\n\n**Tachyon** is an enterprise-grade, lightweight traffic orchestration, multi-protocol proxying, and DPI anti-censorship platform built natively for **OpenWrt** (supporting 23.05, 24.10, 25.x, and SNAPSHOT).\n\n```mermaid\ngraph TD\n Client[LAN Clients] -->|TCP/UDP| Router[OpenWrt Router]\n Router --> NFT[nftables: inet TachyonTable]\n \n NFT -->|Direct List / 0ms| WAN[Direct WAN Gateway]\n NFT -->|NFQueue Desync| Zapret[Zapret v1 / v2 nfqws/2]\n NFT -->|SOCKS Desync| ByeDPI[ByeDPI ciadpi]\n NFT -->|TProxy / Redirect| SingBox[sing-box Core v1.11+]\n \n SingBox -->|VLESS Reality / H2 / WG| VPS[External VPS / Global Web]\n Zapret --> WAN\n ByeDPI --> WAN\n \n subgraph Tachyon Control Plane\n UCODE[ucode Core Runtime] --> NFT\n UCODE --> SingBox\n UCODE --> Zapret\n UCODE --> ByeDPI\n Watchdog[Autonomous Watchdog 5-15s] --> UCODE\n AIDoctor[AI Doctor v2.5 / Local Doctor] --> Watchdog\n Telegram[Telegram Bot Daemon] --> UCODE\n RestAPI[HTTP REST Agent API / OpenAPI 3.0] --> UCODE\n LuCI[LuCI TypeScript Web UI] --> UCODE\n end\n```\n\n---\n\n## 2. Core Architectural Pillars\n\n### 2.1. Native ucode Runtime (Zero Heavy Runtimes)\n* All control plane logic, UCI manipulation, config generation, health checks, and JSON APIs are written in **ucode**, OpenWrt's native C-like scripting language.\n* **Benefits**:\n * Consumes $\\approx$ 1–3 MB RAM (contrasted with 30–60 MB for Python/Node).\n * Executes directly in C-speed with native bindings to `libuci`, `libubus`, `libblobmsg`, and posix syscalls (`fs`, `math`, `socket`).\n * Runs on routers with as little as 128 MB RAM.\n\n### 2.2. Deterministic State & Atomic Writes\n* All configuration changes (`/etc/config/tachyon`) and JSON runtime configurations (`/tmp/tachyon/sing-box.json`) use an **atomic write pattern** (`tmp_file + rename`):\n ```ucode\n fs.writefile(tmp_path, json_str);\n fs.rename(tmp_path, target_path);","embedding":[]},{"id":1,"file":"01_SYSTEM_ARCHITECTURE.md","heading":"3. Directory Layout & Repository Anatomy","text":"* All configuration changes (`/etc/config/tachyon`) and JSON runtime configurations (`/tmp/tachyon/sing-box.json`) use an **atomic write pattern** (`tmp_file + rename`):\n ```ucode\n fs.writefile(tmp_path, json_str);\n fs.rename(tmp_path, target_path);\n ```\n This prevents file corruption during sudden power losses or kernel panics.\n\n### 2.3. Dual Control Interfaces: LuCI & Headless Telegram/REST\n1. **LuCI Web UI**: Modern TypeScript SPA (`fe-app-tachyon`) compiled into LuCI JS assets (`luci-app-tachyon`).\n2. **Interactive Telegram Bot**: Embedded polling daemon with inline keyboards for on-the-fly server switching, rule updates, and instant diagnostics.\n3. **HTTP REST Agent API**: Secure CGI endpoint (`/cgi-bin/tachyon-agent/`) with OpenAPI 3.0.3 spec for integration with LLM agents (ChatGPT Custom GPTs, Cursor, Claude Code, N8N).\n\n---\n\n## 3. Directory Layout & Repository Anatomy\n\n```\ntachyon/\n├── tachyon/files/ # Core backend package root\n│ ├── etc/\n│ │ ├── config/tachyon # Main UCI configuration (chmod 600)\n│ │ ├── init.d/tachyon # Procd service init script\n│ │ └── uci-defaults/ # Post-installation default configs\n│ ├── usr/\n│ │ ├── bin/tachyon # Main CLI entrypoint wrapper\n│ │ └── lib/tachyon/ # Modular ucode libraries (60+ modules)\n│ │ ├── core/ # Low-level helpers, UCI, constants\n│ │ ├── service/ # Lifecycle, Watchdog, APIs, Telegram\n│ │ ├── diagnostics/ # AI Doctor, Local Doctor, Quick Fixes\n│ │ ├── singbox/ # Config generator, DNS, routing\n│ │ ├── providers/ # Zapret v1/v2, ByeDPI, NFQueue\n│ │ ├── nft/ # nftables ruleset compiler & applier\n│ │ ├── dns/ # dnsmasq & DNS routing coordinator\n│ │ ├── components/ # Updater, package manager, hosts\n│ │ ├── config/ # Validator, rule engine, migrations","embedding":[]},{"id":2,"file":"01_SYSTEM_ARCHITECTURE.md","heading":"4. Key Runtime Processes & Daemons","text":"│ │ ├── dns/ # dnsmasq & DNS routing coordinator\n│ │ ├── components/ # Updater, package manager, hosts\n│ │ ├── config/ # Validator, rule engine, migrations\n│ │ └── subscription/ # Subscriptions fetcher & parser\n├── luci-app-tachyon/ # OpenWrt LuCI package\n│ ├── htdocs/luci-static/resources/view/tachyon/ # Compiled frontend JS bundle\n│ ├── root/etc/uci-defaults/ # LuCI menu registration\n│ └── po/ # Translations (ru, en)\n├── fe-app-tachyon/ # Frontend TypeScript source\n│ ├── src/ # TypeScript SPA source\n│ ├── tsup.config.ts # Builds and patches LuCI baseclass\n│ └── package.json # Dependencies (vitest, typescript, tsup)\n├── tests/ # Comprehensive test suite (100+ shell tests)\n├── build.sh # Release packager (ipk + apk)\n├── install.sh # One-liner end-user installer\n└── docs/ # Technical documentation & Knowledge Base\n```\n\n---\n\n## 4. Key Runtime Processes & Daemons\n\n| Process | Role | Execution Model |\n|---|---|---|\n| `sing-box` | Core proxying & packet tunneling engine | Managed by procd (`/etc/init.d/tachyon`) |\n| `nfqws` / `nfqws2` | Local TCP/UDP packet desynchronizer (Zapret) | Spawned into background per configured rule |\n| `ciadpi` | Local SOCKS desync proxy (ByeDPI) | Spawned on `127.0.0.1:1080` / custom port |\n| `watchdog.uc` | State supervision, loop mitigation, self-healing | Background periodic daemon (every 5–15s) |\n| `telegram.uc` | Telegram Bot Long-Polling Daemon | Procd-supervised background worker |\n| `agent_api.uc` | HTTP REST Agent API Handler | Invoked on-demand via `uhttpd` CGI |","embedding":[]},{"id":3,"file":"02_UCODE_MODULE_REFERENCE.md","heading":"2. Service Management Subsystem (`service/`)","text":"# 02. ucode Backend Module Reference\n\nTachyon's backend is modularized under `tachyon/files/usr/lib/tachyon/`. Modules are loaded dynamically via ucode's `require()` or executed directly via `ucode -L `.\n\n---\n\n## 1. Core Subsystem (`core/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `constants.uc` | Central repository of paths, default ports, mark values, version detection (`detect_installed_version()`), commit SHA resolver (`detect_installed_commit_sha()`), UCI config names. |\n| `common.uc` | String manipulation (`trim`, `split_lines`), file helpers (`read_file`, `write_atomic`), logging formatters (`log_info`, `log_error`, `log_debug`). |\n| `helpers.uc` | Process management (`popen_read`, `system_exec`), CIDR formatting, MAC address validators, integer conversions with safety fallbacks. |\n| `ip.uc` | IP v4/v6 parser, subnet containment (`ip_in_subnet`), CIDR validator, loopback & private IP range detection. |\n| `url.uc` | RFC 3986 URL parser, extraction of scheme, host, port, path, query params, hash fragment, safe URL encoding/decoding. |\n| `uci.uc` | High-level wrapper over OpenWrt `libuci`: `get_section`, `set_option`, `add_section`, `delete_section`, atomic commit with lock. |\n| `packages.uc` | Package manager abstraction: detects `opkg` vs `apk` (OpenWrt 25.x+), checks installed packages, versions, and dependencies. |\n| `events.uc` | Internal event bus mechanism: publish/subscribe for service state transitions and notification dispatching. |\n\n---\n\n## 2. Service Management Subsystem (`service/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `lifecycle.uc` | Service start, stop, restart, enable, disable. Coordinates teardown order (nftables -> singbox -> zapret -> dnsmasq) to prevent routing deadlocks. |\n| `state.uc` | Comprehensive runtime state reader (`get_runtime_state()`): active proxy server, watchdog status, interface health, uptime, memory consumption. |\n| `reload.uc` | Hot-reload planner (`plan_reload()`): inspects what changed in UCI and applies the minimal necessary restart (e.g. soft-reload sing-box vs full nftables rebuild). |","embedding":[]},{"id":4,"file":"02_UCODE_MODULE_REFERENCE.md","heading":"3. Diagnostics & AI Subsystem (`diagnostics/`)","text":"| `state.uc` | Comprehensive runtime state reader (`get_runtime_state()`): active proxy server, watchdog status, interface health, uptime, memory consumption. |\n| `reload.uc` | Hot-reload planner (`plan_reload()`): inspects what changed in UCI and applies the minimal necessary restart (e.g. soft-reload sing-box vs full nftables rebuild). |\n| `reset.uc` | Factory reset routines: wipes `/etc/config/tachyon`, cleans up temporary caches, restores default templates. |\n| `watchdog.uc` | Autonomous supervisor loop: checks sing-box process, memory thresholds (OOM guard), DNS resolution, loop-restart mitigation (`safe_proxy_restart`). |\n| `snapshot.uc` | Assembles a structured system snapshot JSON for AI Doctor and external diagnostics. |\n| `agent_api.uc` | CGI handler for `/cgi-bin/tachyon-agent/`: handles routing, Bearer authentication validation, endpoint dispatch, JSON serialization. |\n| `agent_mcp.uc` | Model Context Protocol (MCP) tool schema and handlers for integration with MCP clients (Cursor, Claude Desktop). |\n| `telegram.uc` | Telegram Bot daemon: polling loop (`getUpdates`), command dispatcher (`/doctor`, `/ai_doctor`, `/fix`, `/restart`, `/status`), inline keyboards. |\n| `warp_generator.uc` | Cloudflare WARP account generator & key exchange for auto-provisioning WireGuard outbounds. |\n| `event_controller.uc` | Coordinates async background job workers, PID tracking, lock files, and log ring-buffer management. |\n\n---\n\n## 3. Diagnostics & AI Subsystem (`diagnostics/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `runtime.uc` | **Local Rule Doctor & AI Doctor engine**: runs 10+ local heuristic checks, detects NTP desync, conntrack overflow, MTU issues, bootstrap DNS deadlock; applies 13+ quick fix codes (`apply_quick_fix()`), executes emergency internet restoration (`restore_native_internet()`). |\n| `service_check.uc` | Health probes: tests sing-box TCP/UDP proxying, DNS response latency, WAN internet connectivity, gateway reachability. |\n| `status.uc` | Detailed diagnostics status assembler for LuCI Diagnostic tab and CLI `tachyon doctor`. |","embedding":[]},{"id":5,"file":"02_UCODE_MODULE_REFERENCE.md","heading":"5. Providers & DPI Bypass Subsystem (`providers/`)","text":"| `service_check.uc` | Health probes: tests sing-box TCP/UDP proxying, DNS response latency, WAN internet connectivity, gateway reachability. |\n| `status.uc` | Detailed diagnostics status assembler for LuCI Diagnostic tab and CLI `tachyon doctor`. |\n\n---\n\n## 4. sing-box Subsystem (`singbox/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `generator.uc` | Master sing-box JSON configuration compiler (`/tmp/tachyon/sing-box.json`): binds inbounds, outbounds, routing rules, DNS, experimental. |\n| `generator_outbounds.uc` | Compiles VLESS (Reality/gRPC/WS), VMess, Shadowsocks, Trojan, Hysteria2, WireGuard, Direct, and Block outbounds. |\n| `generator_routes.uc` | Compiles routing rules: domain matchers, IP CIDR matchers, GeoIP rules, client MAC/IP matchers, detour assignments. |\n| `dns.uc` | Compiles sing-box DNS configuration: local DNS, remote DoH/DoT/UDP DNS, fakeip/direct resolution rules. |\n| `dns_failover.uc` | High-availability DNS failover logic: switches between primary and secondary bootstrap DNS upon timeouts. |\n| `dns_prefetch.uc` | Domain pre-fetching & cache warming for frequently accessed sites. |\n| `dns_presets.uc` | Built-in DNS presets (Cloudflare, Google, AdGuard, Quad9, OpenDNS, Custom DoH). |\n| `priority.uc` | Outbound group priority manager: auto-failover, fallback groups, URL-test latency sorting. |\n| `route.uc` | Low-level sing-box route rule builder & selector logic. |\n| `rulesets.uc` | Rule-set binary (`.srs`) and JSON ruleset compiler and parser. |\n| `servers.uc` | Server node parser, validator, and URI serializer (VLESS, VMess, SS, Trojan, H2). |\n| `subscription.uc` | Subscriptions processor: download, base64 decoding, node deduplication, format normalizer. |\n| `urltest.uc` | RTT ping & latency testing worker: measures real response times across proxy servers. |\n\n---\n\n## 5. Providers & DPI Bypass Subsystem (`providers/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `zapret/runtime.uc` | Manages **Zapret v1 (`nfqws`)** process arguments, queue numbers, NFQueue bindings, daemon start/stop. |","embedding":[]},{"id":6,"file":"02_UCODE_MODULE_REFERENCE.md","heading":"7. Configuration & Components Subsystem (`config/`, `components/`, `subscription/`)","text":"## 5. Providers & DPI Bypass Subsystem (`providers/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `zapret/runtime.uc` | Manages **Zapret v1 (`nfqws`)** process arguments, queue numbers, NFQueue bindings, daemon start/stop. |\n| `zapret2/runtime.uc` | Manages **Zapret v2 (`nfqws2`)** advanced multi-vector desync arguments (`--dpi-desync=multisplit`, `--dpi-desync-seqovl`). |\n| `byedpi/runtime.uc` | Manages **ByeDPI (`ciadpi`)** SOCKS5 proxy daemon, port allocation, payload split parameters. |\n| `nfqueue/runtime.uc` | Kernel NFQueue allocation table, prevents queue ID collisions between Zapret v1 and v2. |\n| `rules.uc` | Maps UCI routing rules to specific provider action handlers (`action = zapret | zapret2 | byedpi | proxy`). |\n| `status.uc` | Real-time process inspection and health monitoring of all active DPI bypass daemons. |\n\n---\n\n## 6. Networking & Firewall Subsystem (`nft/`, `dns/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `nft/apply.uc` | Generates and commits nftables ruleset (`inet TachyonTable`): prerouting, output, divert chains, marks, fwmark, bypass sets. |\n| `dns/apply.uc` | Coordinates DNS interception: configures dnsmasq forwarders, port redirection (`127.0.0.1:5353`), ipset / nftset auto-population. |\n\n---\n\n## 7. Configuration & Components Subsystem (`config/`, `components/`, `subscription/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `config/validator.uc` | Strict UCI schema validation: validates IP addresses, ports, UUIDs, private keys, domain names, action modes. |\n| `config/migration.uc` | Automatic migration engine: migrates configurations from legacy Forkop, Podkop Plus, and Podkop configs without data loss. |\n| `components/updater.uc` | Background component installer/updater: handles downloading, unpacking, installing, and version checking of binaries. |\n| `components/hosts.uc` | Remote hosts lists ingestor: fetches blocklists, merges into unified `combined.txt`, handles GitHub mirror failovers. |","embedding":[]},{"id":7,"file":"02_UCODE_MODULE_REFERENCE.md","heading":"7. Configuration & Components Subsystem (`config/`, `components/`, `subscription/`)","text":"| `components/updater.uc` | Background component installer/updater: handles downloading, unpacking, installing, and version checking of binaries. |\n| `components/hosts.uc` | Remote hosts lists ingestor: fetches blocklists, merges into unified `combined.txt`, handles GitHub mirror failovers. |\n| `subscription/cache.uc` | Atomic subscription cache store, prevents redundant network downloads. |\n| `subscription/parser.uc` | Universal proxy URI parser: parses `vless://`, `vmess://`, `ss://`, `trojan://`, `hysteria2://`, `wireguard://`. |","embedding":[]},{"id":8,"file":"03_NETWORKING_NFTABLES_AND_ROUTING.md","heading":"2.1. Key Chains","text":"# 03. Networking, nftables & Traffic Routing\n\n## 1. Packet Journey & Routing Lifecycle\n\nTachyon intercepts traffic at the OpenWrt kernel level using **nftables** and policy routing (`ip rule` + routing table `100`).\n\n```mermaid\nsequenceDiagram\n autonumber\n participant Client as LAN Client\n participant PREROUTING as nftables PREROUTING\n participant Sets as nftables Sets (Bypass / Target)\n participant Divert as Detour Action\n participant SingBox as sing-box / Zapret / ByeDPI\n participant WAN as WAN / Internet\n\n Client->>PREROUTING: TCP/UDP SYN Packet (e.g. 192.168.1.100 -> 1.1.1.1:443)\n PREROUTING->>Sets: Check destination IP / Port against Tachyon sets\n alt IP in Bypass Set (Local Subnet / RuNet / Direct)\n Sets->>WAN: Direct Forwarding (0 ms overhead)\n else IP in Target Set or Default Detour\n Sets->>Divert: Mark packet with FWMARK (e.g. 0x10000000)\n Divert->>SingBox: Divert via TProxy / Redir / NFQueue\n SingBox->>WAN: Processed / Encrypted / Desynchronized Outbound\n end\n```\n\n---\n\n## 2. nftables Table Structure (`inet TachyonTable`)\n\nTachyon encapsulates all its firewall rules inside a dedicated table `inet TachyonTable`. This ensures clean isolation from the system `inet fw4` firewall.\n\n### 2.1. Key Chains\n\n1. **`dstnat` / `prerouting` (Hook `prerouting`, priority `-100` / `dstnat`)**:\n * Intercepts incoming LAN client packets before routing decisions.\n * Checks client MAC / IP exclusion lists.\n * Matches destination IP against `tachyon_bypass_v4` / `tachyon_target_v4` sets.\n * Performs TProxy redirect (`tproxy to :10080 meta mark set 0x10000000 accept`) or Port redirect.\n2. **`output` (Hook `output`, priority `-100`)**:\n * Intercepts router's own locally generated packets (e.g. DNS lookups, curl, router traffic).\n * Prevents self-interception loops (`meta skuid == \"tachyon\" return`).\n3. **`nfqueue_chain`**:\n * Directs packets destined for Zapret v1 / v2 to kernel NFQueue numbers (`queue num 200`, `queue num 201`).","embedding":[]},{"id":9,"file":"03_NETWORKING_NFTABLES_AND_ROUTING.md","heading":"3.3. Bootstrap DNS Dead-Lock Prevention","text":"* Prevents self-interception loops (`meta skuid == \"tachyon\" return`).\n3. **`nfqueue_chain`**:\n * Directs packets destined for Zapret v1 / v2 to kernel NFQueue numbers (`queue num 200`, `queue num 201`).\n\n### 2.2. Bitmask & Firewall Marks\n\n| Mark Value | Meaning | Action |\n|---|---|---|\n| `0x10000000` | Redirected to sing-box TProxy | Routed to local loopback via table 100 |\n| `0x20000000` | Processed by Zapret / NFQueue | Dispatched to nfqws daemon |\n| `0x40000000` | Marked for ByeDPI SOCKS | Forwarded to local SOCKS redirect |\n| `0x80000000` | Bypass marker (Direct WAN) | Accepted immediately without inspection |\n\n---\n\n## 3. DNS Architecture & Interception\n\n### 3.1. DNS Resolution Pipeline\n\n```\n[LAN Client DNS Query: 53]\n │\n ▼\n [dnsmasq / Router]\n │\n ├─► If Domain in Direct / RuNet / Local ──► Local Upstream DNS (ISP / DoH)\n │\n ├─► If Domain in Hosts Section ──────────► Static IP from dns_hosts\n │\n └─► If Domain in Target Proxy / Desync ──► sing-box DNS (127.0.0.1:5353)\n │\n ▼\n [Remote Secure DoH/DoT]\n [Populates nftables set]\n```\n\n### 3.2. Dynamic nftables Set Population (`nftset`)\n* When dnsmasq resolves a domain associated with a proxy or Zapret rule, it automatically adds the resolved IP address to the corresponding kernel nftables set (e.g. `tachyon_target_v4`).\n* This enables sub-millisecond, line-rate packet redirection without re-evaluating domain names in user-space for every packet.\n\n### 3.3. Bootstrap DNS Dead-Lock Prevention\n* A critical failure mode in proxy routers is a **DNS loop**: sing-box needs to resolve the VPS hostname (e.g. `vps.example.com`), but its own DNS resolver routes queries through sing-box, which is not yet connected.","embedding":[]},{"id":10,"file":"03_NETWORKING_NFTABLES_AND_ROUTING.md","heading":"4.1. Emergency Internet Restoration Mechanism","text":"* A critical failure mode in proxy routers is a **DNS loop**: sing-box needs to resolve the VPS hostname (e.g. `vps.example.com`), but its own DNS resolver routes queries through sing-box, which is not yet connected.\n* **Tachyon's Solution**:\n * Dedicated `direct_resolvers` (Cloudflare `1.1.1.1`, Google `8.8.8.8`) bypass all proxy rules.\n * Local Rule Doctor monitors bootstrap DNS reachability and automatically executes `fix_bootstrap_dns` if a circular dependency is detected.\n\n---\n\n## 4. Policy Routing (`ip rule` & Routing Tables)\n\nTachyon provisions routing table `100`:\n```sh\n# Routing rule for marked packets\nip rule add fwmark 0x10000000/0x10000000 lookup 100 priority 10000\n\n# Local loopback route in table 100\nip route add local default dev lo table 100\n```\n\n### 4.1. Emergency Internet Restoration Mechanism\nWhen `tachyon restore_native_internet` is triggered:\n1. `inet TachyonTable` is atomically deleted: `nft delete table inet TachyonTable`.\n2. Policy routing rule `ip rule del lookup 100` is removed.\n3. dnsmasq configuration is reverted to native upstream forwarders.\n4. sing-box process is stopped cleanly.\n5. Result: Full, native WAN connectivity is restored in under 200 ms without rebooting the router.","embedding":[]},{"id":11,"file":"04_DPI_BYPASS_ENGINES.md","heading":"2.1. Основные стратегии обхода","text":"# 04. Движки обхода DPI и десинхронизации пакетов\n\nTachyon интегрирует три независимых локальных движка десинхронизации сетевых пакетов, которые функционируют непосредственно на оборудовании роутера без необходимости использования внешнего VPS или прокси-сервера (режим «Zero-VPS»).\n\n---\n\n## 1. Сравнительная матрица: Zapret v1 vs Zapret v2 vs ByeDPI\n\n| Параметр | Zapret v1 (`nfqws`) | Zapret v2 (`nfqws2`) | ByeDPI (`ciadpi`) |\n|---|---|---|---|\n| **Исполняемый файл** | `/usr/bin/nfqws` | `/usr/bin/nfqws2` | `/usr/bin/ciadpi` |\n| **Модель работы** | Перехват через Kernel NFQueue | Multi-Queue NFQueue с Lua | Локальный SOCKS5 / TProxy |\n| **Целевые протоколы** | HTTP, TLS (ClientHello) | HTTP, TLS, QUIC, WireGuard, UDP | HTTP, TLS |\n| **Методы фрагментации** | `split2`, `disorder`, `fake` | `multisplit`, `seqovl`, `wsize`, `fake` | `--split-pos`, `--disorder`, `--fake` |\n| **Многоуровневые цепочки** | 1 стратегия на правило | Сложные составные цепочки | Составные аргументы SOCKS |\n| **Нагрузка на CPU** | Минимальная (< 1%) | Низкая (< 2%) | Низкая (< 2%) |\n| **Оптимально для** | Базового DPI, старых роутеров | YouTube 4K, Discord, ТСПУ | Не-root окружений, SOCKS-роутинга |\n\n---\n\n## 2. Принципы и техники десинхронизации пакетов\n\nСистемы глубокого анализа пакетов (DPI / ТСПУ) анализируют заголовки сетевых протоколов (такие как `SNI` в расширении TLS ClientHello или заголовок `Host` в HTTP) для блокировки или замедления трафика. \n\nДесинхронизация обманывает конечный автомат DPI, заставляя его потерять контекст TCP-сессии или пропустить целевой заголовок, в то время как целевой сервер корректно собирает исходный поток данных.\n\n```\nИсходный поток: [TLS ClientHello с SNI] ──────────► (Блокируется ТСПУ / DPI)\n\nДесинхронизация: [Fake-пакет с неверной суммой/TTL] ──► (DPI сбрасывает состояние)\n [Фрагмент 1: Начало ClientHello] ───► (DPI не видит полный SNI)\n [Фрагмент 2: Окончание данных] ─────► (Сервер собирает TCP-поток)\n```\n\n### 2.1. Основные стратегии обхода","embedding":[]},{"id":12,"file":"04_DPI_BYPASS_ENGINES.md","heading":"3.1. Пример настройки Zapret v2 (`/etc/config/tachyon`)","text":"[Фрагмент 1: Начало ClientHello] ───► (DPI не видит полный SNI)\n [Фрагмент 2: Окончание данных] ─────► (Сервер собирает TCP-поток)\n```\n\n### 2.1. Основные стратегии обхода\n\n1. **`split2` / `multisplit` (Многопозиционное разделение)**:\n * Разрезает TCP-сегмент непосредственно внутри поля TLS SNI или заголовка HTTP Host. Оборудование DPI не выполняет глубокую реассемблинг-сборку мелких фрагментов, а стек TCP целевого сервера склеивает поток без потерь.\n2. **`disorder` / `disorder2` (Изменение порядка доставки)**:\n * Отправляет вторую часть пакета раньше первой с корректными TCP Sequence Numbers. DPI видит фрагменты не по порядку и пропускает инспекцию.\n3. **`fake` / `fake_sni` (Внедрение фейковых пакетов)**:\n * Отправляет поддельный пакет TLS ClientHello с намеренно заниженным TTL (Time To Live). DPI перехватывает поддельный пакет и считает соединение легитимным, после чего пакет угасает в сети, не доходя до целевого сервера.\n4. **`seqovl` (Наложение порядковых номеров / Sequence Overlap)**:\n * Посылает пакет с перекрывающимся диапазоном TCP Sequence. Стек TCP на сервере отбрасывает дублирующиеся байты, тогда как DPI парсит неверные данные и теряет контроль над сессией.\n5. **`wsize` (Манипуляция размером окна TCP Window Size)**:\n * Принудительно устанавливает размер TCP-окна в 1–2 байта, заставляя клиент слать данные микросегментами, что ломает эвристики DPI.\n\n---\n\n## 3. Конфигурация и управление в UCI\n\n### 3.1. Пример настройки Zapret v2 (`/etc/config/tachyon`)\n\n```ini\nconfig provider 'zapret2'\n option enabled '1'\n option daemon_bin '/usr/bin/nfqws2'\n option qnum '201'\n option args_tcp '--dpi-desync=multisplit --dpi-desync-split-pos=1,midsld --dpi-desync-seqovl=1 --dpi-desync-fooling=badseq'\n option args_udp '--dpi-desync=fake --dpi-desync-any-protocol=1 --dpi-desync-cutoff=d4'\n\nconfig rule 'youtube_rule'\n option enabled '1'\n option name 'YouTube 4K Desync'\n option action 'zapret2'\n list domain_pattern 'googlevideo.com'","embedding":[]},{"id":13,"file":"04_DPI_BYPASS_ENGINES.md","heading":"5. Интеграция AmneziaWG в sing-box-extended (2026)","text":"option args_udp '--dpi-desync=fake --dpi-desync-any-protocol=1 --dpi-desync-cutoff=d4'\n\nconfig rule 'youtube_rule'\n option enabled '1'\n option name 'YouTube 4K Desync'\n option action 'zapret2'\n list domain_pattern 'googlevideo.com'\n list domain_pattern 'youtube.com'\n list domain_pattern 'ytimg.com'\n list domain_pattern 'discord.gg'\n list domain_pattern 'discord.com'\n```\n\n### 3.2. Пример настройки ByeDPI\n\n```ini\nconfig provider 'byedpi'\n option enabled '1'\n option daemon_bin '/usr/bin/ciadpi'\n option listen_ip '127.0.0.1'\n option listen_port '1080'\n option args '--split-pos 1 --disorder 1 --fake -1 --ttl 8'\n```\n\n---\n\n## 4. Мультиплексирование NFQueue и изоляция очередей\n\n* Подсистема ядра Linux `nfnetlink_queue` требует уникальный номер очереди (`qnum`) для каждого запущенного процесса демона.\n* Модуль `providers/nfqueue/runtime.uc` в Tachyon динамически управляет выделением очередей:\n * Базовая очередь Zapret v1: `200`\n * Базовая очередь Zapret v2: `201`\n * Очередь Strategy Fuzzer: `298` / `299`\n* При одновременной активации Zapret v1 и Zapret v2 для разных правил маршрутизации Tachyon гарантирует строгую изоляцию очередей и исключает конфликты PID и fwmark.\n\n---\n\n## 5. Интеграция AmneziaWG в sing-box-extended (2026)\n\nПроверено против релизного бинарника `v1.13.18-extended-2.6.5` (`shtorm-7/sing-box-extended`):\n\n- Секция `endpoint.amnezia` полностью реализована в форке: `AmneziaOptions` (`transport/wireguard/endpoint_options.go`) → параметры IPC `jc / jmin / jmax / s1-s4 / h1-h4 / i1-i5`.\n- Форк `shtorm-7/wireguard-go v0.0.4-extended-1.5.3`: пакеты `I1–I5` отправляются отдельными дейтаграммами **перед** инициализацией рукопожатия (`SendHandshakeInitiation`), значение задается в hex-формате.\n- Генератор Tachyon (`singbox/generator_outbounds.uc` -> `add_awg_endpoint`) формирует конфигурацию, полностью совместимую со схемой форка:\n - Секция `peer` содержит обязательный `allowed_ips`.\n - Параметры `pre_shared_key` и `persistent_keepalive_interval` опциональны.","embedding":[]},{"id":14,"file":"04_DPI_BYPASS_ENGINES.md","heading":"Вывод доступной матрицы стратегий","text":"- Генератор Tachyon (`singbox/generator_outbounds.uc` -> `add_awg_endpoint`) формирует конфигурацию, полностью совместимую со схемой форка:\n - Секция `peer` содержит обязательный `allowed_ips`.\n - Параметры `pre_shared_key` и `persistent_keepalive_interval` опциональны.\n - Hex-значения `i1–i5` передаются через `uci_bin_to_hex` без повторного кодирования.\n- **Диагностика:** если AWG/WARP-туннель имеет состояние «TX есть, RX нет» на sing-box-extended, конфиг применен корректно — причина во внешней UDP-фильтрации провайдера или блокировке сервера.\n\n---\n\n## 6. Strategy Fuzzer и автоматический подбор стратегий\n\nTachyon включает встроенный модуль автоматического тестирования стратегий обхода — **Strategy Fuzzer & Auto-Tuner** (`diagnostics/fuzzer.uc`), который избавляет от необходимости вручную подбирать флаги `nfqws2` или `ciadpi`.\n\n### 6.1. Механизм работы\n- **Изолированный сэндбокс:** Тестирование выполняется через временные очереди `qnum 298/299` с сокетной меткой `0x08000000` (для Zapret) либо через локальный порт `127.0.0.1:11089` (для ByeDPI), не затрагивая активный домашний трафик.\n- **Метрический скоринг:** Замеряются время TLS-рукопожатия, TTFB (время до первого байта), битрейт загрузки чанка потокового видео (MB/s) и HTTP-код ответа.\n- **1-Click Apply:** Победившая стратегия мгновенно применяется к правилу YouTube/Discord или в глобальные параметры провайдера с автоматической перезагрузкой службы.\n\n### 6.2. Команды управления через CLI\n```sh\n# Запуск бенчмарка стратегий\ntachyon fuzzer_start [custom_url] [rule_section]\n\n# Просмотр текущего прогресса и результатов\ntachyon fuzzer_status\n\n# Остановка фонового бенчмарка\ntachyon fuzzer_stop\n\n# Применение выбранной стратегии в UCI\ntachyon fuzzer_apply \"\" [target_rule_or_global]\n\n# Вывод доступной матрицы стратегий\ntachyon fuzzer_strategies\n```","embedding":[]},{"id":15,"file":"05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md","heading":"3. Local Rule Doctor & 13 Quick Fix Codes","text":"# 05. AI Stack, AI Doctor & Autonomous Self-Healing\n\n## 1. Overview of Tachyon AI Stack\n\nTachyon provides a dual-layer AI and autonomous resilience stack:\n1. **Autonomous Layer (Local Rule Doctor & Watchdog)**: Runs locally on the router every 5–15 seconds, detects network drops, memory leaks, DNS deadlocks, and time desync without requiring internet access or API tokens.\n2. **Cognitive Layer (AI Doctor v2.5)**: Deep diagnostics powered by LLMs (OpenAI, Anthropic Claude, DeepSeek, or local Ollama/OpenRouter models) with contextual prompt enrichment and automated Multi-Fix generation.\n3. **Agent Integration Layer (HTTP REST Agent API & OpenAPI 3.0)**: Programmatic interface for autonomous AI agents (Cursor, Claude Code, AutoGPT, ChatGPT Custom GPTs, N8N, Dify).\n\n---\n\n## 2. AI Doctor Architecture (v2.5)\n\n```mermaid\ngraph TD\n subgraph Data Collection\n R1[Process Probes: singbox/zapret/dnsmasq]\n R2[Kernel Metrics: conntrack, mem, uptime]\n R3[Watchdog History: failure streaks, OOM events]\n R4[System Logs: 15 most recent critical lines]\n end\n\n R1 --> Aggregator[snapshot.uc Assembler]\n R2 --> Aggregator\n R3 --> Aggregator\n R4 --> Aggregator\n\n Aggregator --> Prompt[Deep Context LLM Prompt]\n Prompt --> LLM[LLM Provider: OpenAI / Claude / DeepSeek / Custom]\n \n LLM --> Verdict[Structured Diagnosis Report]\n LLM --> MultiFix[Multi-Fix Action Plan: FIX: code1, code2]\n \n MultiFix --> Exec[Local Rule Doctor Execution Engine]\n Exec --> Result[Applied Fixes & Service State Refresh]\n```\n\n---\n\n## 3. Local Rule Doctor & 13 Quick Fix Codes\n\nThe execution engine in `diagnostics/runtime.uc` maps standardized fix codes to automated shell/ucode repair procedures:\n\n| Code | Target Subsystem | Action Performed |\n|---|---|---|\n| `start_singbox` | sing-box | Restarts failed sing-box process via procd. |\n| `rebuild_rules` | nftables | Flushes and recompiles `inet TachyonTable` ruleset. |\n| `fix_dnsmasq` | dnsmasq | Restarts dnsmasq and checks `/tmp/etc/dnsmasq.conf.*`. |","embedding":[]},{"id":16,"file":"05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md","heading":"4.1. Authentication Model","text":"| `start_singbox` | sing-box | Restarts failed sing-box process via procd. |\n| `rebuild_rules` | nftables | Flushes and recompiles `inet TachyonTable` ruleset. |\n| `fix_dnsmasq` | dnsmasq | Restarts dnsmasq and checks `/tmp/etc/dnsmasq.conf.*`. |\n| `fix_resolv_symlink` | DNS | Restores broken `/etc/resolv.conf` -> `/tmp/resolv.conf.d/resolv.conf.auto` link. |\n| `start_watchdog` | Watchdog | Restarts the background watchdog supervisor process. |\n| `restart_singbox_dns` | sing-box DNS | Resets internal sing-box DNS server module and cache. |\n| `fix_uci_config` | UCI | Restores `/etc/config/tachyon` from the latest valid atomic backup. |\n| `fix_wan_interface` | Networking | Runs `ifup wan` to bounce the primary uplink interface. |\n| `fix_gateway` | Networking | Re-establishes default routing gateway via `/etc/init.d/network restart`. |\n| `clear_dns_cache` | Cache | Flushes dnsmasq cache, deletes sing-box `cache.db`, and restarts DNS. |\n| `update_subscriptions`| Subscriptions | Triggers asynchronous background download and refresh of proxy subscriptions. |\n| `reset_firewall` | Firewall | Full restart of OpenWrt firewall (`/etc/init.d/firewall restart`). |\n| `restart_network` | Network Stack | Full restart of OpenWrt network daemon (`/etc/init.d/network restart`). |\n| `fix_system_time` | System NTP | Resynchronizes router clock via NTP pool servers (`ntpd -q -p ...`). |\n| `flush_conntrack` | Kernel | Flushes congested `nf_conntrack` table during connection floods. |\n| `fix_bootstrap_dns` | Resolver | Unblocks sing-box primary bootstrap resolvers and breaks circular loops. |\n| `optimize_mtu` | Tunnels | Auto-calculates optimal MTU (1280–1420) for WireGuard / AmneziaWG interfaces. |\n| `restore_native_internet` | Emergency | One-click full teardown of Tachyon proxying; returns pure native WAN routing. |\n\n---\n\n## 4. HTTP REST Agent API & OpenAPI 3.0.3\n\nTachyon exposes a standardized REST API hosted under `/cgi-bin/tachyon-agent/` via OpenWrt's native `uhttpd`.\n\n### 4.1. Authentication Model","embedding":[]},{"id":17,"file":"05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md","heading":"4.3. Full Endpoint Index","text":"| `restore_native_internet` | Emergency | One-click full teardown of Tachyon proxying; returns pure native WAN routing. |\n\n---\n\n## 4. HTTP REST Agent API & OpenAPI 3.0.3\n\nTachyon exposes a standardized REST API hosted under `/cgi-bin/tachyon-agent/` via OpenWrt's native `uhttpd`.\n\n### 4.1. Authentication Model\n* **Read-Only Endpoints**: Accessible within LAN without authentication (or secured via firewall).\n* **Write Endpoints**: Require Bearer token authentication:\n ```http\n POST /cgi-bin/tachyon-agent/ai-doctor/fix\n Authorization: Bearer \n Content-Type: application/json\n\n {\"fix\": \"clear_dns_cache,start_singbox\"}\n ```\n\n### 4.2. OpenAPI 3.0.3 Specification\n* The live OpenAPI JSON schema is available at:\n ```\n GET /cgi-bin/tachyon-agent/openapi.json\n ```\n* This schema allows instant import into **ChatGPT Custom GPT Actions**, **N8N HTTP Request Nodes**, **Dify**, and **Flowise**.\n\n### 4.3. Full Endpoint Index\n\n| Method | Endpoint | Auth Required | Description |\n|---|---|---|---|\n| `GET` | `/health` | No | Lightweight JSON health status probe. |\n| `GET` | `/snapshot` | No | Full system snapshot (interfaces, memory, proxy status). |\n| `GET` | `/diagnose` | No | Local Rule Doctor diagnosis report. |\n| `GET` | `/logs` | No | Returns last 100 lines of Tachyon system log. |\n| `GET` | `/config` | No | Returns sanitized UCI configuration. |\n| `GET` | `/tools` | No | OpenAI Function Calling / MCP tool definitions. |\n| `GET` | `/openapi.json` | No | OpenAPI 3.0.3 specification JSON. |\n| `POST`| `/heal` | **Bearer** | Triggers manual Watchdog self-healing cycle. |\n| `POST`| `/ai-doctor/fix` | **Bearer** | Applies one or more quick-fix codes. |\n| `POST`| `/restart` | **Bearer** | Restarts specified service (`singbox`, `watchdog`, `dnsmasq`). |\n| `POST`| `/reload` | **Bearer** | Soft-reloads configuration and routing tables. |\n| `POST`| `/config/set` | **Bearer** | Updates specific UCI options. |\n| `POST`| `/section/toggle` | **Bearer** | Enables or disables a routing rule section. |","embedding":[]},{"id":18,"file":"05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md","heading":"4.3. Full Endpoint Index","text":"| `POST`| `/reload` | **Bearer** | Soft-reloads configuration and routing tables. |\n| `POST`| `/config/set` | **Bearer** | Updates specific UCI options. |\n| `POST`| `/section/toggle` | **Bearer** | Enables or disables a routing rule section. |\n| `POST`| `/domain/add` | **Bearer** | Appends domain pattern to target rule list. |","embedding":[]},{"id":19,"file":"06_FRONTEND_LUCI_TYPESCRIPT.md","heading":"3.1. Key Services (`src/tachyon/services/`)","text":"# 06. Frontend Architecture (LuCI & TypeScript)\n\n## 1. Frontend Architecture Overview\n\nTachyon's web UI is authored as a single-page application in **TypeScript** under `fe-app-tachyon/` and compiled into a standalone JavaScript view under `luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/main.js`.\n\n```\nfe-app-tachyon/ (TypeScript Source)\n │\n ▼ (npm run build: tsc --noEmit && tsup)\n │\n[tsup build + baseclass.extend transformation]\n │\n ▼\nluci-app-tachyon/htdocs/luci-static/resources/view/tachyon/main.js (LuCI Asset)\n```\n\n---\n\n## 2. The LuCI `baseclass.extend()` Patch Mechanism\n\nLuCI uses a custom asynchronous class system (`baseclass.extend({...})`) rather than standard ES modules or Webpack bundles.\n\n* `fe-app-tachyon/tsup.config.ts` compiles the TypeScript entry point (`src/main.ts`) into an ES module.\n* A custom post-processing step inside `tsup.config.ts` transforms the compiled file:\n 1. Strips ESM `export default` statements.\n 2. Wraps the controller inside LuCI's expected `return baseclass.extend({...})` pattern.\n 3. Injects global LuCI helper references (`ui`, `rpc`, `uci`, `fs`, `_`).\n\n> [!IMPORTANT]\n> **Do not attempt to convert `main.js` back into a standard ES module export.** This LuCI bridge is intentional and strictly required for compatibility with all OpenWrt web themes (Bootstrap, Material, Argon, OpenWrt-Two).\n\n---\n\n## 3. Reactive State Management & Services\n\nThe frontend does not use heavy external frameworks (like React or Vue) to keep package size minimal ($\\approx$ 500 KB uncompressed, $\\approx$ 90 KB gzipped). Instead, it uses lightweight TypeScript observable stores:\n\n### 3.1. Key Services (`src/tachyon/services/`)\n\n| Service | File | Purpose |\n|---|---|---|\n| `StoreService` | `store.service.ts` | Central reactive data store with subscription listeners. |\n| `UiStateService` | `uiState.service.ts` | Tracks UI view state, tab switching, and modal states. |\n| `RuntimeUiStateService`| `runtimeUiState.service.ts`| Polling and caching of backend service metrics and active jobs. |","embedding":[]},{"id":20,"file":"06_FRONTEND_LUCI_TYPESCRIPT.md","heading":"4.1. The Updates & Installation Modal (`renderUpdateProgressModal.ts`)","text":"| `UiStateService` | `uiState.service.ts` | Tracks UI view state, tab switching, and modal states. |\n| `RuntimeUiStateService`| `runtimeUiState.service.ts`| Polling and caching of backend service metrics and active jobs. |\n| `SocketService` | `socket.service.ts` | WebSocket client for real-time log streaming when available. |\n| `TachyonLogWatcher` | `tachyonLogWatcher.service.ts`| Logread stream deduplication and notification dispatcher. |\n\n---\n\n## 4. Tabs & UI View Structure\n\n```\nsrc/tachyon/tabs/\n├── dashboard/ # Live status, RTT ping matrix, traffic toggles\n├── diagnostic/ # AI Doctor modal, Local Rule Doctor, Emergency Fallback\n├── rules/ # Selective routing rules, domain/IP lists, client matchers\n├── providers/ # Zapret v1, Zapret v2, ByeDPI configurations\n├── updates/ # Component installer, version checks, streaming log modal\n└── settings/ # DNS settings, Telegram bot credentials, AI Doctor API keys\n```\n\n### 4.1. The Updates & Installation Modal (`renderUpdateProgressModal.ts`)\n* Provides a streaming log console that polls `/usr/bin/tachyon` output asynchronously via `componentActionLog(jobId, offset)`.\n* Features:\n * Non-blocking operation: router performs installation in background.\n * Real-time timer and progress badge.\n * Preserves output logs and green success/red error banners.\n * Prevents premature auto-close so users can inspect package manager details.\n * Graceful countdown timer for Tachyon package reloads.","embedding":[]},{"id":21,"file":"07_BUILD_TESTS_AND_DEPLOYMENT.md","heading":"2.1. Installer Lifecycle","text":"# 07. Build System, Testing & Deployment Pipeline\n\n## 1. Release Package Compilation (`build.sh`)\n\nTachyon produces both legacy **IPK** (opkg) and modern **APK** (apk-tools, OpenWrt 25.x+) packages.\n\n### 1.1. Running the Build\n\n```bash\nbash build.sh [output-dir]\n```\n\n* **Semver Requirement**: `build.sh` strictly enforces semantic versioning (`x.y.z`).\n* **Cross-Filesystem WSL Protection**: When executed under Windows Subsystem for Linux (WSL), `build.sh` automatically clones the source repository into the native Linux filesystem (`/tmp/tachyon-build-...`) before packaging to avoid Windows filesystem metadata and permission corruption.\n* **Outputs**:\n * `dist/release-final/tachyon__all.ipk`\n * `dist/release-final/luci-app-tachyon__all.ipk`\n * `dist/release-final/tachyon-.apk`\n * `dist/release-final/luci-app-tachyon-.apk`\n\n---\n\n## 2. End-User Installer (`install.sh`)\n\nTachyon provides an automated one-liner installer:\n\n```bash\nwget -O /tmp/tachyon-setup.sh https://raw.githubusercontent.com/Dushnilin/tachyon/main/install.sh && sh /tmp/tachyon-setup.sh\n```\n\n### 2.1. Installer Lifecycle\n1. **Architecture & OS Detection**: Detects OpenWrt version (23.05, 24.10, 25.x, SNAPSHOT), CPU architecture (`mips`, `mipsel`, `arm_cortex-a7`, `aarch64_cortex-a53`, `x86_64`), and package manager (`opkg` vs `apk`).\n2. **Dependency Resolution**: Ensures `ucode`, `ucode-mod-fs`, `ucode-mod-uci`, `ucode-mod-ubus`, `kmod-nft-tproxy`, `kmod-nft-queue`, `ca-bundle` are installed.\n3. **Legacy Migration**: Automatically detects `/etc/config/forkop` or `/etc/config/podkop` and seamlessly migrates all rules and servers to `/etc/config/tachyon`.\n4. **Binary Provisioning**: Downloads pre-compiled, optimized sing-box, Zapret, or ByeDPI binaries tailored for the router's target architecture.\n5. **Zero-Reboot Initialization**: Configures UCI defaults, registers LuCI menus, builds initial rulesets, and starts services without requiring a full router reboot.","embedding":[]},{"id":22,"file":"07_BUILD_TESTS_AND_DEPLOYMENT.md","heading":"4. Key Developer Gotchas & Conventions","text":"4. **Binary Provisioning**: Downloads pre-compiled, optimized sing-box, Zapret, or ByeDPI binaries tailored for the router's target architecture.\n5. **Zero-Reboot Initialization**: Configures UCI defaults, registers LuCI menus, builds initial rulesets, and starts services without requiring a full router reboot.\n\n---\n\n## 3. Testing Workflows\n\n### 3.1. Frontend Unit Tests (vitest)\n\n```bash\ncd fe-app-tachyon\nnpm test # Runs all 522+ vitest unit tests\nnpm run build # Verifies TypeScript compilation and LuCI bundle packaging\n```\n\n### 3.2. Backend Integration Tests & ucode Syntax Linting\n\nBackend tests require the `ucode` binary. On development machines without local ucode, tests run inside the Docker CI image:\n\n```bash\n# 1. ucode syntax check across all 60+ modules\ndocker run --rm -v \"$(pwd):/mnt\" -w /mnt ucode-ci-img:latest bash tests/ucode_syntax_lint.sh\n\n# 2. Run all backend behavioral and unit tests in parallel (-P4)\ndocker run --rm -v \"$(pwd):/mnt\" -w /mnt ucode-ci-img:latest bash tests/run_all.sh\n\n# 3. Run a specific test\ndocker run --rm -v \"$(pwd):/mnt\" -w /mnt ucode-ci-img:latest bash tests/ai_doctor_local.sh\n```\n\n### 3.3. ShellCheck Linting\n\n```bash\nshellcheck --severity=error build.sh install.sh tachyon/files/etc/init.d/* tests/**/*.sh\n```\n\n---\n\n## 4. Key Developer Gotchas & Conventions\n\n1. **LF Line Endings**: Enforced via `.gitattributes`. Committing CRLF will break shell scripts on OpenWrt target systems.\n2. **`fe-app-tachyon` Package Manager**: Always use `npm` (`npm install`, `npm test`, `npm run build`), not `yarn`.\n3. **Version Placeholder**: `__COMPILED_VERSION_VARIABLE__` in `src/constants.ts` is replaced during `build.sh` packaging. Do not remove it.\n4. **UCI Config Permissions**: `/etc/config/tachyon` must remain `chmod 600` because it can store sensitive Telegram bot tokens and API keys.","embedding":[]},{"id":23,"file":"08_UCI_CONFIGURATION_SCHEMA.md","heading":"1. Section: `config settings 'settings'`","text":"# 08. Complete UCI Configuration Schema Reference\n\nThe primary configuration for Tachyon is stored at `/etc/config/tachyon` (UCI format, mode `0600`).\n\n---\n\n## 1. Section: `config settings 'settings'`\n\nGlobal settings defining service behaviour, DNS resolution, watchdog parameters, Telegram integration, and AI Doctor.\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `enabled` | `boolean` (`0`/`1`) | `1` | Master toggle for Tachyon service. |\n| `log_level` | `string` | `info` | Logging verbosity: `debug`, `info`, `warn`, `error`. |\n| `dns_mode` | `string` | `doh` | DNS routing mode: `direct`, `doh`, `dot`, `udp`, `hosts_only`. |\n| `remote_dns_server` | `string` | `https://1.1.1.1/dns-query` | Upstream secure DNS resolver for proxied domains. |\n| `direct_dns_server` | `string` | `77.88.8.8` | Fallback DNS resolver for direct / local domains. |\n| `tproxy_port` | `integer` | `10080` | Local TCP/UDP transparent proxy port for sing-box. |\n| `dns_port` | `integer` | `5353` | Local DNS listening port for sing-box DNS engine. |\n| `clash_api_port` | `integer` | `9090` | sing-box Clash REST API controller port. |\n| `clash_api_secret` | `string` | `\"\"` | Secret token for sing-box Clash API. |\n| `watchdog_interval` | `integer` | `10` | Watchdog polling interval in seconds (5–60s). |\n| `memory_limit_mb` | `integer` | `0` | Dynamic `GOMEMLIMIT` cap in MB (`0` = auto 50% free RAM). |\n| `enable_telegram` | `boolean` | `0` | Enable interactive Telegram management bot. |\n| `telegram_token` | `string` | `\"\"` | Telegram Bot API token from `@BotFather`. |\n| `telegram_chat_id` | `string` | `\"\"` | Allowed Admin Telegram Chat ID(s) (comma-separated). |\n| `enable_ai_doctor` | `boolean` | `0` | Enable LLM AI Doctor diagnostic engine. |\n| `ai_doctor_provider`| `string` | `openai` | LLM Provider: `openai`, `anthropic`, `deepseek`, `custom`. |\n| `ai_doctor_model` | `string` | `\"\"` | Model override (e.g. `gpt-4o-mini`, `claude-3-5-haiku`). |\n| `ai_doctor_api_key`| `string` | `\"\"` | API key for the chosen LLM provider. |","embedding":[]},{"id":24,"file":"08_UCI_CONFIGURATION_SCHEMA.md","heading":"2. Section: `config server 'name'`","text":"| `ai_doctor_provider`| `string` | `openai` | LLM Provider: `openai`, `anthropic`, `deepseek`, `custom`. |\n| `ai_doctor_model` | `string` | `\"\"` | Model override (e.g. `gpt-4o-mini`, `claude-3-5-haiku`). |\n| `ai_doctor_api_key`| `string` | `\"\"` | API key for the chosen LLM provider. |\n| `ai_doctor_custom_url`| `string` | `\"\"` | Custom OpenAI-compatible endpoint URL (e.g. OpenRouter/Ollama). |\n| `agent_api_token` | `string` | `\"\"` | Bearer token for HTTP REST Agent API write access. |\n\n---\n\n## 2. Section: `config server 'name'`\n\nDefines an individual manual proxy outbound node.\n\n| Option | Type | Required | Description |\n|---|---|---|---|\n| `type` | `string` | Yes | Protocol: `vless`, `vmess`, `shadowsocks`, `trojan`, `hysteria2`, `wireguard`. |\n| `server` | `string` | Yes | Remote server hostname or IPv4/IPv6 address. |\n| `server_port` | `integer` | Yes | Remote server port (e.g. `443`, `8443`). |\n| `uuid` | `string` | Conditional | User UUID for VLESS / VMess. |\n| `password` | `string` | Conditional | Password for Shadowsocks / Trojan / Hysteria2. |\n| `flow` | `string` | No | Flow control: `xtls-rprx-vision` (VLESS). |\n| `security` | `string` | No | Security type: `reality`, `tls`, `none`. |\n| `sni` | `string` | Conditional | Server Name Indication for TLS / Reality. |\n| `pbk` | `string` | Conditional | Public Key for VLESS Reality. |\n| `sid` | `string` | Conditional | Short ID for VLESS Reality (hex string). |\n| `fingerprint` | `string` | No | TLS fingerprint: `chrome`, `firefox`, `safari`, `randomized`. |\n| `method` | `string` | Conditional | Cipher method for Shadowsocks (e.g. `2022-blake3-aes-128-gcm`). |\n| `routing_mode` | `string` | No | Routing mode: `rules` (default), `direct`, `section`. |\n| `routing_section` | `string` | No | Bound routing section when `routing_mode = 'section'`. |\n| `isolate_lan_for_users` | `boolean` | No | Restrict access to private/LAN IP addresses (`1` / `0`). |\n| `isolated_users` | `list string` | No | Specific usernames (`auth_user`) restricted from LAN. If empty, restricts all users of the inbound. |","embedding":[]},{"id":25,"file":"08_UCI_CONFIGURATION_SCHEMA.md","heading":"5. Section: `config hosts 'name'`","text":"| `isolate_lan_for_users` | `boolean` | No | Restrict access to private/LAN IP addresses (`1` / `0`). |\n| `isolated_users` | `list string` | No | Specific usernames (`auth_user`) restricted from LAN. If empty, restricts all users of the inbound. |\n| `isolated_subnets` | `list string` | No | Optional custom subnets to block for isolated users (defaults to `ip_is_private: true`). |\n| `custom_route_rules` | `list string` | No | Raw JSON sing-box route rule objects injected before general routing rules. |\n\n---\n\n## 3. Section: `config subscription 'name'`\n\nDefines a remote subscription URL for automated batch node fetching.\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `enabled` | `boolean` | `1` | Enable this subscription source. |\n| `url` | `string` | Required | HTTPS / HTTP link to subscription (Base64, Clash, SIP002). |\n| `update_interval`| `integer` | `86400` | Auto-update interval in seconds (default 24 hours). |\n| `custom_user_agent`| `string` | `\"\"` | Custom User-Agent header for subscription request. |\n| `filter_keywords` | `list string` | `[]` | Include nodes matching regex/keywords. |\n| `exclude_keywords`| `list string` | `[]` | Exclude nodes matching regex/keywords. |\n\n---\n\n## 4. Section: `config rule 'name'`\n\nDefines a selective routing policy.\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `enabled` | `boolean` | `1` | Enable this routing rule. |\n| `name` | `string` | `\"\"` | Human-readable label for UI. |\n| `action` | `string` | `proxy` | Route target: `proxy`, `zapret`, `zapret2`, `byedpi`, `direct`, `hosts`. |\n| `target_server` | `string` | `\"\"` | Bound server ID or outbound tag when `action = 'proxy'`. |\n| `domain_pattern` | `list string` | `[]` | List of target domains or wildcards (e.g. `*.youtube.com`). |\n| `ip_cidr` | `list string` | `[]` | List of IP subnets (e.g. `104.16.0.0/12`). |\n| `client_group` | `string` | `\"\"` | Restrict this rule to a specific client device group. |\n\n---\n\n## 5. Section: `config hosts 'name'`","embedding":[]},{"id":26,"file":"08_UCI_CONFIGURATION_SCHEMA.md","heading":"Recipe B: Hybrid Mode (Local Desync for Media + VLESS Reality for Blocked Sites)","text":"| `ip_cidr` | `list string` | `[]` | List of IP subnets (e.g. `104.16.0.0/12`). |\n| `client_group` | `string` | `\"\"` | Restrict this rule to a specific client device group. |\n\n---\n\n## 5. Section: `config hosts 'name'`\n\nConfigures static DNS overrides and remote blocklists ingestion.\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `enabled` | `boolean` | `1` | Enable hosts mapping. |\n| `dns_hosts` | `list string` | `[]` | Static mappings in format `domain:ip` (e.g. `example.com:1.2.3.4`). |\n| `hosts_list_urls` | `list string` | `[]` | External URLs for blocklists (AdAway, StevenBlack). |\n| `update_interval` | `integer` | `86400` | Auto-refresh interval in seconds. |\n\n---\n\n## 6. Ready-to-Use Configuration Recipes\n\n### Recipe A: Zero-VPS Local DPI Bypass (YouTube + Discord)\n```ini\nconfig settings 'settings'\n option enabled '1'\n option dns_mode 'doh'\n\nconfig provider 'zapret2'\n option enabled '1'\n option daemon_bin '/usr/bin/nfqws2'\n option qnum '201'\n option args_tcp '--dpi-desync=multisplit --dpi-desync-split-pos=1,midsld --dpi-desync-seqovl=1 --dpi-desync-fooling=badseq'\n\nconfig rule 'youtube_discord'\n option enabled '1'\n option name 'YouTube & Discord Local Desync'\n option action 'zapret2'\n list domain_pattern 'googlevideo.com'\n list domain_pattern 'youtube.com'\n list domain_pattern 'ytimg.com'\n list domain_pattern 'discord.com'\n list domain_pattern 'discord.gg'\n```\n\n### Recipe B: Hybrid Mode (Local Desync for Media + VLESS Reality for Blocked Sites)\n```ini\nconfig server 'my_vps'\n option type 'vless'\n option server 'vps.example.com'\n option server_port '443'\n option uuid '12345678-1234-1234-1234-123456789abc'\n option flow 'xtls-rprx-vision'\n option security 'reality'\n option sni 'yahoo.com'\n option pbk 'XYZ...PUBLIC_KEY...'\n option sid '1a2b3c4d'\n\nconfig rule 'media_rule'\n option enabled '1'\n option action 'zapret2'\n list domain_pattern 'youtube.com'\n list domain_pattern 'googlevideo.com'","embedding":[]},{"id":27,"file":"08_UCI_CONFIGURATION_SCHEMA.md","heading":"Recipe B: Hybrid Mode (Local Desync for Media + VLESS Reality for Blocked Sites)","text":"option pbk 'XYZ...PUBLIC_KEY...'\n option sid '1a2b3c4d'\n\nconfig rule 'media_rule'\n option enabled '1'\n option action 'zapret2'\n list domain_pattern 'youtube.com'\n list domain_pattern 'googlevideo.com'\n\nconfig rule 'blocked_rule'\n option enabled '1'\n option action 'proxy'\n option target_server 'my_vps'\n list domain_pattern 'instagram.com'\n list domain_pattern 'twitter.com'\n list domain_pattern 'x.com'\n```","embedding":[]},{"id":28,"file":"09_TELEGRAM_BOT_ARCHITECTURE.md","heading":"2. Command Set Reference","text":"# 09. Telegram Bot Architecture & Management Protocol\n\nTachyon includes an embedded, high-performance Telegram management bot written entirely in **ucode** (`service/telegram.uc`).\n\n---\n\n## 1. Architectural Highlights\n\n```mermaid\ngraph LR\n User[Telegram Client] -->|Encrypted HTTPS| TGAPI[Telegram Bot API Servers]\n TGAPI -->|Long Polling: getUpdates| Daemon[Tachyon telegram.uc Daemon]\n \n Daemon --> Auth{Admin Chat ID Match?}\n Auth -->|No| Reject[Silent Ignore / Warning]\n Auth -->|Yes| Router[Command & Callback Dispatcher]\n \n Router -->|/doctor, /ai_doctor| AIDoc[AI Doctor Engine]\n Router -->|/server, /switch| SrvMgr[Server Manager]\n Router -->|/restart| SvcLife[Service Lifecycle]\n Router -->|/status| StateRep[State Assembler]\n```\n\n* **No Public IP or Port Forwarding Required**: Uses outbound long-polling (`getUpdates` with 30s timeout) to securely communicate through NAT/firewalls.\n* **Zero Overhead Memory Footprint**: Runs as a lightweight ucode process consuming under 2 MB RAM.\n* **Role-Based Access Control**: Rejects any commands from chat IDs not explicitly listed in UCI option `telegram_chat_id`.\n\n---\n\n## 2. Command Set Reference\n\n| Command | Arguments | Action |\n|---|---|---|\n| `/start` | — | Displays main welcome card and interactive control keyboard. |\n| `/status` | — | Returns real-time health card: uptime, active server, RAM usage, ping RTT. |\n| `/doctor` | — | Executes Local Rule Doctor and returns offline diagnostic report. |\n| `/ai_doctor`| — | Invokes AI Doctor with LLM reasoning and returns diagnosis + fix buttons. |\n| `/fix` | `` | Applies specific automated repair code (e.g. `/fix clear_dns_cache`). |\n| `/server` | — | Opens interactive server selector with inline pagination and RTT pings. |\n| `/rules` | — | Shows active routing rules with 1-click toggle switches. |\n| `/restart` | `[service]` | Restarts sing-box, dnsmasq, watchdog, or entire network stack. |\n| `/backup` | — | Sends latest atomic configuration backup directly to Telegram chat. |","embedding":[]},{"id":29,"file":"09_TELEGRAM_BOT_ARCHITECTURE.md","heading":"Commit and restart service","text":"| `/rules` | — | Shows active routing rules with 1-click toggle switches. |\n| `/restart` | `[service]` | Restarts sing-box, dnsmasq, watchdog, or entire network stack. |\n| `/backup` | — | Sends latest atomic configuration backup directly to Telegram chat. |\n\n---\n\n## 3. Inline Keyboard & Callback Query Protocol\n\nThe bot uses dynamic inline keyboards (`InlineKeyboardMarkup`) for single-tap actions without typing commands.\n\n### 3.1. Callback Data Scheme\nCallbacks follow a structured token format: `action:target:param`\n\n```\nsrv:select:node_1 # Switch active proxy server to node_1\nrule:toggle:youtube # Toggle routing rule 'youtube' on/off\nfix:apply:clear_dns_cache# Execute repair code 'clear_dns_cache'\npage:srv:2 # Navigate to page 2 of server list\n```\n\n### 3.2. Example: Server Switcher Response\n\n```json\n{\n \"chat_id\": 123456789,\n \"text\": \"⚡ Выберите активный сервер:\\nТекущий: 🇩🇪 Frankfurt VLESS (18 ms)\",\n \"parse_mode\": \"HTML\",\n \"reply_markup\": {\n \"inline_keyboard\": [\n [\n {\"text\": \"🇩🇪 Frankfurt (18 ms) ✅\", \"callback_data\": \"srv:select:de_1\"},\n {\"text\": \"🇳🇱 Amsterdam (24 ms)\", \"callback_data\": \"srv:select:nl_1\"}\n ],\n [\n {\"text\": \"🇫🇮 Helsinki (31 ms)\", \"callback_data\": \"srv:select:fi_1\"},\n {\"text\": \"🇺🇸 New York (95 ms)\", \"callback_data\": \"srv:select:us_1\"}\n ],\n [\n {\"text\": \"🔄 Замерить пинг\", \"callback_data\": \"srv:ping:all\"},\n {\"text\": \"🩺 Запустить Доктора\", \"callback_data\": \"cmd:doctor\"}\n ]\n ]\n }\n}\n```\n\n---\n\n## 4. Configuration via CLI\n\n```sh\n# Set Bot Token\nuci set tachyon.settings.enable_telegram='1'\nuci set tachyon.settings.telegram_token='123456789:ABCdefGHIjklMNOpqrsTUVwxyz'\n\n# Set Authorized Chat ID(s)\nuci set tachyon.settings.telegram_chat_id='123456789'\n\n# Commit and restart service\nuci commit tachyon\n/etc/init.d/tachyon restart\n```","embedding":[]},{"id":30,"file":"10_HOSTS_ENGINE_AND_BLOCKLISTS.md","heading":"Example UCI Configuration:","text":"# 10. Hosts Engine, Blocklists & Smart Caching\n\nThe Hosts Engine (`components/hosts.uc`) provides automated background ingestion, normalization, deduplication, and caching of external host lists and static DNS overrides.\n\n---\n\n## 1. Architecture of Hosts Engine\n\n```mermaid\ngraph TD\n Sources[External Remote URLs: AdAway, StevenBlack, Custom] --> Downloader[HTTP Fetcher with Mirror Retry]\n Static[Static dns_hosts in UCI] --> Downloader\n \n Downloader --> Parser[Multi-Format Parser: Hosts, AdBlock, Domains]\n Parser --> Deduper[Deduplication & Sorting Engine]\n Deduper --> Cache[Unified Cache: /tmp/tachyon/hosts/combined.txt]\n \n Cache --> DNSMasq[dnsmasq /etc/dnsmasq.d/tachyon-hosts.conf]\n Cache --> SingboxDNS[sing-box DNS hosts rule]\n```\n\n---\n\n## 2. Multi-Format Ingestion\n\nThe parser automatically detects and normalizes multiple common blocklist formats:\n\n1. **Standard `/etc/hosts` format**:\n ```\n 0.0.0.0 ads.example.com\n 127.0.0.1 tracker.adserver.net\n ```\n2. **Domain-only list format**:\n ```\n malware-domain.org\n telemetry.app.com\n ```\n3. **AdBlock / DNSmasq syntax**:\n ```\n ||badsite.com^\n server=/blocked.com/\n address=/ads.org/0.0.0.0\n ```\n\n---\n\n## 3. GitHub Mirror Retry Resiliency\n\nWhen fetching blocklists hosted on GitHub (e.g. `raw.githubusercontent.com`), access may be blocked or throttled by regional DPI.\n\nTachyon implements an automated fallback retry chain:\n1. **Primary**: Direct HTTPS request to target URL.\n2. **Mirror 1**: `https://gh-proxy.com/`\n3. **Mirror 2**: `https://ghfast.top/`\n4. **Mirror 3**: `https://ghproxy.net/`\n\nIf direct connection fails with timeout or SSL handshake error, Tachyon transparently cycles through available mirrors before reporting an error.\n\n---\n\n## 4. Dedicated Hosts Routing (`action = 'hosts'`)\n\nTachyon supports routing sections that operate purely as DNS-overriding engines without requiring an outbound proxy association.\n\n### Example UCI Configuration:","embedding":[]},{"id":31,"file":"10_HOSTS_ENGINE_AND_BLOCKLISTS.md","heading":"Example UCI Configuration:","text":"## 4. Dedicated Hosts Routing (`action = 'hosts'`)\n\nTachyon supports routing sections that operate purely as DNS-overriding engines without requiring an outbound proxy association.\n\n### Example UCI Configuration:\n```ini\nconfig rule 'adblock_section'\n option enabled '1'\n option name 'AdBlock & Anti-Tracker'\n option action 'hosts'\n list hosts_list_urls 'https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts'\n list hosts_list_urls 'https://adaway.org/hosts.txt'\n```\n\n* Domains in this section are redirected directly to `0.0.0.0` or custom IPs in dnsmasq / sing-box DNS.\n* Zero traffic is routed to external proxies, preserving VPS bandwidth and minimizing latency.","embedding":[]},{"id":32,"file":"11_TROUBLESHOOTING_AND_FIELD_MANUAL.md","heading":"2. Run AI Doctor with LLM analysis","text":"# 11. Troubleshooting & Field Diagnostic Manual\n\nA comprehensive guide for diagnosing and resolving common network, proxy, and routing issues on OpenWrt routers running Tachyon.\n\n---\n\n## 1. Quick Emergency Recovery\n\nIf router traffic drops completely or DNS resolution is broken, use the **Emergency Native Internet Restoration** command:\n\n```sh\ntachyon restore_native_internet\n```\n\nThis performs the following actions in under 200 ms:\n1. Atomically drops all nftables interception tables (`nft delete table inet TachyonTable`).\n2. Clears policy routing `table 100` and `ip rule` entries.\n3. Restores dnsmasq to stock upstream forwarders.\n4. Stops sing-box and DPI bypass daemons without rebooting the router.\n\n---\n\n## 2. Symptom Resolution Matrix\n\n| Symptom | Likely Cause | Recommended Fix / Command |\n|---|---|---|\n| **Websites fail to open, ping to 8.8.8.8 works** | DNS loop or dnsmasq forwarder crash. | `tachyon apply_quick_fix clear_dns_cache,fix_dnsmasq` |\n| **YouTube 4K buffers indefinitely** | Zapret strategy out-of-date for current ISP. | Switch Zapret v2 strategy to `multisplit` with `seqovl=1`. |\n| **sing-box fails to start after config change** | Syntax error in custom outbound or invalid UUID. | Check `/var/log/tachyon_service.log` and run `tachyon doctor`. |\n| **System clock desynchronized, TLS fails** | Router rebooted without RTC battery, NTP desync. | `tachyon apply_quick_fix fix_system_time` |\n| **High latency or packet drop under heavy load** | Kernel `nf_conntrack` table overflow. | `tachyon apply_quick_fix flush_conntrack` |\n| **VLESS Reality connection timeout** | Reality SNI domain blocked or expired short ID. | Update server SNI to accessible target (e.g. `yahoo.com`). |\n| **Router runs out of RAM (OOM Crash)** | sing-box buffer explosion on low-RAM device (128 MB). | Lower `memory_limit_mb` in UCI settings (`GOMEMLIMIT=40MiB`). |\n\n---\n\n## 3. Diagnostic Commands Reference\n\n```sh\n# 1. Run local offline rule checks\ntachyon doctor\n\n# 2. Run AI Doctor with LLM analysis","embedding":[]},{"id":33,"file":"11_TROUBLESHOOTING_AND_FIELD_MANUAL.md","heading":"4. Log Inspection Paths","text":"| **Router runs out of RAM (OOM Crash)** | sing-box buffer explosion on low-RAM device (128 MB). | Lower `memory_limit_mb` in UCI settings (`GOMEMLIMIT=40MiB`). |\n\n---\n\n## 3. Diagnostic Commands Reference\n\n```sh\n# 1. Run local offline rule checks\ntachyon doctor\n\n# 2. Run AI Doctor with LLM analysis\ntachyon ai_doctor\n\n# 3. View real-time Watchdog telemetry\ntachyon ai_status_full\n\n# 4. Inspect active nftables firewall tables\nnft list table inet TachyonTable\n\n# 5. Inspect policy routing table 100\nip route show table 100\nip rule show\n\n# 6. Stream live Tachyon system logs\nlogread -f -e tachyon\n\n# 7. Check listening ports (TProxy 10080, DNS 5353, Clash 9090)\nnetstat -tulpn | grep -E 'sing-box|tachyon|5353|10080'\n```\n\n---\n\n## 4. Log Inspection Paths\n\n| Log Location | Content Description |\n|---|---|\n| `/var/log/tachyon_service.log` | Core service lifecycle events (start, stop, reload). |\n| `/var/log/tachyon_watchdog.log` | Background supervisor health checks and loop warnings. |\n| `/tmp/ai_doctor_last.json` | JSON report of the most recent AI Doctor diagnosis. |\n| `/tmp/tachyon/sing-box.json` | Generated live configuration compiled for sing-box. |\n| `/tmp/tachyon/hosts/combined.txt` | Consolidated deduplicated hosts list. |","embedding":[]},{"id":34,"file":"12_UCODE_PROGRAMMING_PATTERNS.md","heading":"2.3. Safe Error Handling (`try-catch`)","text":"# 12. ucode Programming Patterns & Conventions\n\nA developer's guide to writing safe, high-performance, and idiomatic **ucode** modules for Tachyon on OpenWrt.\n\n---\n\n## 1. ucode vs JavaScript: Critical Distinctions\n\nWhile ucode syntax resembles JavaScript, its runtime semantics differ significantly:\n\n1. **Variables & Scope**:\n * Always declare variables with `let` or `const`.\n * Unassigned variables are `null` (not `undefined`).\n2. **Arrays vs Dictionaries**:\n * Arrays: `[1, 2, 3]`. Iterated with `for (let item in array)`.\n * Dictionaries (Objects): `{\"key\": \"value\"}`. Iterated with `for (let key, val in dict)`.\n3. **Regular Expressions**:\n * Use `match(str, /regex/)` or `replace(str, /regex/g, \"replacement\")`.\n * Global flag `/g` works with `replace()`, while `match()` returns capture groups array `[full_match, group1, ...]`.\n4. **Boolean Coercion**:\n * Empty strings `\"\"`, `0`, and `null` are falsy. Everything else is truthy.\n\n---\n\n## 2. Mandatory Core Design Patterns\n\n### 2.1. Atomic Configuration Writes\nNever overwrite active configuration files in-place. Always write to a temporary file in `/tmp/` and atomically rename:\n\n```ucode\nlet fs = require(\"fs\");\n\nfunction write_atomic(path, content) {\n let tmp_path = path + \".tmp.\" + int(time());\n let f = fs.open(tmp_path, \"w\");\n if (!f) return false;\n \n f.write(content);\n f.close();\n \n return fs.rename(tmp_path, path);\n}\n```\n\n### 2.2. Shell Argument Quoting\nWhen executing external shell commands, all user inputs must be quoted safely:\n\n```ucode\nfunction shell_quote(value) {\n return \"'\" + replace(\"\" + value, /'/g, \"'\\\\''\") + \"'\";\n}\n\nfunction safe_exec(cmd_args) {\n let parts = [];\n for (let arg in cmd_args)\n push(parts, shell_quote(arg));\n return system(join(\" \", parts));\n}\n```\n\n### 2.3. Safe Error Handling (`try-catch`)\nAll external library loading or file parsing must be wrapped in `try-catch` blocks to avoid unhandled script panics:\n\n```ucode\nlet uci_data = null;","embedding":[]},{"id":35,"file":"12_UCODE_PROGRAMMING_PATTERNS.md","heading":"3. Performance & Memory Optimization Guidelines","text":"return system(join(\" \", parts));\n}\n```\n\n### 2.3. Safe Error Handling (`try-catch`)\nAll external library loading or file parsing must be wrapped in `try-catch` blocks to avoid unhandled script panics:\n\n```ucode\nlet uci_data = null;\ntry {\n let uci = require(\"uci\").cursor();\n uci_data = uci.get_all(\"tachyon\", \"settings\");\n}\ncatch (e) {\n warn(\"Failed to load UCI settings: \" + e + \"\\n\");\n}\n```\n\n---\n\n## 3. Performance & Memory Optimization Guidelines\n\n1. **Stream Large Files**: Avoid loading multi-megabyte blocklists entirely into RAM with `fs.readfile()`. Use line-by-line streaming via `fs.open()` and `f.read(\"line\")`.\n2. **Avoid Spawning Subprocesses in Loops**: Invoking `system()` or `fs.popen()` spawns a fork-exec sequence in Linux. Use native ucode functions for string manipulation and path operations whenever possible.\n3. **Keep Modules Stateless**: Module files under `usr/lib/tachyon/` should export reusable pure functions or class definitions rather than maintaining mutable global state.","embedding":[]},{"id":36,"file":"13_REST_API_AND_MCP_SPECIFICATION.md","heading":"4. Model Context Protocol (MCP) Tool Definitions","text":"# 13. HTTP REST Agent API & Model Context Protocol (MCP) Specification\n\nTachyon provides a standardized RESTful Agent API and Model Context Protocol (MCP) integration, enabling seamless orchestration by autonomous LLM agents (ChatGPT Actions, Claude Code, Cursor, Windsurf, N8N, Dify).\n\n---\n\n## 1. REST API Overview\n\n* **Base URL**: `http:///cgi-bin/tachyon-agent/`\n* **OpenAPI Schema**: `http:///cgi-bin/tachyon-agent/openapi.json`\n* **Content-Type**: `application/json`\n\n---\n\n## 2. Authentication Model\n\n1. **Read-Only Endpoints**: Unrestricted when accessed from local LAN.\n2. **Write Endpoints**: Require HTTP Authorization header:\n ```http\n Authorization: Bearer \n ```\n\n---\n\n## 3. Endpoint Reference & Payloads\n\n### 3.1. `GET /health`\nReturns lightweight status of all core daemons.\n```json\n{\n \"status\": \"healthy\",\n \"version\": \"1.2.86\",\n \"uptime_seconds\": 18450,\n \"singbox_running\": true,\n \"watchdog_running\": true,\n \"active_server\": \"Frankfurt_VLESS_Reality\"\n}\n```\n\n### 3.2. `GET /diagnose`\nReturns Local Rule Doctor checks and suggested repair codes.\n```json\n{\n \"status\": \"warning\",\n \"checks\": {\n \"dns_loop\": false,\n \"conntrack_full\": false,\n \"time_desync\": true,\n \"singbox_ok\": true\n },\n \"suggested_fixes\": [\"fix_system_time\"]\n}\n```\n\n### 3.3. `POST /ai-doctor/fix`\nApplies one or more quick-fix codes.\n* **Request**:\n ```json\n {\n \"fix\": \"clear_dns_cache,start_singbox\"\n }\n ```\n* **Response**:\n ```json\n {\n \"success\": true,\n \"applied_fixes\": [\"clear_dns_cache\", \"start_singbox\"],\n \"details\": \"DNS cache cleared. sing-box process restarted.\"\n }\n ```\n\n---\n\n## 4. Model Context Protocol (MCP) Tool Definitions\n\nFor MCP-compatible agents (Cursor, Claude Desktop), Tachyon exports tools via `GET /cgi-bin/tachyon-agent/tools`:\n\n```json\n[\n {\n \"name\": \"tachyon_diagnose\",\n \"description\": \"Run diagnostic checks on OpenWrt router network and proxy health\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {}","embedding":[]},{"id":37,"file":"13_REST_API_AND_MCP_SPECIFICATION.md","heading":"4. Model Context Protocol (MCP) Tool Definitions","text":"```json\n[\n {\n \"name\": \"tachyon_diagnose\",\n \"description\": \"Run diagnostic checks on OpenWrt router network and proxy health\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {}\n }\n },\n {\n \"name\": \"tachyon_apply_fix\",\n \"description\": \"Apply automated repair codes to fix router network or proxy issues\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"fix_codes\": {\n \"type\": \"string\",\n \"description\": \"Comma-separated list of fix codes (e.g. clear_dns_cache,restart_singbox)\"\n }\n },\n \"required\": [\"fix_codes\"]\n }\n },\n {\n \"name\": \"tachyon_switch_server\",\n \"description\": \"Switch active proxy server node\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"server_id\": {\n \"type\": \"string\",\n \"description\": \"Identifier of target proxy server\"\n }\n },\n \"required\": [\"server_id\"]\n }\n }\n]\n```","embedding":[]},{"id":38,"file":"14_ZAPRET2_DEEP_DIVE_MANUAL.md","heading":"3.1. `multisplit` (Многосегментная фрагментация)","text":"# 14. Руководство по Zapret v2 (nfqws2): Архитектура, Lua-десинхронизация и Стратегии\n\n## 1. Введение и Архитектурные отличия Zapret v2\n\nZapret v2 (`nfqws2`) — это эволюция классического `nfqws`, переписанная с акцентом на **модульную Lua-логику десинхронизации** и высокопроизводительное мультипрофилирование. В отличие от Zapret v1, где все параметры передавались через монолитные CLI-флаги `--dpi-desync-*`, в `nfqws2` обработка пакетов построена на вызове Lua-скриптов (`--lua-init`) и специализированных действий `--lua-desync`.\n\n### Ключевые преимущества `nfqws2`:\n1. **Мультипрофилирование в одном процессе:** возможность разделять правила для разных протоколов (HTTP, TLS, QUIC, UDP Voice) и диапазонов портов без запуска отдельных демонов.\n2. **Гибкое позиционирование фрагментов (`pos`):** поддержка составных позиций сплита (`pos=1,midsld,sniext+4`), позволяющих резать пакет ровно в уязвимых местах сигнатур DPI.\n3. **Управление перекрытием (`seqovl`):** внедрение контролируемого наложения TCP Sequence чисел (`seqovl=1..2`), сбивающего стейтфул-реассемблеры ТСПУ.\n4. **Контроль размера TCP окна (`wsize`):** принудительное занижение Window Size в исходящих пакетах (`wsize=1`), заставляющее сервер и стек дробить поток на однобайтовые сегменты.\n\n---\n\n## 2. Формат командной строки и Lua-инициализация\n\nTachyon запускает `nfqws2` со стандартным набором Lua-библиотек из `/opt/zapret2/lua/`:\n```bash\n/opt/zapret2/nfq2/nfqws2 \\\n --qnum= \\\n --fwmark= \\\n --lua-init=@/opt/zapret2/lua/zapret-lib.lua \\\n --lua-init=@/opt/zapret2/lua/zapret-antidpi.lua \\\n --lua-init=@/opt/zapret2/lua/zapret-auto.lua \\\n [СТРАТЕГИИ]\n```\n\n---\n\n## 3. Функции Lua-десинхронизации (`--lua-desync`)\n\nВ `nfqws2` действия десинхронизации задаются через параметр `--lua-desync=<функция>[:ключ=значение[:ключ2=значение2]]`.\n\n### 3.1. `multisplit` (Многосегментная фрагментация)\nОсновная и самая эффективная функция против современных ТСПУ.\n- **Синтаксис:** `--lua-desync=multisplit:pos=<позиции>[:seqovl=][:fooling=<метод>][:wsize=]`","embedding":[]},{"id":39,"file":"14_ZAPRET2_DEEP_DIVE_MANUAL.md","heading":"4. Методы дурения DPI (`fooling`)","text":"### 3.1. `multisplit` (Многосегментная фрагментация)\nОсновная и самая эффективная функция против современных ТСПУ.\n- **Синтаксис:** `--lua-desync=multisplit:pos=<позиции>[:seqovl=][:fooling=<метод>][:wsize=]`\n- **Параметры `pos`:**\n - `pos=1` — сплит на 1-м байте payload (режет TLS ClientHello на этапе Handshake Type).\n - `pos=midsld` — сплит посередине Second Level Domain внутри SNI (например, `you` | `tube.com`).\n - `pos=sniext` — сплит в начале блока расширений TLS SNI.\n - `pos=sniext+4` — сплит на 4 байта глубже расширения SNI (разрывает парсер расширений DPI).\n - `pos=1,midsld,sniext+2` — тройной сплит, создающий 3 фрагмента с высоким уровнем энтропии.\n- **Параметр `seqovl` (Sequence Overlap):**\n - `seqovl=1` или `seqovl=2` — второй фрагмент отправляется со сдвигом TCP Sequence назад на 1–2 байта. DPI видит конфликт перекрытия данных и пропускает поток, в то время как целевой сервер корректно отбрасывает дублирующийся байт.\n- **Параметр `wsize`:**\n - `wsize=1` — зажимает размер TCP-окна, препятствуя реассемблингу со стороны DPI.\n\n### 3.2. `fake` (Инжекция фейковых пакетов)\nОтправка ложного ClientHello с некорректным SNI или контрольной суммой перед настоящим пакетом.\n- **Синтаксис:** `--lua-desync=fake[:ttl=][:fooling=<метод>]`\n- **Параметры:**\n - `ttl=6` / `ttl=8` — Time-To-Live фейкового пакета. Должен быть достаточным, чтобы долететь до ТСПУ провайдера, но недостаточным, чтобы дойти до сервера назначения.\n - `fooling=badseq` — отправка фейка с невалидным TCP Sequence номером.\n - `fooling=md5sig` — добавление TCP Option 19 (MD5 Signature) в фейковый пакет. ТСПУ часто пассивно анализирует такой пакет и сбрасывает стейт сессии, а сервер назначения дропает его из-за отсутствия MD5-ключа.\n\n### 3.3. `split2` и `disorder2`\n- `split2:pos=` — классическое деление пакета на 2 части в указанной позиции.\n- `disorder2:pos=` — деление на 2 части с обратным порядком отправки (сначала хвост, затем голова).\n\n---\n\n## 4. Методы дурения DPI (`fooling`)","embedding":[]},{"id":40,"file":"14_ZAPRET2_DEEP_DIVE_MANUAL.md","heading":"Instagram & Meta (TLS 1.3 / ECH)","text":"- `split2:pos=` — классическое деление пакета на 2 части в указанной позиции.\n- `disorder2:pos=` — деление на 2 части с обратным порядком отправки (сначала хвост, затем голова).\n\n---\n\n## 4. Методы дурения DPI (`fooling`)\n\n| Метод | Механизм действия | Когда применять |\n|---|---|---|\n| `badseq` | Фейковый пакет имеет ACK/SEQ вне текущего окна TCP. | Универсально против большинства ТСПУ (Ростелеком, МТС, Мегафон, Билайн). |\n| `md5sig` | Пакет содержит TCP MD5 Signature Option (RFC 2385). | Эффективно, если ТСПУ валидирует опции TCP и дропает сессию. |\n| `badack` | Инвертированный или повреждённый ACK-номер. | Против DPI с жестким контролем двустороннего TCP-хэндшейка. |\n| `datanoack` | Данные в сегменте передаются без флага ACK. | Обход сигнатур, триггерящихся только на валидные ACK-сегменты. |\n\n---\n\n## 5. Готовые шаблоны стратегий под сервисы\n\n### YouTube 4K (GoogleVideo chunk stream)\n```text\n--lua-desync=multisplit:pos=1,midsld:seqovl=1:fooling=badseq\n```\n*Разрывает SNI googlevideo и ClientHello, предотвращая троттлинг видеопотока 2160p60.*\n\n### Discord (Gateway, API и Голосовые каналы UDP)\n```text\n--filter-tcp=443 --lua-desync=multisplit:pos=1,sniext+4:seqovl=1:fooling=badseq --new --filter-udp=50000-65535 --lua-desync=fake:ttl=8\n```\n*Комбинированный профиль: TCP 443 для шлюза сообщений и UDP-фейк для RTC Voice серверов.*\n\n### Instagram & Meta (TLS 1.3 / ECH)\n```text\n--lua-desync=fake:ttl=8 --lua-desync=multisplit:pos=midsld:fooling=badseq\n```\n*Низко-TTL фейк перегружает стейт ТСПУ, после чего фрагментированный TLS 1.3 хэндшейк проходит без сброса.*","embedding":[]},{"id":41,"file":"15_ZAPRET1_NFQWS_FIELD_GUIDE.md","heading":"4. Перекрытие Sequence (`--dpi-desync-split-seqovl`)","text":"# 15. Руководство по Zapret v1 (nfqws): Полная спецификация и рецепты\n\n## 1. Архитектура и принцип работы `nfqws` (Zapret v1)\n\nКлассический `nfqws` — это высокопроизводительный демон перехвата пакетов через Linux Netfilter Queue (`NFQUEUE`). Он работает на уровне ядра и L4/L7 сетевого стека, перехватывая исходящие TCP и UDP соединения до отправки в физический сетевой интерфейс и модифицируя структуру пакетов.\n\n---\n\n## 2. Основные параметры десинхронизации (`--dpi-desync`)\n\nВ Zapret v1 режим десинхронизации задается флагом `--dpi-desync=<режим1>,<режим2>`.\n\n| Режим | Описание | Механика |\n|---|---|---|\n| `split2` | Деление пакета на 2 части | Пакет режется на 2 TCP-сегмента по указанной позиции. |\n| `disorder2` | Деление с обратной отправкой | Сегменты отправляются в порядке [хвост, голова]. |\n| `fake` | Инжекция фейкового пакета | Перед реальным запросом отправляется ложный payload с низким TTL. |\n| `multisplit` | Множественная фрагментация | Пакет делится на 3+ сегмента по списку позиций. |\n| `ipfrag2` | IP-фрагментация | Фрагментация на сетевом уровне L3 (IP-пакет делится на части). |\n| `syndata` | Данные в SYN пакете | Внедрение полезной нагрузки в первый TCP SYN пакет (TCP Fast Open). |\n\n---\n\n## 3. Позиционирование сплита (`--dpi-desync-split-pos`)\n\nПараметр `--dpi-desync-split-pos` определяет точное смещение (байт), по которому происходит разрезание TCP-сегмента:\n- `--dpi-desync-split-pos=1` — сплит на 1-м байте payload. Разрывает первый байт TLS Content Type (`0x16`).\n- `--dpi-desync-split-pos=2` — сплит на 2-м байте. Разрывает версию TLS (`0x0301`).\n- `--dpi-desync-split-pos=midsld` — сплит посередине доменного имени второго уровня в SNI.\n- `--dpi-desync-split-pos=sniext+4` — сплит в блоке TLS расширений.\n- `--dpi-desync-split-pos=1,midsld` — комбинированное разделение.\n\n---\n\n## 4. Перекрытие Sequence (`--dpi-desync-split-seqovl`)\n\n- `--dpi-desync-split-seqovl=1` или `2` — при сплите второй сегмент имеет начальный Sequence номер, заходящий на N байт назад (перекрывает конец первого сегмента).","embedding":[]},{"id":42,"file":"15_ZAPRET1_NFQWS_FIELD_GUIDE.md","heading":"3. State-DPI Bypass (Перекрытие TCP Sequence)","text":"## 4. Перекрытие Sequence (`--dpi-desync-split-seqovl`)\n\n- `--dpi-desync-split-seqovl=1` или `2` — при сплите второй сегмент имеет начальный Sequence номер, заходящий на N байт назад (перекрывает конец первого сегмента).\n- ТСПУ видит коллизию данных в потоке и сбрасывает проверку, а сервер назначения корректно дедуплицирует байты по RFC 793.\n\n---\n\n## 5. Методы дурения ТСПУ (`--dpi-desync-fooling`)\n\n- `badseq` — отправка фейка с невалидным Sequence номером.\n- `md5sig` — добавление опции TCP MD5 signature, заставляющей DPI дропнуть фейк или пропустить сессию.\n- `badack` — невалидный номер подтверждения ACK.\n- `hopbyhop` — добавление IPv6 Hop-by-Hop extension header.\n\n---\n\n## 6. Проверенные рецепты для Zapret v1\n\n### 1. YouTube 4K / Web\n```text\n--dpi-desync=fake,split2 --dpi-desync-split-pos=1 --dpi-desync-ttl=8 --dpi-desync-fooling=badseq\n```\n\n### 2. RuTracker & Заблокированные HTTP/HTTPS ресурсы\n```text\n--dpi-desync=disorder2 --dpi-desync-split-pos=1 --dpi-desync-fooling=badseq\n```\n\n### 3. State-DPI Bypass (Перекрытие TCP Sequence)\n```text\n--dpi-desync=split2 --dpi-desync-split-seqovl=1 --dpi-desync-fooling=badseq\n```","embedding":[]},{"id":43,"file":"16_BYEDPI_CIADPI_REFERENCE.md","heading":"2.6. Дополнительные опции","text":"# 16. Справочник по ByeDPI (ciadpi): SOCKS5/TProxy десинхронизация\n\n## 1. Архитектура и принцип работы ByeDPI (`ciadpi`)\n\n`ciadpi` (ByeDPI) — это легковесный локальный прокси-сервер (SOCKS5 / Transparent TCP), который принимает исходящий трафик и выполняет фрагментацию и манипуляцию пакетами на сокетовом уровне (L7/L4). \n\n### Ключевое отличие от Zapret:\n- Zapret работает через перехват `NFQUEUE` (L3/L4 фильтрация ядра).\n- ByeDPI работает как SOCKS5 прокси (по умолчанию порт `4539` в Tachyon) или прозрачный прокси, модифицируя TCP payload непосредственно перед системным вызовом `send()`/`write()`.\n\n---\n\n## 2. Основные параметры командной строки ByeDPI\n\n### 2.1. Фрагментация (`--split` / `-s`)\n- `--split <позиция>` или `-s <позиция>`\n- **Значения позиции:**\n - `1` — сплит на 1-м байте payload.\n - `2` — сплит на 2-м байте.\n - `1+sniext` — сплит в начале блока TLS SNI расширений.\n - `midsld` — сплит посередине SLD домена.\n\n### 2.2. Изменение порядка сегментов (`--disorder` / `-d`)\n- `--disorder <позиция>` или `-d <позиция>`\n- Отправляет первый сегмент с задержкой или после второго сегмента (out-of-order delivery).\n\n### 2.3. Инжекция фейковых пакетов (`--fake` / `-f` и `--ttl` / `-t`)\n- `--fake <смещение>` или `-f <смещение>` — смещение вставки фейкового пакета (`-1` = перед началом реального запроса).\n- `--ttl ` или `-t ` — Time-To-Live для фейковых пакетов (обычно `4..8` в зависимости от провайдера).\n\n### 2.4. Out-of-Band данные (`--oob` / `-o`)\n- `--oob <смещение>` или `-o <смещение>` — отправка одного срочного байта TCP OOB (Urgent Pointer) на указанном смещении. Ломает разбор буфера в DPI, заставляя его пропустить пакет.\n\n### 2.5. Автоматический режим (`--auto` / `-a`)\n- `--auto=t,r,a,s`\n- Адаптивный режим подбора: ByeDPI автоматически пробует комбинации флагов при обнаружении сброса соединения или таймаута:\n - `t` — TLS Record splitting\n - `r` — Reverse disorder\n - `a` — Auto-ttl\n - `s` — Simple split\n\n### 2.6. Дополнительные опции\n- `--tlsrec ` / `-r ` — деление одного ClientHello на несколько независимых TLS Records.","embedding":[]},{"id":44,"file":"16_BYEDPI_CIADPI_REFERENCE.md","heading":"4. Агрессивный низко-TTL фейк","text":"- `t` — TLS Record splitting\n - `r` — Reverse disorder\n - `a` — Auto-ttl\n - `s` — Simple split\n\n### 2.6. Дополнительные опции\n- `--tlsrec ` / `-r ` — деление одного ClientHello на несколько независимых TLS Records.\n- `--ip-frag` — включение фрагментации на уровне IP.\n- `--mod-http` / `-M` — модификация HTTP заголовков (манипуляция Host/символами переноса строки).\n\n---\n\n## 3. Рецепты ByeDPI\n\n### 1. Универсальный адаптивный авто-режим\n```text\n-o 2 --auto=t,r,a,s -d 2\n```\n\n### 2. Disorder + Fake с контролем TTL\n```text\n--split 1 --disorder 1 --fake -1 --ttl 8\n```\n\n### 3. SNI Extension Split + Fake\n```text\n-s 1+sniext -f -1 -t 6\n```\n\n### 4. Агрессивный низко-TTL фейк\n```text\n--fake -1 --ttl 4 --disorder 1 --split 1\n```","embedding":[]},{"id":45,"file":"17_TSPU_DPI_SIGNATURES_AND_COUNTERS.md","heading":"2.3. Instagram & Meta (TLS 1.3 / ECH)","text":"# 17. Сигнатуры ТСПУ (РКН) и методы противодействия десинхронизацией\n\n## 1. Архитектура и принципы работы ТСПУ\n\nТСПУ (Технические средства противодействия угрозам) — это аппаратно-программные комплексы глубокого анализа пакетов (DPI), установленные на сетях операторов связи в РФ. \n\n### Основные режимы фильтрации:\n1. **Пассивный анализ (In-line / TAP):** ТСПУ прослушивает зеркалированный трафик. При обнаружении запрещенного SNI или URL генерирует и инжектирует TCP RST пакет в обе стороны соединения.\n2. **Активный дроп (In-line Drop):** ТСПУ установлен в разрыв канала и физически отбрасывает пакеты сессии, вызывая `Connection Timeout` или `EOF`.\n3. **Троттлинг (Шейпинг по L7-сигнатурам):** Ограничение пропускной способности (например, до 128 Кбит/с) при обнаружении определённых потоков данных (YouTube `googlevideo.com` CDN).\n\n---\n\n## 2. Анализ блокировок по ключевым сервисам\n\n### 2.1. YouTube (GoogleVideo 4K троттлинг)\n- **Механика блокировки:** ТСПУ анализирует TLS ClientHello при обращении к CDN-нодам `rr*.googlevideo.com`. При совпадении сигнатуры ТСПУ не закрывает соединение сразу, а переводит TCP-сессию в режим искусственного ограничения скорости или отбрасывает чанки видео.\n- **Эффективное противодействие:**\n - `multisplit:pos=1,midsld:seqovl=1:fooling=badseq` (Zapret v2)\n - `fake,split2:pos=1:ttl=8:fooling=badseq` (Zapret v1)\n - Сплит на `midsld` разрывает домен `googlevideo` пополам, предотвращая сработку строкового парсера ТСПУ.\n\n### 2.2. Discord (Gateway + Голосовые каналы RTC)\n- **Механика блокировки:** Блокировка состоит из двух компонентов:\n 1. TCP 443 — шлюз сообщений и API (`discord.com`, `gateway.discord.gg`).\n 2. UDP 50000-65535 — голосовые сессии WebRTC / Voice.\n- **Эффективное противодействие:**\n - Мультипрофиль `zapret2`:\n - Для TCP 443: `--filter-tcp=443 --lua-desync=multisplit:pos=1,sniext+4:seqovl=1:fooling=badseq`\n - Для UDP Voice: `--filter-udp=50000-65535 --lua-desync=fake:ttl=8`\n\n### 2.3. Instagram & Meta (TLS 1.3 / ECH)\n- **Механика блокировки:** ТСПУ сбрасывает TCP-соединение инжекцией RST-пакета сразу после получения первого ClientHello с открытым SNI `instagram.com`.","embedding":[]},{"id":46,"file":"17_TSPU_DPI_SIGNATURES_AND_COUNTERS.md","heading":"3. Вычисление оптимального TTL до ТСПУ","text":"- Для UDP Voice: `--filter-udp=50000-65535 --lua-desync=fake:ttl=8`\n\n### 2.3. Instagram & Meta (TLS 1.3 / ECH)\n- **Механика блокировки:** ТСПУ сбрасывает TCP-соединение инжекцией RST-пакета сразу после получения первого ClientHello с открытым SNI `instagram.com`.\n- **Эффективное противодействие:**\n - Низко-TTL фейк с `fooling=badseq` или `fooling=md5sig`, за которым следует сегментированный TLS-хэндшейк. ТСПУ «съедает» фейковый пакет и блокирует его, игнорируя последующий настоящий запрос.\n\n### 2.4. RuTracker & Сайты из реестра РКН\n- **Механика блокировки:** HTTP перенаправление на заглушку провайдера (302 Redirect) или TCP RST на HTTPS SNI.\n- **Эффективное противодействие:**\n - `disorder2:pos=1` или `split2:pos=1:seqovl=1` нарушает сборку HTTP/TLS заголовка в DPI.\n\n---\n\n## 3. Вычисление оптимального TTL до ТСПУ\n\nДля стратегий с инжекцией фейковых пакетов (`fake`) критически важно подобрать параметр `ttl`:\n- **Слишком маленький TTL (< 3):** фейковый пакет умирает на маршрутизаторах провайдера до того, как долетит до ТСПУ. ТСПУ видит реальный пакет и блокирует сессию.\n- **Слишком большой TTL (> 15):** фейковый пакет долетает до сервера назначения, и сервер разрывает соединение из-за невалидного хэндшейка.\n- **Оптимальный диапазон:** `TTL = 6..8` для большинства магистральных операторов РФ.","embedding":[]},{"id":47,"file":"INDEX.md","heading":"📚 Knowledge Base Table of Contents","text":"# Tachyon Knowledge Base & Architecture Index\n\nWelcome to the comprehensive technical knowledge base for **Tachyon**. This directory contains deep architectural specifications, module references, packet flow maps, and developer guidelines compiled directly from the codebase.\n\n---\n\n## 📚 Knowledge Base Table of Contents\n\n| Document | Description | Key Topics Covered |\n|---|---|---|\n| [**01. System Architecture**](01_SYSTEM_ARCHITECTURE.md) | High-level system architecture & control plane | ucode runtime, atomic writes, repository layout, daemon lifecycle |\n| [**02. ucode Module Reference**](02_UCODE_MODULE_REFERENCE.md) | Comprehensive reference for all 60+ `.uc` files | `core/`, `service/`, `diagnostics/`, `singbox/`, `providers/`, `nft/`, `dns/` |\n| [**03. Networking & nftables**](03_NETWORKING_NFTABLES_AND_ROUTING.md) | Packet lifecycle, firewall tables & DNS routing | `inet TachyonTable`, fwmark bitmasks, TProxy, bootstrap DNS loops |\n| [**04. DPI Bypass Engines**](04_DPI_BYPASS_ENGINES.md) | Local packet desynchronization deep dive | Zapret v1 (`nfqws`), Zapret v2 (`nfqws2`), ByeDPI (`ciadpi`), multisplit, seqovl |\n| [**05. AI Stack & AI Doctor**](05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md) | AI Doctor v2.5, Watchdog & REST Agent API | 13 Quick Fixes, Local Rule Doctor, NTP/MTU tuning, OpenAPI 3.0.3, REST API |\n| [**06. Frontend LuCI Architecture**](06_FRONTEND_LUCI_TYPESCRIPT.md) | TypeScript SPA & LuCI view integration | `baseclass.extend` patch, reactive stores, live log streaming modal |\n| [**07. Build & Testing Pipeline**](07_BUILD_TESTS_AND_DEPLOYMENT.md) | Compilation, testing & release workflows | `build.sh` (ipk/apk), `install.sh`, Docker CI container, vitest tests |\n| [**08. UCI Configuration Schema**](08_UCI_CONFIGURATION_SCHEMA.md) | Complete `/etc/config/tachyon` reference | All UCI sections, options, validators, default values, ready recipes |\n| [**09. Telegram Bot Architecture**](09_TELEGRAM_BOT_ARCHITECTURE.md) | Remote Telegram control daemon protocol | Long-polling model, inline keyboards, callback query routing, security |","embedding":[]},{"id":48,"file":"INDEX.md","heading":"Diagnostics & AI","text":"| [**08. UCI Configuration Schema**](08_UCI_CONFIGURATION_SCHEMA.md) | Complete `/etc/config/tachyon` reference | All UCI sections, options, validators, default values, ready recipes |\n| [**09. Telegram Bot Architecture**](09_TELEGRAM_BOT_ARCHITECTURE.md) | Remote Telegram control daemon protocol | Long-polling model, inline keyboards, callback query routing, security |\n| [**10. Hosts Engine & Blocklists**](10_HOSTS_ENGINE_AND_BLOCKLISTS.md) | Hosts ingestion, parsing & smart caching | `combined.txt`, multi-format parsing, GitHub mirror retry resiliency |\n| [**11. Troubleshooting Manual**](11_TROUBLESHOOTING_AND_FIELD_MANUAL.md) | Field diagnostics & emergency recovery | Symptom resolution matrix, diagnostic commands, log inspection paths |\n| [**12. ucode Programming Patterns**](12_UCODE_PROGRAMMING_PATTERNS.md) | Developer guidelines for OpenWrt ucode | Atomic file writes, shell quoting, libuci bindings, RAM efficiency |\n| [**13. REST API & MCP Specification**](13_REST_API_AND_MCP_SPECIFICATION.md) | REST Agent API & MCP tool definitions | OpenAPI 3.0.3, Bearer Auth, OpenAI Function Calling, MCP JSON schema |\n| [**14. Zapret v2 (nfqws2) Deep Dive**](14_ZAPRET2_DEEP_DIVE_MANUAL.md) | Comprehensive Zapret v2 Lua manual | Lua desync functions, multisplit, seqovl, wsize, fooling, multi-profiles |\n| [**15. Zapret v1 (nfqws) Field Guide**](15_ZAPRET1_NFQWS_FIELD_GUIDE.md) | Complete Zapret v1 CLI specification | NFQUEUE desync modes, split-pos, seqovl, syndata, ipfrag, fooling |\n| [**16. ByeDPI (ciadpi) Reference**](16_BYEDPI_CIADPI_REFERENCE.md) | Complete ByeDPI SOCKS5/TProxy manual | Split, disorder, fake, ttl, auto-mode, oob, tlsrec, ip-frag |\n| [**17. TSPU / DPI Signatures & Counters**](17_TSPU_DPI_SIGNATURES_AND_COUNTERS.md) | TSPU filtering mechanics and counters | GoogleVideo 4K, Discord WebRTC, TLS 1.3 RST, TTL distance calculation |\n\n---\n\n## ⚡ Quick Operational Cheat Sheet\n\n### Common CLI Commands\n```sh\n# Diagnostics & AI\ntachyon doctor # Local offline rule diagnostics","embedding":[]},{"id":49,"file":"INDEX.md","heading":"Full backend suite in Docker CI","text":"| [**17. TSPU / DPI Signatures & Counters**](17_TSPU_DPI_SIGNATURES_AND_COUNTERS.md) | TSPU filtering mechanics and counters | GoogleVideo 4K, Discord WebRTC, TLS 1.3 RST, TTL distance calculation |\n\n---\n\n## ⚡ Quick Operational Cheat Sheet\n\n### Common CLI Commands\n```sh\n# Diagnostics & AI\ntachyon doctor # Local offline rule diagnostics\ntachyon ai_doctor # AI Doctor LLM analysis\ntachyon apply_quick_fix # Apply automated repair codes\ntachyon restore_native_internet # 1-Click emergency WAN restore\n\n# Service & Watchdog\ntachyon ai_heal # Trigger immediate self-healing cycle\ntachyon ai_status # Concise Watchdog status JSON\ntachyon ai_status_full # Full Watchdog telemetry JSON\n\n# Component Management\ntachyon check_update # Check for component updates\ntachyon component_action install # Install or update component\n```\n\n### Local Test Execution\n```sh\n# Frontend vitest suite\nnpm --prefix fe-app-tachyon test\n\n# Full backend suite in Docker CI\ndocker run --rm -v \"$(pwd):/mnt\" -w /mnt ucode-ci-img:latest bash tests/run_all.sh\n```","embedding":[]}]} \ No newline at end of file +{"version": 1, "chunk_size": 2000, "chunk_overlap": 200, "total_chunks": 50, "files": ["01_SYSTEM_ARCHITECTURE.md", "02_UCODE_MODULE_REFERENCE.md", "03_NETWORKING_NFTABLES_AND_ROUTING.md", "04_DPI_BYPASS_ENGINES.md", "05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md", "06_FRONTEND_LUCI_TYPESCRIPT.md", "07_BUILD_TESTS_AND_DEPLOYMENT.md", "08_UCI_CONFIGURATION_SCHEMA.md", "09_TELEGRAM_BOT_ARCHITECTURE.md", "10_HOSTS_ENGINE_AND_BLOCKLISTS.md", "11_TROUBLESHOOTING_AND_FIELD_MANUAL.md", "12_UCODE_PROGRAMMING_PATTERNS.md", "13_REST_API_AND_MCP_SPECIFICATION.md", "14_ZAPRET2_DEEP_DIVE_MANUAL.md", "15_ZAPRET1_NFQWS_FIELD_GUIDE.md", "16_BYEDPI_CIADPI_REFERENCE.md", "17_TSPU_DPI_SIGNATURES_AND_COUNTERS.md", "INDEX.md"], "chunks": [{"id": 0, "file": "01_SYSTEM_ARCHITECTURE.md", "heading": "2.2. Deterministic State & Atomic Writes", "text": "# 01. System Architecture & Core Concepts\n\n## 1. High-Level Overview\n\n**Tachyon** is an enterprise-grade, lightweight traffic orchestration, multi-protocol proxying, and DPI anti-censorship platform built natively for **OpenWrt** (supporting 23.05, 24.10, 25.x, and SNAPSHOT).\n\n```mermaid\ngraph TD\n Client[LAN Clients] -->|TCP/UDP| Router[OpenWrt Router]\n Router --> NFT[nftables: inet TachyonTable]\n \n NFT -->|Direct List / 0ms| WAN[Direct WAN Gateway]\n NFT -->|NFQueue Desync| Zapret[Zapret v1 / v2 nfqws/2]\n NFT -->|SOCKS Desync| ByeDPI[ByeDPI ciadpi]\n NFT -->|TProxy / Redirect| SingBox[sing-box Core v1.11+]\n \n SingBox -->|VLESS Reality / H2 / WG| VPS[External VPS / Global Web]\n Zapret --> WAN\n ByeDPI --> WAN\n \n subgraph Tachyon Control Plane\n UCODE[ucode Core Runtime] --> NFT\n UCODE --> SingBox\n UCODE --> Zapret\n UCODE --> ByeDPI\n Watchdog[Autonomous Watchdog 5-15s] --> UCODE\n AIDoctor[AI Doctor v2.5 / Local Doctor] --> Watchdog\n Telegram[Telegram Bot Daemon] --> UCODE\n RestAPI[HTTP REST Agent API / OpenAPI 3.0] --> UCODE\n LuCI[LuCI TypeScript Web UI] --> UCODE\n end\n```\n\n---\n\n## 2. Core Architectural Pillars\n\n### 2.1. Native ucode Runtime (Zero Heavy Runtimes)\n* All control plane logic, UCI manipulation, config generation, health checks, and JSON APIs are written in **ucode**, OpenWrt's native C-like scripting language.\n* **Benefits**:\n * Consumes $\\approx$ 1–3 MB RAM (contrasted with 30–60 MB for Python/Node).\n * Executes directly in C-speed with native bindings to `libuci`, `libubus`, `libblobmsg`, and posix syscalls (`fs`, `math`, `socket`).\n * Runs on routers with as little as 128 MB RAM.\n\n### 2.2. Deterministic State & Atomic Writes\n* All configuration changes (`/etc/config/tachyon`) and JSON runtime configurations (`/tmp/tachyon/sing-box.json`) use an **atomic write pattern** (`tmp_file + rename`):\n ```ucode\n fs.writefile(tmp_path, json_str);\n fs.rename(tmp_path, target_path);", "embedding": []}, {"id": 1, "file": "01_SYSTEM_ARCHITECTURE.md", "heading": "3. Directory Layout & Repository Anatomy", "text": "* All configuration changes (`/etc/config/tachyon`) and JSON runtime configurations (`/tmp/tachyon/sing-box.json`) use an **atomic write pattern** (`tmp_file + rename`):\n ```ucode\n fs.writefile(tmp_path, json_str);\n fs.rename(tmp_path, target_path);\n ```\n This prevents file corruption during sudden power losses or kernel panics.\n\n### 2.3. Dual Control Interfaces: LuCI & Headless Telegram/REST\n1. **LuCI Web UI**: Modern TypeScript SPA (`fe-app-tachyon`) compiled into LuCI JS assets (`luci-app-tachyon`).\n2. **Interactive Telegram Bot**: Embedded polling daemon with inline keyboards for on-the-fly server switching, rule updates, and instant diagnostics.\n3. **HTTP REST Agent API**: Secure CGI endpoint (`/cgi-bin/tachyon-agent/`) with OpenAPI 3.0.3 spec for integration with LLM agents (ChatGPT Custom GPTs, Cursor, Claude Code, N8N).\n\n---\n\n## 3. Directory Layout & Repository Anatomy\n\n```\ntachyon/\n├── tachyon/files/ # Core backend package root\n│ ├── etc/\n│ │ ├── config/tachyon # Main UCI configuration (chmod 600)\n│ │ ├── init.d/tachyon # Procd service init script\n│ │ └── uci-defaults/ # Post-installation default configs\n│ ├── usr/\n│ │ ├── bin/tachyon # Main CLI entrypoint wrapper\n│ │ └── lib/tachyon/ # Modular ucode libraries (60+ modules)\n│ │ ├── core/ # Low-level helpers, UCI, constants\n│ │ ├── service/ # Lifecycle, Watchdog, APIs, Telegram\n│ │ ├── diagnostics/ # AI Doctor, Local Doctor, Quick Fixes\n│ │ ├── singbox/ # Config generator, DNS, routing\n│ │ ├── providers/ # Zapret v1/v2, ByeDPI, NFQueue\n│ │ ├── nft/ # nftables ruleset compiler & applier\n│ │ ├── dns/ # dnsmasq & DNS routing coordinator\n│ │ ├── components/ # Updater, package manager, hosts\n│ │ ├── config/ # Validator, rule engine, migrations", "embedding": []}, {"id": 2, "file": "01_SYSTEM_ARCHITECTURE.md", "heading": "4. Key Runtime Processes & Daemons", "text": "│ │ ├── dns/ # dnsmasq & DNS routing coordinator\n│ │ ├── components/ # Updater, package manager, hosts\n│ │ ├── config/ # Validator, rule engine, migrations\n│ │ └── subscription/ # Subscriptions fetcher & parser\n├── luci-app-tachyon/ # OpenWrt LuCI package\n│ ├── htdocs/luci-static/resources/view/tachyon/ # Compiled frontend JS bundle\n│ ├── root/etc/uci-defaults/ # LuCI menu registration\n│ └── po/ # Translations (ru, en)\n├── fe-app-tachyon/ # Frontend TypeScript source\n│ ├── src/ # TypeScript SPA source\n│ ├── tsup.config.ts # Builds and patches LuCI baseclass\n│ └── package.json # Dependencies (vitest, typescript, tsup)\n├── tests/ # Comprehensive test suite (100+ shell tests)\n├── build.sh # Release packager (ipk + apk)\n├── install.sh # One-liner end-user installer\n└── docs/ # Technical documentation & Knowledge Base\n```\n\n---\n\n## 4. Key Runtime Processes & Daemons\n\n| Process | Role | Execution Model |\n|---|---|---|\n| `sing-box` | Core proxying & packet tunneling engine | Managed by procd (`/etc/init.d/tachyon`) |\n| `nfqws` / `nfqws2` | Local TCP/UDP packet desynchronizer (Zapret) | Spawned into background per configured rule |\n| `ciadpi` | Local SOCKS desync proxy (ByeDPI) | Spawned on `127.0.0.1:1080` / custom port |\n| `watchdog.uc` | State supervision, loop mitigation, self-healing | Background periodic daemon (every 5–15s) |\n| `telegram.uc` | Telegram Bot Long-Polling Daemon | Procd-supervised background worker |\n| `agent_api.uc` | HTTP REST Agent API Handler | Invoked on-demand via `uhttpd` CGI |", "embedding": []}, {"id": 3, "file": "02_UCODE_MODULE_REFERENCE.md", "heading": "2. Service Management Subsystem (`service/`)", "text": "# 02. ucode Backend Module Reference\n\nTachyon's backend is modularized under `tachyon/files/usr/lib/tachyon/`. Modules are loaded dynamically via ucode's `require()` or executed directly via `ucode -L `.\n\n---\n\n## 1. Core Subsystem (`core/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `constants.uc` | Central repository of paths, default ports, mark values, version detection (`detect_installed_version()`), commit SHA resolver (`detect_installed_commit_sha()`), UCI config names. |\n| `common.uc` | String manipulation (`trim`, `split_lines`), file helpers (`read_file`, `write_atomic`), logging formatters (`log_info`, `log_error`, `log_debug`). |\n| `helpers.uc` | Process management (`popen_read`, `system_exec`), CIDR formatting, MAC address validators, integer conversions with safety fallbacks. |\n| `ip.uc` | IP v4/v6 parser, subnet containment (`ip_in_subnet`), CIDR validator, loopback & private IP range detection. |\n| `url.uc` | RFC 3986 URL parser, extraction of scheme, host, port, path, query params, hash fragment, safe URL encoding/decoding. |\n| `uci.uc` | High-level wrapper over OpenWrt `libuci`: `get_section`, `set_option`, `add_section`, `delete_section`, atomic commit with lock. |\n| `packages.uc` | Package manager abstraction: detects `opkg` vs `apk` (OpenWrt 25.x+), checks installed packages, versions, and dependencies. |\n| `events.uc` | Internal event bus mechanism: publish/subscribe for service state transitions and notification dispatching. |\n\n---\n\n## 2. Service Management Subsystem (`service/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `lifecycle.uc` | Service start, stop, restart, enable, disable. Coordinates teardown order (nftables -> singbox -> zapret -> dnsmasq) to prevent routing deadlocks. |\n| `state.uc` | Comprehensive runtime state reader (`get_runtime_state()`): active proxy server, watchdog status, interface health, uptime, memory consumption. |\n| `reload.uc` | Hot-reload planner (`plan_reload()`): inspects what changed in UCI and applies the minimal necessary restart (e.g. soft-reload sing-box vs full nftables rebuild). |", "embedding": []}, {"id": 4, "file": "02_UCODE_MODULE_REFERENCE.md", "heading": "3. Diagnostics & AI Subsystem (`diagnostics/`)", "text": "| `state.uc` | Comprehensive runtime state reader (`get_runtime_state()`): active proxy server, watchdog status, interface health, uptime, memory consumption. |\n| `reload.uc` | Hot-reload planner (`plan_reload()`): inspects what changed in UCI and applies the minimal necessary restart (e.g. soft-reload sing-box vs full nftables rebuild). |\n| `reset.uc` | Factory reset routines: wipes `/etc/config/tachyon`, cleans up temporary caches, restores default templates. |\n| `watchdog.uc` | Autonomous supervisor loop: checks sing-box process, memory thresholds (OOM guard), DNS resolution, loop-restart mitigation (`safe_proxy_restart`). |\n| `snapshot.uc` | Assembles a structured system snapshot JSON for AI Doctor and external diagnostics. |\n| `agent_api.uc` | CGI handler for `/cgi-bin/tachyon-agent/`: handles routing, Bearer authentication validation, endpoint dispatch, JSON serialization. |\n| `agent_mcp.uc` | Model Context Protocol (MCP) tool schema and handlers for integration with MCP clients (Cursor, Claude Desktop). |\n| `telegram.uc` | Telegram Bot daemon: polling loop (`getUpdates`), command dispatcher (`/doctor`, `/ai_doctor`, `/fix`, `/restart`, `/status`), inline keyboards. |\n| `warp_generator.uc` | Cloudflare WARP account generator & key exchange for auto-provisioning WireGuard outbounds. |\n| `event_controller.uc` | Coordinates async background job workers, PID tracking, lock files, and log ring-buffer management. |\n\n---\n\n## 3. Diagnostics & AI Subsystem (`diagnostics/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `runtime.uc` | **Local Rule Doctor & AI Doctor engine**: runs 10+ local heuristic checks, detects NTP desync, conntrack overflow, MTU issues, bootstrap DNS deadlock; applies 13+ quick fix codes (`apply_quick_fix()`), executes emergency internet restoration (`restore_native_internet()`). |\n| `service_check.uc` | Health probes: tests sing-box TCP/UDP proxying, DNS response latency, WAN internet connectivity, gateway reachability. |\n| `status.uc` | Detailed diagnostics status assembler for LuCI Diagnostic tab and CLI `tachyon doctor`. |", "embedding": []}, {"id": 5, "file": "02_UCODE_MODULE_REFERENCE.md", "heading": "5. Providers & DPI Bypass Subsystem (`providers/`)", "text": "| `service_check.uc` | Health probes: tests sing-box TCP/UDP proxying, DNS response latency, WAN internet connectivity, gateway reachability. |\n| `status.uc` | Detailed diagnostics status assembler for LuCI Diagnostic tab and CLI `tachyon doctor`. |\n\n---\n\n## 4. sing-box Subsystem (`singbox/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `generator.uc` | Master sing-box JSON configuration compiler (`/tmp/tachyon/sing-box.json`): binds inbounds, outbounds, routing rules, DNS, experimental. |\n| `generator_outbounds.uc` | Compiles VLESS (Reality/gRPC/WS), VMess, Shadowsocks, Trojan, Hysteria2, WireGuard, Direct, and Block outbounds. |\n| `generator_routes.uc` | Compiles routing rules: domain matchers, IP CIDR matchers, GeoIP rules, client MAC/IP matchers, detour assignments. |\n| `dns.uc` | Compiles sing-box DNS configuration: local DNS, remote DoH/DoT/UDP DNS, fakeip/direct resolution rules. |\n| `dns_failover.uc` | High-availability DNS failover logic: switches between primary and secondary bootstrap DNS upon timeouts. |\n| `dns_prefetch.uc` | Domain pre-fetching & cache warming for frequently accessed sites. |\n| `dns_presets.uc` | Built-in DNS presets (Cloudflare, Google, AdGuard, Quad9, OpenDNS, Custom DoH). |\n| `priority.uc` | Outbound group priority manager: auto-failover, fallback groups, URL-test latency sorting. |\n| `route.uc` | Low-level sing-box route rule builder & selector logic. |\n| `rulesets.uc` | Rule-set binary (`.srs`) and JSON ruleset compiler and parser. |\n| `servers.uc` | Server node parser, validator, and URI serializer (VLESS, VMess, SS, Trojan, H2). |\n| `subscription.uc` | Subscriptions processor: download, base64 decoding, node deduplication, format normalizer. |\n| `urltest.uc` | RTT ping & latency testing worker: measures real response times across proxy servers. |\n\n---\n\n## 5. Providers & DPI Bypass Subsystem (`providers/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `zapret/runtime.uc` | Manages **Zapret v1 (`nfqws`)** process arguments, queue numbers, NFQueue bindings, daemon start/stop. |", "embedding": []}, {"id": 6, "file": "02_UCODE_MODULE_REFERENCE.md", "heading": "7. Configuration & Components Subsystem (`config/`, `components/`, `subscription/`)", "text": "## 5. Providers & DPI Bypass Subsystem (`providers/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `zapret/runtime.uc` | Manages **Zapret v1 (`nfqws`)** process arguments, queue numbers, NFQueue bindings, daemon start/stop. |\n| `zapret2/runtime.uc` | Manages **Zapret v2 (`nfqws2`)** advanced multi-vector desync arguments (`--dpi-desync=multisplit`, `--dpi-desync-seqovl`). |\n| `byedpi/runtime.uc` | Manages **ByeDPI (`ciadpi`)** SOCKS5 proxy daemon, port allocation, payload split parameters. |\n| `nfqueue/runtime.uc` | Kernel NFQueue allocation table, prevents queue ID collisions between Zapret v1 and v2. |\n| `rules.uc` | Maps UCI routing rules to specific provider action handlers (`action = zapret | zapret2 | byedpi | proxy`). |\n| `status.uc` | Real-time process inspection and health monitoring of all active DPI bypass daemons. |\n\n---\n\n## 6. Networking & Firewall Subsystem (`nft/`, `dns/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `nft/apply.uc` | Generates and commits nftables ruleset (`inet TachyonTable`): prerouting, output, divert chains, marks, fwmark, bypass sets. |\n| `dns/apply.uc` | Coordinates DNS interception: configures dnsmasq forwarders, port redirection (`127.0.0.1:5353`), ipset / nftset auto-population. |\n\n---\n\n## 7. Configuration & Components Subsystem (`config/`, `components/`, `subscription/`)\n\n| Module | Key Functions & Responsibilities |\n|---|---|\n| `config/validator.uc` | Strict UCI schema validation: validates IP addresses, ports, UUIDs, private keys, domain names, action modes. |\n| `config/migration.uc` | Automatic migration engine: migrates configurations from legacy Forkop, Podkop Plus, and Podkop configs without data loss. |\n| `components/updater.uc` | Background component installer/updater: handles downloading, unpacking, installing, and version checking of binaries. |\n| `components/hosts.uc` | Remote hosts lists ingestor: fetches blocklists, merges into unified `combined.txt`, handles GitHub mirror failovers. |", "embedding": []}, {"id": 7, "file": "02_UCODE_MODULE_REFERENCE.md", "heading": "7. Configuration & Components Subsystem (`config/`, `components/`, `subscription/`)", "text": "| `components/updater.uc` | Background component installer/updater: handles downloading, unpacking, installing, and version checking of binaries. |\n| `components/hosts.uc` | Remote hosts lists ingestor: fetches blocklists, merges into unified `combined.txt`, handles GitHub mirror failovers. |\n| `subscription/cache.uc` | Atomic subscription cache store, prevents redundant network downloads. |\n| `subscription/parser.uc` | Universal proxy URI parser: parses `vless://`, `vmess://`, `ss://`, `trojan://`, `hysteria2://`, `wireguard://`. |", "embedding": []}, {"id": 8, "file": "03_NETWORKING_NFTABLES_AND_ROUTING.md", "heading": "2.1. Key Chains", "text": "# 03. Networking, nftables & Traffic Routing\n\n## 1. Packet Journey & Routing Lifecycle\n\nTachyon intercepts traffic at the OpenWrt kernel level using **nftables** and policy routing (`ip rule` + routing table `100`).\n\n```mermaid\nsequenceDiagram\n autonumber\n participant Client as LAN Client\n participant PREROUTING as nftables PREROUTING\n participant Sets as nftables Sets (Bypass / Target)\n participant Divert as Detour Action\n participant SingBox as sing-box / Zapret / ByeDPI\n participant WAN as WAN / Internet\n\n Client->>PREROUTING: TCP/UDP SYN Packet (e.g. 192.168.1.100 -> 1.1.1.1:443)\n PREROUTING->>Sets: Check destination IP / Port against Tachyon sets\n alt IP in Bypass Set (Local Subnet / RuNet / Direct)\n Sets->>WAN: Direct Forwarding (0 ms overhead)\n else IP in Target Set or Default Detour\n Sets->>Divert: Mark packet with FWMARK (e.g. 0x10000000)\n Divert->>SingBox: Divert via TProxy / Redir / NFQueue\n SingBox->>WAN: Processed / Encrypted / Desynchronized Outbound\n end\n```\n\n---\n\n## 2. nftables Table Structure (`inet TachyonTable`)\n\nTachyon encapsulates all its firewall rules inside a dedicated table `inet TachyonTable`. This ensures clean isolation from the system `inet fw4` firewall.\n\n### 2.1. Key Chains\n\n1. **`dstnat` / `prerouting` (Hook `prerouting`, priority `-100` / `dstnat`)**:\n * Intercepts incoming LAN client packets before routing decisions.\n * Checks client MAC / IP exclusion lists.\n * Matches destination IP against `tachyon_bypass_v4` / `tachyon_target_v4` sets.\n * Performs TProxy redirect (`tproxy to :10080 meta mark set 0x10000000 accept`) or Port redirect.\n2. **`output` (Hook `output`, priority `-100`)**:\n * Intercepts router's own locally generated packets (e.g. DNS lookups, curl, router traffic).\n * Prevents self-interception loops (`meta skuid == \"tachyon\" return`).\n3. **`nfqueue_chain`**:\n * Directs packets destined for Zapret v1 / v2 to kernel NFQueue numbers (`queue num 200`, `queue num 201`).", "embedding": []}, {"id": 9, "file": "03_NETWORKING_NFTABLES_AND_ROUTING.md", "heading": "3.3. Bootstrap DNS Dead-Lock Prevention", "text": "* Prevents self-interception loops (`meta skuid == \"tachyon\" return`).\n3. **`nfqueue_chain`**:\n * Directs packets destined for Zapret v1 / v2 to kernel NFQueue numbers (`queue num 200`, `queue num 201`).\n\n### 2.2. Bitmask & Firewall Marks\n\n| Mark Value | Meaning | Action |\n|---|---|---|\n| `0x10000000` | Redirected to sing-box TProxy | Routed to local loopback via table 100 |\n| `0x20000000` | Processed by Zapret / NFQueue | Dispatched to nfqws daemon |\n| `0x40000000` | Marked for ByeDPI SOCKS | Forwarded to local SOCKS redirect |\n| `0x80000000` | Bypass marker (Direct WAN) | Accepted immediately without inspection |\n\n---\n\n## 3. DNS Architecture & Interception\n\n### 3.1. DNS Resolution Pipeline\n\n```\n[LAN Client DNS Query: 53]\n │\n ▼\n [dnsmasq / Router]\n │\n ├─► If Domain in Direct / RuNet / Local ──► Local Upstream DNS (ISP / DoH)\n │\n ├─► If Domain in Hosts Section ──────────► Static IP from dns_hosts\n │\n └─► If Domain in Target Proxy / Desync ──► sing-box DNS (127.0.0.1:5353)\n │\n ▼\n [Remote Secure DoH/DoT]\n [Populates nftables set]\n```\n\n### 3.2. Dynamic nftables Set Population (`nftset`)\n* When dnsmasq resolves a domain associated with a proxy or Zapret rule, it automatically adds the resolved IP address to the corresponding kernel nftables set (e.g. `tachyon_target_v4`).\n* This enables sub-millisecond, line-rate packet redirection without re-evaluating domain names in user-space for every packet.\n\n### 3.3. Bootstrap DNS Dead-Lock Prevention\n* A critical failure mode in proxy routers is a **DNS loop**: sing-box needs to resolve the VPS hostname (e.g. `vps.example.com`), but its own DNS resolver routes queries through sing-box, which is not yet connected.", "embedding": []}, {"id": 10, "file": "03_NETWORKING_NFTABLES_AND_ROUTING.md", "heading": "4.1. Emergency Internet Restoration Mechanism", "text": "* A critical failure mode in proxy routers is a **DNS loop**: sing-box needs to resolve the VPS hostname (e.g. `vps.example.com`), but its own DNS resolver routes queries through sing-box, which is not yet connected.\n* **Tachyon's Solution**:\n * Dedicated `direct_resolvers` (Cloudflare `1.1.1.1`, Google `8.8.8.8`) bypass all proxy rules.\n * Local Rule Doctor monitors bootstrap DNS reachability and automatically executes `fix_bootstrap_dns` if a circular dependency is detected.\n\n---\n\n## 4. Policy Routing (`ip rule` & Routing Tables)\n\nTachyon provisions routing table `100`:\n```sh\n# Routing rule for marked packets\nip rule add fwmark 0x10000000/0x10000000 lookup 100 priority 10000\n\n# Local loopback route in table 100\nip route add local default dev lo table 100\n```\n\n### 4.1. Emergency Internet Restoration Mechanism\nWhen `tachyon restore_native_internet` is triggered:\n1. `inet TachyonTable` is atomically deleted: `nft delete table inet TachyonTable`.\n2. Policy routing rule `ip rule del lookup 100` is removed.\n3. dnsmasq configuration is reverted to native upstream forwarders.\n4. sing-box process is stopped cleanly.\n5. Result: Full, native WAN connectivity is restored in under 200 ms without rebooting the router.", "embedding": []}, {"id": 11, "file": "04_DPI_BYPASS_ENGINES.md", "heading": "2.1. Основные стратегии обхода", "text": "# 04. Движки обхода DPI и десинхронизации пакетов\n\nTachyon интегрирует три независимых локальных движка десинхронизации сетевых пакетов, которые функционируют непосредственно на оборудовании роутера без необходимости использования внешнего VPS или прокси-сервера (режим «Zero-VPS»).\n\n---\n\n## 1. Сравнительная матрица: Zapret v1 vs Zapret v2 vs ByeDPI\n\n| Параметр | Zapret v1 (`nfqws`) | Zapret v2 (`nfqws2`) | ByeDPI (`ciadpi`) |\n|---|---|---|---|\n| **Исполняемый файл** | `/usr/bin/nfqws` | `/usr/bin/nfqws2` | `/usr/bin/ciadpi` |\n| **Модель работы** | Перехват через Kernel NFQueue | Multi-Queue NFQueue с Lua | Локальный SOCKS5 / TProxy |\n| **Целевые протоколы** | HTTP, TLS (ClientHello) | HTTP, TLS, QUIC, WireGuard, UDP | HTTP, TLS |\n| **Методы фрагментации** | `split2`, `disorder`, `fake` | `multisplit`, `seqovl`, `wsize`, `fake` | `--split-pos`, `--disorder`, `--fake` |\n| **Многоуровневые цепочки** | 1 стратегия на правило | Сложные составные цепочки | Составные аргументы SOCKS |\n| **Нагрузка на CPU** | Минимальная (< 1%) | Низкая (< 2%) | Низкая (< 2%) |\n| **Оптимально для** | Базового DPI, старых роутеров | YouTube 4K, Discord, ТСПУ | Не-root окружений, SOCKS-роутинга |\n\n---\n\n## 2. Принципы и техники десинхронизации пакетов\n\nСистемы глубокого анализа пакетов (DPI / ТСПУ) анализируют заголовки сетевых протоколов (такие как `SNI` в расширении TLS ClientHello или заголовок `Host` в HTTP) для блокировки или замедления трафика. \n\nДесинхронизация обманывает конечный автомат DPI, заставляя его потерять контекст TCP-сессии или пропустить целевой заголовок, в то время как целевой сервер корректно собирает исходный поток данных.\n\n```\nИсходный поток: [TLS ClientHello с SNI] ──────────► (Блокируется ТСПУ / DPI)\n\nДесинхронизация: [Fake-пакет с неверной суммой/TTL] ──► (DPI сбрасывает состояние)\n [Фрагмент 1: Начало ClientHello] ───► (DPI не видит полный SNI)\n [Фрагмент 2: Окончание данных] ─────► (Сервер собирает TCP-поток)\n```\n\n### 2.1. Основные стратегии обхода", "embedding": []}, {"id": 12, "file": "04_DPI_BYPASS_ENGINES.md", "heading": "3.1. Пример настройки Zapret v2 (`/etc/config/tachyon`)", "text": "[Фрагмент 1: Начало ClientHello] ───► (DPI не видит полный SNI)\n [Фрагмент 2: Окончание данных] ─────► (Сервер собирает TCP-поток)\n```\n\n### 2.1. Основные стратегии обхода\n\n1. **`split2` / `multisplit` (Многопозиционное разделение)**:\n * Разрезает TCP-сегмент непосредственно внутри поля TLS SNI или заголовка HTTP Host. Оборудование DPI не выполняет глубокую реассемблинг-сборку мелких фрагментов, а стек TCP целевого сервера склеивает поток без потерь.\n2. **`disorder` / `disorder2` (Изменение порядка доставки)**:\n * Отправляет вторую часть пакета раньше первой с корректными TCP Sequence Numbers. DPI видит фрагменты не по порядку и пропускает инспекцию.\n3. **`fake` / `fake_sni` (Внедрение фейковых пакетов)**:\n * Отправляет поддельный пакет TLS ClientHello с намеренно заниженным TTL (Time To Live). DPI перехватывает поддельный пакет и считает соединение легитимным, после чего пакет угасает в сети, не доходя до целевого сервера.\n4. **`seqovl` (Наложение порядковых номеров / Sequence Overlap)**:\n * Посылает пакет с перекрывающимся диапазоном TCP Sequence. Стек TCP на сервере отбрасывает дублирующиеся байты, тогда как DPI парсит неверные данные и теряет контроль над сессией.\n5. **`wsize` (Манипуляция размером окна TCP Window Size)**:\n * Принудительно устанавливает размер TCP-окна в 1–2 байта, заставляя клиент слать данные микросегментами, что ломает эвристики DPI.\n\n---\n\n## 3. Конфигурация и управление в UCI\n\n### 3.1. Пример настройки Zapret v2 (`/etc/config/tachyon`)\n\n```ini\nconfig provider 'zapret2'\n option enabled '1'\n option daemon_bin '/usr/bin/nfqws2'\n option qnum '201'\n option args_tcp '--dpi-desync=multisplit --dpi-desync-split-pos=1,midsld --dpi-desync-seqovl=1 --dpi-desync-fooling=badseq'\n option args_udp '--dpi-desync=fake --dpi-desync-any-protocol=1 --dpi-desync-cutoff=d4'\n\nconfig rule 'youtube_rule'\n option enabled '1'\n option name 'YouTube 4K Desync'\n option action 'zapret2'\n list domain_pattern 'googlevideo.com'", "embedding": []}, {"id": 13, "file": "04_DPI_BYPASS_ENGINES.md", "heading": "5. Интеграция AmneziaWG в sing-box-extended (2026)", "text": "option args_udp '--dpi-desync=fake --dpi-desync-any-protocol=1 --dpi-desync-cutoff=d4'\n\nconfig rule 'youtube_rule'\n option enabled '1'\n option name 'YouTube 4K Desync'\n option action 'zapret2'\n list domain_pattern 'googlevideo.com'\n list domain_pattern 'youtube.com'\n list domain_pattern 'ytimg.com'\n list domain_pattern 'discord.gg'\n list domain_pattern 'discord.com'\n```\n\n### 3.2. Пример настройки ByeDPI\n\n```ini\nconfig provider 'byedpi'\n option enabled '1'\n option daemon_bin '/usr/bin/ciadpi'\n option listen_ip '127.0.0.1'\n option listen_port '1080'\n option args '--split-pos 1 --disorder 1 --fake -1 --ttl 8'\n```\n\n---\n\n## 4. Мультиплексирование NFQueue и изоляция очередей\n\n* Подсистема ядра Linux `nfnetlink_queue` требует уникальный номер очереди (`qnum`) для каждого запущенного процесса демона.\n* Модуль `providers/nfqueue/runtime.uc` в Tachyon динамически управляет выделением очередей:\n * Базовая очередь Zapret v1: `200`\n * Базовая очередь Zapret v2: `201`\n * Очередь Strategy Fuzzer: `298` / `299`\n* При одновременной активации Zapret v1 и Zapret v2 для разных правил маршрутизации Tachyon гарантирует строгую изоляцию очередей и исключает конфликты PID и fwmark.\n\n---\n\n## 5. Интеграция AmneziaWG в sing-box-extended (2026)\n\nПроверено против релизного бинарника `v1.13.18-extended-2.6.5` (`shtorm-7/sing-box-extended`):\n\n- Секция `endpoint.amnezia` полностью реализована в форке: `AmneziaOptions` (`transport/wireguard/endpoint_options.go`) → параметры IPC `jc / jmin / jmax / s1-s4 / h1-h4 / i1-i5`.\n- Форк `shtorm-7/wireguard-go v0.0.4-extended-1.5.3`: пакеты `I1–I5` отправляются отдельными дейтаграммами **перед** инициализацией рукопожатия (`SendHandshakeInitiation`), значение задается в hex-формате.\n- Генератор Tachyon (`singbox/generator_outbounds.uc` -> `add_awg_endpoint`) формирует конфигурацию, полностью совместимую со схемой форка:\n - Секция `peer` содержит обязательный `allowed_ips`.\n - Параметры `pre_shared_key` и `persistent_keepalive_interval` опциональны.", "embedding": []}, {"id": 14, "file": "04_DPI_BYPASS_ENGINES.md", "heading": "Вывод доступной матрицы стратегий", "text": "- Генератор Tachyon (`singbox/generator_outbounds.uc` -> `add_awg_endpoint`) формирует конфигурацию, полностью совместимую со схемой форка:\n - Секция `peer` содержит обязательный `allowed_ips`.\n - Параметры `pre_shared_key` и `persistent_keepalive_interval` опциональны.\n - Hex-значения `i1–i5` передаются через `uci_bin_to_hex` без повторного кодирования.\n- **Диагностика:** если AWG/WARP-туннель имеет состояние «TX есть, RX нет» на sing-box-extended, конфиг применен корректно — причина во внешней UDP-фильтрации провайдера или блокировке сервера.\n\n---\n\n## 6. Strategy Fuzzer и автоматический подбор стратегий\n\nTachyon включает встроенный модуль автоматического тестирования стратегий обхода — **Strategy Fuzzer & Auto-Tuner** (`diagnostics/fuzzer.uc`), который избавляет от необходимости вручную подбирать флаги `nfqws2` или `ciadpi`.\n\n### 6.1. Механизм работы\n- **Изолированный сэндбокс:** Тестирование выполняется через временные очереди `qnum 298/299` с сокетной меткой `0x08000000` (для Zapret) либо через локальный порт `127.0.0.1:11089` (для ByeDPI), не затрагивая активный домашний трафик.\n- **Метрический скоринг:** Замеряются время TLS-рукопожатия, TTFB (время до первого байта), битрейт загрузки чанка потокового видео (MB/s) и HTTP-код ответа.\n- **1-Click Apply:** Победившая стратегия мгновенно применяется к правилу YouTube/Discord или в глобальные параметры провайдера с автоматической перезагрузкой службы.\n\n### 6.2. Команды управления через CLI\n```sh\n# Запуск бенчмарка стратегий\ntachyon fuzzer_start [custom_url] [rule_section]\n\n# Просмотр текущего прогресса и результатов\ntachyon fuzzer_status\n\n# Остановка фонового бенчмарка\ntachyon fuzzer_stop\n\n# Применение выбранной стратегии в UCI\ntachyon fuzzer_apply \"\" [target_rule_or_global]\n\n# Вывод доступной матрицы стратегий\ntachyon fuzzer_strategies\n```", "embedding": []}, {"id": 15, "file": "05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md", "heading": "3. Local Rule Doctor & 13 Quick Fix Codes", "text": "# 05. AI Stack, AI Doctor & Autonomous Self-Healing\n\n## 1. Overview of Tachyon AI Stack\n\nTachyon provides a dual-layer AI and autonomous resilience stack:\n1. **Autonomous Layer (Local Rule Doctor & Watchdog)**: Runs locally on the router every 5–15 seconds, detects network drops, memory leaks, DNS deadlocks, and time desync without requiring internet access or API tokens.\n2. **Cognitive Layer (AI Doctor v2.5)**: Deep diagnostics powered by LLMs (OpenAI, Anthropic Claude, DeepSeek, or local Ollama/OpenRouter models) with contextual prompt enrichment and automated Multi-Fix generation.\n3. **Agent Integration Layer (HTTP REST Agent API & OpenAPI 3.0)**: Programmatic interface for autonomous AI agents (Cursor, Claude Code, AutoGPT, ChatGPT Custom GPTs, N8N, Dify).\n\n---\n\n## 2. AI Doctor Architecture (v2.5)\n\n```mermaid\ngraph TD\n subgraph Data Collection\n R1[Process Probes: singbox/zapret/dnsmasq]\n R2[Kernel Metrics: conntrack, mem, uptime]\n R3[Watchdog History: failure streaks, OOM events]\n R4[System Logs: 15 most recent critical lines]\n end\n\n R1 --> Aggregator[snapshot.uc Assembler]\n R2 --> Aggregator\n R3 --> Aggregator\n R4 --> Aggregator\n\n Aggregator --> Prompt[Deep Context LLM Prompt]\n Prompt --> LLM[LLM Provider: OpenAI / Claude / DeepSeek / Custom]\n \n LLM --> Verdict[Structured Diagnosis Report]\n LLM --> MultiFix[Multi-Fix Action Plan: FIX: code1, code2]\n \n MultiFix --> Exec[Local Rule Doctor Execution Engine]\n Exec --> Result[Applied Fixes & Service State Refresh]\n```\n\n---\n\n## 3. Local Rule Doctor & 13 Quick Fix Codes\n\nThe execution engine in `diagnostics/runtime.uc` maps standardized fix codes to automated shell/ucode repair procedures:\n\n| Code | Target Subsystem | Action Performed |\n|---|---|---|\n| `start_singbox` | sing-box | Restarts failed sing-box process via procd. |\n| `rebuild_rules` | nftables | Flushes and recompiles `inet TachyonTable` ruleset. |\n| `fix_dnsmasq` | dnsmasq | Restarts dnsmasq and checks `/tmp/etc/dnsmasq.conf.*`. |", "embedding": []}, {"id": 16, "file": "05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md", "heading": "4.1. Authentication Model", "text": "| `start_singbox` | sing-box | Restarts failed sing-box process via procd. |\n| `rebuild_rules` | nftables | Flushes and recompiles `inet TachyonTable` ruleset. |\n| `fix_dnsmasq` | dnsmasq | Restarts dnsmasq and checks `/tmp/etc/dnsmasq.conf.*`. |\n| `fix_resolv_symlink` | DNS | Restores broken `/etc/resolv.conf` -> `/tmp/resolv.conf.d/resolv.conf.auto` link. |\n| `start_watchdog` | Watchdog | Restarts the background watchdog supervisor process. |\n| `restart_singbox_dns` | sing-box DNS | Resets internal sing-box DNS server module and cache. |\n| `fix_uci_config` | UCI | Restores `/etc/config/tachyon` from the latest valid atomic backup. |\n| `fix_wan_interface` | Networking | Runs `ifup wan` to bounce the primary uplink interface. |\n| `fix_gateway` | Networking | Re-establishes default routing gateway via `/etc/init.d/network restart`. |\n| `clear_dns_cache` | Cache | Flushes dnsmasq cache, deletes sing-box `cache.db`, and restarts DNS. |\n| `update_subscriptions`| Subscriptions | Triggers asynchronous background download and refresh of proxy subscriptions. |\n| `reset_firewall` | Firewall | Full restart of OpenWrt firewall (`/etc/init.d/firewall restart`). |\n| `restart_network` | Network Stack | Full restart of OpenWrt network daemon (`/etc/init.d/network restart`). |\n| `fix_system_time` | System NTP | Resynchronizes router clock via NTP pool servers (`ntpd -q -p ...`). |\n| `flush_conntrack` | Kernel | Flushes congested `nf_conntrack` table during connection floods. |\n| `fix_bootstrap_dns` | Resolver | Unblocks sing-box primary bootstrap resolvers and breaks circular loops. |\n| `optimize_mtu` | Tunnels | Auto-calculates optimal MTU (1280–1420) for WireGuard / AmneziaWG interfaces. |\n| `restore_native_internet` | Emergency | One-click full teardown of Tachyon proxying; returns pure native WAN routing. |\n\n---\n\n## 4. HTTP REST Agent API & OpenAPI 3.0.3\n\nTachyon exposes a standardized REST API hosted under `/cgi-bin/tachyon-agent/` via OpenWrt's native `uhttpd`.\n\n### 4.1. Authentication Model", "embedding": []}, {"id": 17, "file": "05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md", "heading": "4.3. Full Endpoint Index", "text": "| `restore_native_internet` | Emergency | One-click full teardown of Tachyon proxying; returns pure native WAN routing. |\n\n---\n\n## 4. HTTP REST Agent API & OpenAPI 3.0.3\n\nTachyon exposes a standardized REST API hosted under `/cgi-bin/tachyon-agent/` via OpenWrt's native `uhttpd`.\n\n### 4.1. Authentication Model\n* **Read-Only Endpoints**: Accessible within LAN without authentication (or secured via firewall).\n* **Write Endpoints**: Require Bearer token authentication:\n ```http\n POST /cgi-bin/tachyon-agent/ai-doctor/fix\n Authorization: Bearer \n Content-Type: application/json\n\n {\"fix\": \"clear_dns_cache,start_singbox\"}\n ```\n\n### 4.2. OpenAPI 3.0.3 Specification\n* The live OpenAPI JSON schema is available at:\n ```\n GET /cgi-bin/tachyon-agent/openapi.json\n ```\n* This schema allows instant import into **ChatGPT Custom GPT Actions**, **N8N HTTP Request Nodes**, **Dify**, and **Flowise**.\n\n### 4.3. Full Endpoint Index\n\n| Method | Endpoint | Auth Required | Description |\n|---|---|---|---|\n| `GET` | `/health` | No | Lightweight JSON health status probe. |\n| `GET` | `/snapshot` | No | Full system snapshot (interfaces, memory, proxy status). |\n| `GET` | `/diagnose` | No | Local Rule Doctor diagnosis report. |\n| `GET` | `/logs` | No | Returns last 100 lines of Tachyon system log. |\n| `GET` | `/config` | No | Returns sanitized UCI configuration. |\n| `GET` | `/tools` | No | OpenAI Function Calling / MCP tool definitions. |\n| `GET` | `/openapi.json` | No | OpenAPI 3.0.3 specification JSON. |\n| `POST`| `/heal` | **Bearer** | Triggers manual Watchdog self-healing cycle. |\n| `POST`| `/ai-doctor/fix` | **Bearer** | Applies one or more quick-fix codes. |\n| `POST`| `/restart` | **Bearer** | Restarts specified service (`singbox`, `watchdog`, `dnsmasq`). |\n| `POST`| `/reload` | **Bearer** | Soft-reloads configuration and routing tables. |\n| `POST`| `/config/set` | **Bearer** | Updates specific UCI options. |\n| `POST`| `/section/toggle` | **Bearer** | Enables or disables a routing rule section. |", "embedding": []}, {"id": 18, "file": "05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md", "heading": "4.3. Full Endpoint Index", "text": "| `POST`| `/reload` | **Bearer** | Soft-reloads configuration and routing tables. |\n| `POST`| `/config/set` | **Bearer** | Updates specific UCI options. |\n| `POST`| `/section/toggle` | **Bearer** | Enables or disables a routing rule section. |\n| `POST`| `/domain/add` | **Bearer** | Appends domain pattern to target rule list. |", "embedding": []}, {"id": 19, "file": "06_FRONTEND_LUCI_TYPESCRIPT.md", "heading": "3.1. Key Services (`src/tachyon/services/`)", "text": "# 06. Frontend Architecture (LuCI & TypeScript)\n\n## 1. Frontend Architecture Overview\n\nTachyon's web UI is authored as a single-page application in **TypeScript** under `fe-app-tachyon/` and compiled into a standalone JavaScript view under `luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/main.js`.\n\n```\nfe-app-tachyon/ (TypeScript Source)\n │\n ▼ (npm run build: tsc --noEmit && tsup)\n │\n[tsup build + baseclass.extend transformation]\n │\n ▼\nluci-app-tachyon/htdocs/luci-static/resources/view/tachyon/main.js (LuCI Asset)\n```\n\n---\n\n## 2. The LuCI `baseclass.extend()` Patch Mechanism\n\nLuCI uses a custom asynchronous class system (`baseclass.extend({...})`) rather than standard ES modules or Webpack bundles.\n\n* `fe-app-tachyon/tsup.config.ts` compiles the TypeScript entry point (`src/main.ts`) into an ES module.\n* A custom post-processing step inside `tsup.config.ts` transforms the compiled file:\n 1. Strips ESM `export default` statements.\n 2. Wraps the controller inside LuCI's expected `return baseclass.extend({...})` pattern.\n 3. Injects global LuCI helper references (`ui`, `rpc`, `uci`, `fs`, `_`).\n\n> [!IMPORTANT]\n> **Do not attempt to convert `main.js` back into a standard ES module export.** This LuCI bridge is intentional and strictly required for compatibility with all OpenWrt web themes (Bootstrap, Material, Argon, OpenWrt-Two).\n\n---\n\n## 3. Reactive State Management & Services\n\nThe frontend does not use heavy external frameworks (like React or Vue) to keep package size minimal ($\\approx$ 500 KB uncompressed, $\\approx$ 90 KB gzipped). Instead, it uses lightweight TypeScript observable stores:\n\n### 3.1. Key Services (`src/tachyon/services/`)\n\n| Service | File | Purpose |\n|---|---|---|\n| `StoreService` | `store.service.ts` | Central reactive data store with subscription listeners. |\n| `UiStateService` | `uiState.service.ts` | Tracks UI view state, tab switching, and modal states. |\n| `RuntimeUiStateService`| `runtimeUiState.service.ts`| Polling and caching of backend service metrics and active jobs. |", "embedding": []}, {"id": 20, "file": "06_FRONTEND_LUCI_TYPESCRIPT.md", "heading": "4.1. The Updates & Installation Modal (`renderUpdateProgressModal.ts`)", "text": "| `UiStateService` | `uiState.service.ts` | Tracks UI view state, tab switching, and modal states. |\n| `RuntimeUiStateService`| `runtimeUiState.service.ts`| Polling and caching of backend service metrics and active jobs. |\n| `SocketService` | `socket.service.ts` | WebSocket client for real-time log streaming when available. |\n| `TachyonLogWatcher` | `tachyonLogWatcher.service.ts`| Logread stream deduplication and notification dispatcher. |\n\n---\n\n## 4. Tabs & UI View Structure\n\n```\nsrc/tachyon/tabs/\n├── dashboard/ # Live status, RTT ping matrix, traffic toggles\n├── diagnostic/ # AI Doctor modal, Local Rule Doctor, Emergency Fallback\n├── rules/ # Selective routing rules, domain/IP lists, client matchers\n├── providers/ # Zapret v1, Zapret v2, ByeDPI configurations\n├── updates/ # Component installer, version checks, streaming log modal\n└── settings/ # DNS settings, Telegram bot credentials, AI Doctor API keys\n```\n\n### 4.1. The Updates & Installation Modal (`renderUpdateProgressModal.ts`)\n* Provides a streaming log console that polls `/usr/bin/tachyon` output asynchronously via `componentActionLog(jobId, offset)`.\n* Features:\n * Non-blocking operation: router performs installation in background.\n * Real-time timer and progress badge.\n * Preserves output logs and green success/red error banners.\n * Prevents premature auto-close so users can inspect package manager details.\n * Graceful countdown timer for Tachyon package reloads.", "embedding": []}, {"id": 21, "file": "07_BUILD_TESTS_AND_DEPLOYMENT.md", "heading": "2.1. Installer Lifecycle", "text": "# 07. Build System, Testing & Deployment Pipeline\n\n## 1. Release Package Compilation (`build.sh`)\n\nTachyon produces both legacy **IPK** (opkg) and modern **APK** (apk-tools, OpenWrt 25.x+) packages.\n\n### 1.1. Running the Build\n\n```bash\nbash build.sh [output-dir]\n```\n\n* **Semver Requirement**: `build.sh` strictly enforces semantic versioning (`x.y.z`).\n* **Cross-Filesystem WSL Protection**: When executed under Windows Subsystem for Linux (WSL), `build.sh` automatically clones the source repository into the native Linux filesystem (`/tmp/tachyon-build-...`) before packaging to avoid Windows filesystem metadata and permission corruption.\n* **Outputs**:\n * `dist/release-final/tachyon__all.ipk`\n * `dist/release-final/luci-app-tachyon__all.ipk`\n * `dist/release-final/tachyon-.apk`\n * `dist/release-final/luci-app-tachyon-.apk`\n\n---\n\n## 2. End-User Installer (`install.sh`)\n\nTachyon provides an automated one-liner installer:\n\n```bash\nwget -O /tmp/tachyon-setup.sh https://raw.githubusercontent.com/Dushnilin/tachyon/main/install.sh && sh /tmp/tachyon-setup.sh\n```\n\n### 2.1. Installer Lifecycle\n1. **Architecture & OS Detection**: Detects OpenWrt version (23.05, 24.10, 25.x, SNAPSHOT), CPU architecture (`mips`, `mipsel`, `arm_cortex-a7`, `aarch64_cortex-a53`, `x86_64`), and package manager (`opkg` vs `apk`).\n2. **Dependency Resolution**: Ensures `ucode`, `ucode-mod-fs`, `ucode-mod-uci`, `ucode-mod-ubus`, `kmod-nft-tproxy`, `kmod-nft-queue`, `ca-bundle` are installed.\n3. **Legacy Migration**: Automatically detects `/etc/config/forkop` or `/etc/config/podkop` and seamlessly migrates all rules and servers to `/etc/config/tachyon`.\n4. **Binary Provisioning**: Downloads pre-compiled, optimized sing-box, Zapret, or ByeDPI binaries tailored for the router's target architecture.\n5. **Zero-Reboot Initialization**: Configures UCI defaults, registers LuCI menus, builds initial rulesets, and starts services without requiring a full router reboot.", "embedding": []}, {"id": 22, "file": "07_BUILD_TESTS_AND_DEPLOYMENT.md", "heading": "4. Key Developer Gotchas & Conventions", "text": "4. **Binary Provisioning**: Downloads pre-compiled, optimized sing-box, Zapret, or ByeDPI binaries tailored for the router's target architecture.\n5. **Zero-Reboot Initialization**: Configures UCI defaults, registers LuCI menus, builds initial rulesets, and starts services without requiring a full router reboot.\n\n---\n\n## 3. Testing Workflows\n\n### 3.1. Frontend Unit Tests (vitest)\n\n```bash\ncd fe-app-tachyon\nnpm test # Runs all 522+ vitest unit tests\nnpm run build # Verifies TypeScript compilation and LuCI bundle packaging\n```\n\n### 3.2. Backend Integration Tests & ucode Syntax Linting\n\nBackend tests require the `ucode` binary. On development machines without local ucode, tests run inside the Docker CI image:\n\n```bash\n# 1. ucode syntax check across all 60+ modules\ndocker run --rm -v \"$(pwd):/mnt\" -w /mnt ucode-ci-img:latest bash tests/ucode_syntax_lint.sh\n\n# 2. Run all backend behavioral and unit tests in parallel (-P4)\ndocker run --rm -v \"$(pwd):/mnt\" -w /mnt ucode-ci-img:latest bash tests/run_all.sh\n\n# 3. Run a specific test\ndocker run --rm -v \"$(pwd):/mnt\" -w /mnt ucode-ci-img:latest bash tests/ai_doctor_local.sh\n```\n\n### 3.3. ShellCheck Linting\n\n```bash\nshellcheck --severity=error build.sh install.sh tachyon/files/etc/init.d/* tests/**/*.sh\n```\n\n---\n\n## 4. Key Developer Gotchas & Conventions\n\n1. **LF Line Endings**: Enforced via `.gitattributes`. Committing CRLF will break shell scripts on OpenWrt target systems.\n2. **`fe-app-tachyon` Package Manager**: Always use `npm` (`npm install`, `npm test`, `npm run build`), not `yarn`.\n3. **Version Placeholder**: `__COMPILED_VERSION_VARIABLE__` in `src/constants.ts` is replaced during `build.sh` packaging. Do not remove it.\n4. **UCI Config Permissions**: `/etc/config/tachyon` must remain `chmod 600` because it can store sensitive Telegram bot tokens and API keys.", "embedding": []}, {"id": 23, "file": "08_UCI_CONFIGURATION_SCHEMA.md", "heading": "1. Section: `config settings 'settings'`", "text": "# 08. Complete UCI Configuration Schema Reference\n\nThe primary configuration for Tachyon is stored at `/etc/config/tachyon` (UCI format, mode `0600`).\n\n---\n\n## 1. Section: `config settings 'settings'`\n\nGlobal settings defining service behaviour, DNS resolution, watchdog parameters, Telegram integration, and AI Doctor.\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `enabled` | `boolean` (`0`/`1`) | `1` | Master toggle for Tachyon service. |\n| `log_level` | `string` | `info` | Logging verbosity: `debug`, `info`, `warn`, `error`. |\n| `dns_mode` | `string` | `doh` | DNS routing mode: `direct`, `doh`, `dot`, `udp`, `hosts_only`. |\n| `remote_dns_server` | `string` | `https://1.1.1.1/dns-query` | Upstream secure DNS resolver for proxied domains. |\n| `direct_dns_server` | `string` | `77.88.8.8` | Fallback DNS resolver for direct / local domains. |\n| `tproxy_port` | `integer` | `10080` | Local TCP/UDP transparent proxy port for sing-box. |\n| `dns_port` | `integer` | `5353` | Local DNS listening port for sing-box DNS engine. |\n| `clash_api_port` | `integer` | `9090` | sing-box Clash REST API controller port. |\n| `clash_api_secret` | `string` | `\"\"` | Secret token for sing-box Clash API. |\n| `watchdog_interval` | `integer` | `10` | Watchdog polling interval in seconds (5–60s). |\n| `memory_limit_mb` | `integer` | `0` | Dynamic `GOMEMLIMIT` cap in MB (`0` = auto 50% free RAM). |\n| `enable_telegram` | `boolean` | `0` | Enable interactive Telegram management bot. |\n| `telegram_token` | `string` | `\"\"` | Telegram Bot API token from `@BotFather`. |\n| `telegram_chat_id` | `string` | `\"\"` | Allowed Admin Telegram Chat ID(s) (comma-separated). |\n| `enable_ai_doctor` | `boolean` | `0` | Enable LLM AI Doctor diagnostic engine. |\n| `ai_doctor_provider`| `string` | `openai` | LLM Provider: `openai`, `anthropic`, `deepseek`, `custom`. |\n| `ai_doctor_model` | `string` | `\"\"` | Model override (e.g. `gpt-4o-mini`, `claude-3-5-haiku`). |\n| `ai_doctor_api_key`| `string` | `\"\"` | API key for the chosen LLM provider. |", "embedding": []}, {"id": 24, "file": "08_UCI_CONFIGURATION_SCHEMA.md", "heading": "2. Section: `config server 'name'`", "text": "| `ai_doctor_provider`| `string` | `openai` | LLM Provider: `openai`, `anthropic`, `deepseek`, `custom`. |\n| `ai_doctor_model` | `string` | `\"\"` | Model override (e.g. `gpt-4o-mini`, `claude-3-5-haiku`). |\n| `ai_doctor_api_key`| `string` | `\"\"` | API key for the chosen LLM provider. |\n| `ai_doctor_custom_url`| `string` | `\"\"` | Custom OpenAI-compatible endpoint URL (e.g. OpenRouter/Ollama). |\n| `agent_api_token` | `string` | `\"\"` | Bearer token for HTTP REST Agent API write access. |\n\n---\n\n## 2. Section: `config server 'name'`\n\nDefines an individual manual proxy outbound node.\n\n| Option | Type | Required | Description |\n|---|---|---|---|\n| `type` | `string` | Yes | Protocol: `vless`, `vmess`, `shadowsocks`, `trojan`, `hysteria2`, `wireguard`. |\n| `server` | `string` | Yes | Remote server hostname or IPv4/IPv6 address. |\n| `server_port` | `integer` | Yes | Remote server port (e.g. `443`, `8443`). |\n| `uuid` | `string` | Conditional | User UUID for VLESS / VMess. |\n| `password` | `string` | Conditional | Password for Shadowsocks / Trojan / Hysteria2. |\n| `flow` | `string` | No | Flow control: `xtls-rprx-vision` (VLESS). |\n| `security` | `string` | No | Security type: `reality`, `tls`, `none`. |\n| `sni` | `string` | Conditional | Server Name Indication for TLS / Reality. |\n| `pbk` | `string` | Conditional | Public Key for VLESS Reality. |\n| `sid` | `string` | Conditional | Short ID for VLESS Reality (hex string). |\n| `fingerprint` | `string` | No | TLS fingerprint: `chrome`, `firefox`, `safari`, `randomized`. |\n| `method` | `string` | Conditional | Cipher method for Shadowsocks (e.g. `2022-blake3-aes-128-gcm`). |\n| `routing_mode` | `string` | No | Routing mode: `rules` (default), `direct`, `section`. |\n| `routing_section` | `string` | No | Bound routing section when `routing_mode = 'section'`. |\n| `isolate_lan_for_users` | `boolean` | No | Restrict access to private/LAN IP addresses (`1` / `0`). |\n| `isolated_users` | `list string` | No | Specific usernames (`auth_user`) restricted from LAN. If empty, restricts all users of the inbound. |", "embedding": []}, {"id": 25, "file": "08_UCI_CONFIGURATION_SCHEMA.md", "heading": "5. Section: `config hosts 'name'`", "text": "| `isolate_lan_for_users` | `boolean` | No | Restrict access to private/LAN IP addresses (`1` / `0`). |\n| `isolated_users` | `list string` | No | Specific usernames (`auth_user`) restricted from LAN. If empty, restricts all users of the inbound. |\n| `isolated_subnets` | `list string` | No | Optional custom subnets to block for isolated users (defaults to `ip_is_private: true`). |\n| `custom_route_rules` | `list string` | No | Raw JSON sing-box route rule objects injected before general routing rules. |\n\n---\n\n## 3. Section: `config subscription 'name'`\n\nDefines a remote subscription URL for automated batch node fetching.\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `enabled` | `boolean` | `1` | Enable this subscription source. |\n| `url` | `string` | Required | HTTPS / HTTP link to subscription (Base64, Clash, SIP002). |\n| `update_interval`| `integer` | `86400` | Auto-update interval in seconds (default 24 hours). |\n| `custom_user_agent`| `string` | `\"\"` | Custom User-Agent header for subscription request. |\n| `filter_keywords` | `list string` | `[]` | Include nodes matching regex/keywords. |\n| `exclude_keywords`| `list string` | `[]` | Exclude nodes matching regex/keywords. |\n\n---\n\n## 4. Section: `config rule 'name'`\n\nDefines a selective routing policy.\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `enabled` | `boolean` | `1` | Enable this routing rule. |\n| `name` | `string` | `\"\"` | Human-readable label for UI. |\n| `action` | `string` | `proxy` | Route target: `proxy`, `zapret`, `zapret2`, `byedpi`, `direct`, `hosts`. |\n| `target_server` | `string` | `\"\"` | Bound server ID or outbound tag when `action = 'proxy'`. |\n| `domain_pattern` | `list string` | `[]` | List of target domains or wildcards (e.g. `*.youtube.com`). |\n| `ip_cidr` | `list string` | `[]` | List of IP subnets (e.g. `104.16.0.0/12`). |\n| `client_group` | `string` | `\"\"` | Restrict this rule to a specific client device group. |\n\n---\n\n## 5. Section: `config hosts 'name'`", "embedding": []}, {"id": 26, "file": "08_UCI_CONFIGURATION_SCHEMA.md", "heading": "Recipe B: Hybrid Mode (Local Desync for Media + VLESS Reality for Blocked Sites)", "text": "| `ip_cidr` | `list string` | `[]` | List of IP subnets (e.g. `104.16.0.0/12`). |\n| `client_group` | `string` | `\"\"` | Restrict this rule to a specific client device group. |\n\n---\n\n## 5. Section: `config hosts 'name'`\n\nConfigures static DNS overrides and remote blocklists ingestion.\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `enabled` | `boolean` | `1` | Enable hosts mapping. |\n| `dns_hosts` | `list string` | `[]` | Static mappings in format `domain:ip` (e.g. `example.com:1.2.3.4`). |\n| `hosts_list_urls` | `list string` | `[]` | External URLs for blocklists (AdAway, StevenBlack). |\n| `update_interval` | `integer` | `86400` | Auto-refresh interval in seconds. |\n\n---\n\n## 6. Ready-to-Use Configuration Recipes\n\n### Recipe A: Zero-VPS Local DPI Bypass (YouTube + Discord)\n```ini\nconfig settings 'settings'\n option enabled '1'\n option dns_mode 'doh'\n\nconfig provider 'zapret2'\n option enabled '1'\n option daemon_bin '/usr/bin/nfqws2'\n option qnum '201'\n option args_tcp '--dpi-desync=multisplit --dpi-desync-split-pos=1,midsld --dpi-desync-seqovl=1 --dpi-desync-fooling=badseq'\n\nconfig rule 'youtube_discord'\n option enabled '1'\n option name 'YouTube & Discord Local Desync'\n option action 'zapret2'\n list domain_pattern 'googlevideo.com'\n list domain_pattern 'youtube.com'\n list domain_pattern 'ytimg.com'\n list domain_pattern 'discord.com'\n list domain_pattern 'discord.gg'\n```\n\n### Recipe B: Hybrid Mode (Local Desync for Media + VLESS Reality for Blocked Sites)\n```ini\nconfig server 'my_vps'\n option type 'vless'\n option server 'vps.example.com'\n option server_port '443'\n option uuid '12345678-1234-1234-1234-123456789abc'\n option flow 'xtls-rprx-vision'\n option security 'reality'\n option sni 'yahoo.com'\n option pbk 'XYZ...PUBLIC_KEY...'\n option sid '1a2b3c4d'\n\nconfig rule 'media_rule'\n option enabled '1'\n option action 'zapret2'\n list domain_pattern 'youtube.com'\n list domain_pattern 'googlevideo.com'", "embedding": []}, {"id": 27, "file": "08_UCI_CONFIGURATION_SCHEMA.md", "heading": "Recipe B: Hybrid Mode (Local Desync for Media + VLESS Reality for Blocked Sites)", "text": "option pbk 'XYZ...PUBLIC_KEY...'\n option sid '1a2b3c4d'\n\nconfig rule 'media_rule'\n option enabled '1'\n option action 'zapret2'\n list domain_pattern 'youtube.com'\n list domain_pattern 'googlevideo.com'\n\nconfig rule 'blocked_rule'\n option enabled '1'\n option action 'proxy'\n option target_server 'my_vps'\n list domain_pattern 'instagram.com'\n list domain_pattern 'twitter.com'\n list domain_pattern 'x.com'\n```", "embedding": []}, {"id": 28, "file": "09_TELEGRAM_BOT_ARCHITECTURE.md", "heading": "2. Command Set Reference", "text": "# 09. Telegram Bot Architecture & Management Protocol\n\nTachyon includes an embedded, high-performance Telegram management bot written entirely in **ucode** (`service/telegram.uc`).\n\n---\n\n## 1. Architectural Highlights\n\n```mermaid\ngraph LR\n User[Telegram Client] -->|Encrypted HTTPS| TGAPI[Telegram Bot API Servers]\n TGAPI -->|Long Polling: getUpdates| Daemon[Tachyon telegram.uc Daemon]\n \n Daemon --> Auth{Admin Chat ID Match?}\n Auth -->|No| Reject[Silent Ignore / Warning]\n Auth -->|Yes| Router[Command & Callback Dispatcher]\n \n Router -->|/doctor, /ai_doctor| AIDoc[AI Doctor Engine]\n Router -->|/server, /switch| SrvMgr[Server Manager]\n Router -->|/restart| SvcLife[Service Lifecycle]\n Router -->|/status| StateRep[State Assembler]\n```\n\n* **No Public IP or Port Forwarding Required**: Uses outbound long-polling (`getUpdates` with 30s timeout) to securely communicate through NAT/firewalls.\n* **Zero Overhead Memory Footprint**: Runs as a lightweight ucode process consuming under 2 MB RAM.\n* **Role-Based Access Control**: Rejects any commands from chat IDs not explicitly listed in UCI option `telegram_chat_id`.\n\n---\n\n## 2. Command Set Reference\n\n| Command | Arguments | Action |\n|---|---|---|\n| `/start` | — | Displays main welcome card and interactive control keyboard. |\n| `/status` | — | Returns real-time health card: uptime, active server, RAM usage, ping RTT. |\n| `/doctor` | — | Executes Local Rule Doctor and returns offline diagnostic report. |\n| `/ai_doctor`| — | Invokes AI Doctor with LLM reasoning and returns diagnosis + fix buttons. |\n| `/fix` | `` | Applies specific automated repair code (e.g. `/fix clear_dns_cache`). |\n| `/server` | — | Opens interactive server selector with inline pagination and RTT pings. |\n| `/rules` | — | Shows active routing rules with 1-click toggle switches. |\n| `/restart` | `[service]` | Restarts sing-box, dnsmasq, watchdog, or entire network stack. |\n| `/backup` | — | Sends latest atomic configuration backup directly to Telegram chat. |", "embedding": []}, {"id": 29, "file": "09_TELEGRAM_BOT_ARCHITECTURE.md", "heading": "Commit and restart service", "text": "| `/rules` | — | Shows active routing rules with 1-click toggle switches. |\n| `/restart` | `[service]` | Restarts sing-box, dnsmasq, watchdog, or entire network stack. |\n| `/backup` | — | Sends latest atomic configuration backup directly to Telegram chat. |\n\n---\n\n## 3. Inline Keyboard & Callback Query Protocol\n\nThe bot uses dynamic inline keyboards (`InlineKeyboardMarkup`) for single-tap actions without typing commands.\n\n### 3.1. Callback Data Scheme\nCallbacks follow a structured token format: `action:target:param`\n\n```\nsrv:select:node_1 # Switch active proxy server to node_1\nrule:toggle:youtube # Toggle routing rule 'youtube' on/off\nfix:apply:clear_dns_cache# Execute repair code 'clear_dns_cache'\npage:srv:2 # Navigate to page 2 of server list\n```\n\n### 3.2. Example: Server Switcher Response\n\n```json\n{\n \"chat_id\": 123456789,\n \"text\": \"⚡ Выберите активный сервер:\\nТекущий: 🇩🇪 Frankfurt VLESS (18 ms)\",\n \"parse_mode\": \"HTML\",\n \"reply_markup\": {\n \"inline_keyboard\": [\n [\n {\"text\": \"🇩🇪 Frankfurt (18 ms) ✅\", \"callback_data\": \"srv:select:de_1\"},\n {\"text\": \"🇳🇱 Amsterdam (24 ms)\", \"callback_data\": \"srv:select:nl_1\"}\n ],\n [\n {\"text\": \"🇫🇮 Helsinki (31 ms)\", \"callback_data\": \"srv:select:fi_1\"},\n {\"text\": \"🇺🇸 New York (95 ms)\", \"callback_data\": \"srv:select:us_1\"}\n ],\n [\n {\"text\": \"🔄 Замерить пинг\", \"callback_data\": \"srv:ping:all\"},\n {\"text\": \"🩺 Запустить Доктора\", \"callback_data\": \"cmd:doctor\"}\n ]\n ]\n }\n}\n```\n\n---\n\n## 4. Configuration via CLI\n\n```sh\n# Set Bot Token\nuci set tachyon.settings.enable_telegram='1'\nuci set tachyon.settings.telegram_token='123456789:ABCdefGHIjklMNOpqrsTUVwxyz'\n\n# Set Authorized Chat ID(s)\nuci set tachyon.settings.telegram_chat_id='123456789'\n\n# Commit and restart service\nuci commit tachyon\n/etc/init.d/tachyon restart\n```", "embedding": []}, {"id": 30, "file": "10_HOSTS_ENGINE_AND_BLOCKLISTS.md", "heading": "Example UCI Configuration:", "text": "# 10. Hosts Engine, Blocklists & Smart Caching\n\nThe Hosts Engine (`components/hosts.uc`) provides automated background ingestion, normalization, deduplication, and caching of external host lists and static DNS overrides.\n\n---\n\n## 1. Architecture of Hosts Engine\n\n```mermaid\ngraph TD\n Sources[External Remote URLs: AdAway, StevenBlack, Custom] --> Downloader[HTTP Fetcher with Mirror Retry]\n Static[Static dns_hosts in UCI] --> Downloader\n \n Downloader --> Parser[Multi-Format Parser: Hosts, AdBlock, Domains]\n Parser --> Deduper[Deduplication & Sorting Engine]\n Deduper --> Cache[Unified Cache: /tmp/tachyon/hosts/combined.txt]\n \n Cache --> DNSMasq[dnsmasq /etc/dnsmasq.d/tachyon-hosts.conf]\n Cache --> SingboxDNS[sing-box DNS hosts rule]\n```\n\n---\n\n## 2. Multi-Format Ingestion\n\nThe parser automatically detects and normalizes multiple common blocklist formats:\n\n1. **Standard `/etc/hosts` format**:\n ```\n 0.0.0.0 ads.example.com\n 127.0.0.1 tracker.adserver.net\n ```\n2. **Domain-only list format**:\n ```\n malware-domain.org\n telemetry.app.com\n ```\n3. **AdBlock / DNSmasq syntax**:\n ```\n ||badsite.com^\n server=/blocked.com/\n address=/ads.org/0.0.0.0\n ```\n\n---\n\n## 3. GitHub Mirror Retry Resiliency\n\nWhen fetching blocklists hosted on GitHub (e.g. `raw.githubusercontent.com`), access may be blocked or throttled by regional DPI.\n\nTachyon implements an automated fallback retry chain:\n1. **Primary**: Direct HTTPS request to target URL.\n2. **Mirror 1**: `https://gh-proxy.com/`\n3. **Mirror 2**: `https://ghfast.top/`\n4. **Mirror 3**: `https://ghproxy.net/`\n\nIf direct connection fails with timeout or SSL handshake error, Tachyon transparently cycles through available mirrors before reporting an error.\n\n---\n\n## 4. Dedicated Hosts Routing (`action = 'hosts'`)\n\nTachyon supports routing sections that operate purely as DNS-overriding engines without requiring an outbound proxy association.\n\n### Example UCI Configuration:", "embedding": []}, {"id": 31, "file": "10_HOSTS_ENGINE_AND_BLOCKLISTS.md", "heading": "Example UCI Configuration:", "text": "## 4. Dedicated Hosts Routing (`action = 'hosts'`)\n\nTachyon supports routing sections that operate purely as DNS-overriding engines without requiring an outbound proxy association.\n\n### Example UCI Configuration:\n```ini\nconfig rule 'adblock_section'\n option enabled '1'\n option name 'AdBlock & Anti-Tracker'\n option action 'hosts'\n list hosts_list_urls 'https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts'\n list hosts_list_urls 'https://adaway.org/hosts.txt'\n```\n\n* Domains in this section are redirected directly to `0.0.0.0` or custom IPs in dnsmasq / sing-box DNS.\n* Zero traffic is routed to external proxies, preserving VPS bandwidth and minimizing latency.", "embedding": []}, {"id": 32, "file": "11_TROUBLESHOOTING_AND_FIELD_MANUAL.md", "heading": "2. Run AI Doctor with LLM analysis", "text": "# 11. Troubleshooting & Field Diagnostic Manual\n\nA comprehensive guide for diagnosing and resolving common network, proxy, and routing issues on OpenWrt routers running Tachyon.\n\n---\n\n## 1. Quick Emergency Recovery\n\nIf router traffic drops completely or DNS resolution is broken, use the **Emergency Native Internet Restoration** command:\n\n```sh\ntachyon restore_native_internet\n```\n\nThis performs the following actions in under 200 ms:\n1. Atomically drops all nftables interception tables (`nft delete table inet TachyonTable`).\n2. Clears policy routing `table 100` and `ip rule` entries.\n3. Restores dnsmasq to stock upstream forwarders.\n4. Stops sing-box and DPI bypass daemons without rebooting the router.\n\n---\n\n## 2. Symptom Resolution Matrix\n\n| Symptom | Likely Cause | Recommended Fix / Command |\n|---|---|---|\n| **Websites fail to open, ping to 8.8.8.8 works** | DNS loop or dnsmasq forwarder crash. | `tachyon apply_quick_fix clear_dns_cache,fix_dnsmasq` |\n| **YouTube 4K buffers indefinitely** | Zapret strategy out-of-date for current ISP. | Switch Zapret v2 strategy to `multisplit` with `seqovl=1`. |\n| **sing-box fails to start after config change** | Syntax error in custom outbound or invalid UUID. | Check `/var/log/tachyon_service.log` and run `tachyon doctor`. |\n| **System clock desynchronized, TLS fails** | Router rebooted without RTC battery, NTP desync. | `tachyon apply_quick_fix fix_system_time` |\n| **High latency or packet drop under heavy load** | Kernel `nf_conntrack` table overflow. | `tachyon apply_quick_fix flush_conntrack` |\n| **VLESS Reality connection timeout** | Reality SNI domain blocked or expired short ID. | Update server SNI to accessible target (e.g. `yahoo.com`). |\n| **Router runs out of RAM (OOM Crash)** | sing-box buffer explosion on low-RAM device (128 MB). | Lower `memory_limit_mb` in UCI settings (`GOMEMLIMIT=40MiB`). |\n\n---\n\n## 3. Diagnostic Commands Reference\n\n```sh\n# 1. Run local offline rule checks\ntachyon doctor\n\n# 2. Run AI Doctor with LLM analysis", "embedding": []}, {"id": 33, "file": "11_TROUBLESHOOTING_AND_FIELD_MANUAL.md", "heading": "4. Log Inspection Paths", "text": "| **Router runs out of RAM (OOM Crash)** | sing-box buffer explosion on low-RAM device (128 MB). | Lower `memory_limit_mb` in UCI settings (`GOMEMLIMIT=40MiB`). |\n\n---\n\n## 3. Diagnostic Commands Reference\n\n```sh\n# 1. Run local offline rule checks\ntachyon doctor\n\n# 2. Run AI Doctor with LLM analysis\ntachyon ai_doctor\n\n# 3. View real-time Watchdog telemetry\ntachyon ai_status_full\n\n# 4. Inspect active nftables firewall tables\nnft list table inet TachyonTable\n\n# 5. Inspect policy routing table 100\nip route show table 100\nip rule show\n\n# 6. Stream live Tachyon system logs\nlogread -f -e tachyon\n\n# 7. Check listening ports (TProxy 10080, DNS 5353, Clash 9090)\nnetstat -tulpn | grep -E 'sing-box|tachyon|5353|10080'\n```\n\n---\n\n## 4. Log Inspection Paths\n\n| Log Location | Content Description |\n|---|---|\n| `/var/log/tachyon_service.log` | Core service lifecycle events (start, stop, reload). |\n| `/var/log/tachyon_watchdog.log` | Background supervisor health checks and loop warnings. |\n| `/tmp/ai_doctor_last.json` | JSON report of the most recent AI Doctor diagnosis. |\n| `/tmp/tachyon/sing-box.json` | Generated live configuration compiled for sing-box. |\n| `/tmp/tachyon/hosts/combined.txt` | Consolidated deduplicated hosts list. |", "embedding": []}, {"id": 34, "file": "12_UCODE_PROGRAMMING_PATTERNS.md", "heading": "2.3. Safe Error Handling (`try-catch`)", "text": "# 12. ucode Programming Patterns & Conventions\n\nA developer's guide to writing safe, high-performance, and idiomatic **ucode** modules for Tachyon on OpenWrt.\n\n---\n\n## 1. ucode vs JavaScript: Critical Distinctions\n\nWhile ucode syntax resembles JavaScript, its runtime semantics differ significantly:\n\n1. **Variables & Scope**:\n * Always declare variables with `let` or `const`.\n * Unassigned variables are `null` (not `undefined`).\n2. **Arrays vs Dictionaries**:\n * Arrays: `[1, 2, 3]`. Iterated with `for (let item in array)`.\n * Dictionaries (Objects): `{\"key\": \"value\"}`. Iterated with `for (let key, val in dict)`.\n3. **Regular Expressions**:\n * Use `match(str, /regex/)` or `replace(str, /regex/g, \"replacement\")`.\n * Global flag `/g` works with `replace()`, while `match()` returns capture groups array `[full_match, group1, ...]`.\n4. **Boolean Coercion**:\n * Empty strings `\"\"`, `0`, and `null` are falsy. Everything else is truthy.\n\n---\n\n## 2. Mandatory Core Design Patterns\n\n### 2.1. Atomic Configuration Writes\nNever overwrite active configuration files in-place. Always write to a temporary file in `/tmp/` and atomically rename:\n\n```ucode\nlet fs = require(\"fs\");\n\nfunction write_atomic(path, content) {\n let tmp_path = path + \".tmp.\" + int(time());\n let f = fs.open(tmp_path, \"w\");\n if (!f) return false;\n \n f.write(content);\n f.close();\n \n return fs.rename(tmp_path, path);\n}\n```\n\n### 2.2. Shell Argument Quoting\nWhen executing external shell commands, all user inputs must be quoted safely:\n\n```ucode\nfunction shell_quote(value) {\n return \"'\" + replace(\"\" + value, /'/g, \"'\\\\''\") + \"'\";\n}\n\nfunction safe_exec(cmd_args) {\n let parts = [];\n for (let arg in cmd_args)\n push(parts, shell_quote(arg));\n return system(join(\" \", parts));\n}\n```\n\n### 2.3. Safe Error Handling (`try-catch`)\nAll external library loading or file parsing must be wrapped in `try-catch` blocks to avoid unhandled script panics:\n\n```ucode\nlet uci_data = null;", "embedding": []}, {"id": 35, "file": "12_UCODE_PROGRAMMING_PATTERNS.md", "heading": "3. Performance & Memory Optimization Guidelines", "text": "return system(join(\" \", parts));\n}\n```\n\n### 2.3. Safe Error Handling (`try-catch`)\nAll external library loading or file parsing must be wrapped in `try-catch` blocks to avoid unhandled script panics:\n\n```ucode\nlet uci_data = null;\ntry {\n let uci = require(\"uci\").cursor();\n uci_data = uci.get_all(\"tachyon\", \"settings\");\n}\ncatch (e) {\n warn(\"Failed to load UCI settings: \" + e + \"\\n\");\n}\n```\n\n---\n\n## 3. Performance & Memory Optimization Guidelines\n\n1. **Stream Large Files**: Avoid loading multi-megabyte blocklists entirely into RAM with `fs.readfile()`. Use line-by-line streaming via `fs.open()` and `f.read(\"line\")`.\n2. **Avoid Spawning Subprocesses in Loops**: Invoking `system()` or `fs.popen()` spawns a fork-exec sequence in Linux. Use native ucode functions for string manipulation and path operations whenever possible.\n3. **Keep Modules Stateless**: Module files under `usr/lib/tachyon/` should export reusable pure functions or class definitions rather than maintaining mutable global state.", "embedding": []}, {"id": 36, "file": "13_REST_API_AND_MCP_SPECIFICATION.md", "heading": "4. Model Context Protocol (MCP) Tool Definitions", "text": "# 13. HTTP REST Agent API & Model Context Protocol (MCP) Specification\n\nTachyon provides a standardized RESTful Agent API and Model Context Protocol (MCP) integration, enabling seamless orchestration by autonomous LLM agents (ChatGPT Actions, Claude Code, Cursor, Windsurf, N8N, Dify).\n\n---\n\n## 1. REST API Overview\n\n* **Base URL**: `http:///cgi-bin/tachyon-agent/`\n* **OpenAPI Schema**: `http:///cgi-bin/tachyon-agent/openapi.json`\n* **Content-Type**: `application/json`\n\n---\n\n## 2. Authentication Model\n\n1. **Read-Only Endpoints**: Unrestricted when accessed from local LAN.\n2. **Write Endpoints**: Require HTTP Authorization header:\n ```http\n Authorization: Bearer \n ```\n\n---\n\n## 3. Endpoint Reference & Payloads\n\n### 3.1. `GET /health`\nReturns lightweight status of all core daemons.\n```json\n{\n \"status\": \"healthy\",\n \"version\": \"1.2.86\",\n \"uptime_seconds\": 18450,\n \"singbox_running\": true,\n \"watchdog_running\": true,\n \"active_server\": \"Frankfurt_VLESS_Reality\"\n}\n```\n\n### 3.2. `GET /diagnose`\nReturns Local Rule Doctor checks and suggested repair codes.\n```json\n{\n \"status\": \"warning\",\n \"checks\": {\n \"dns_loop\": false,\n \"conntrack_full\": false,\n \"time_desync\": true,\n \"singbox_ok\": true\n },\n \"suggested_fixes\": [\"fix_system_time\"]\n}\n```\n\n### 3.3. `POST /ai-doctor/fix`\nApplies one or more quick-fix codes.\n* **Request**:\n ```json\n {\n \"fix\": \"clear_dns_cache,start_singbox\"\n }\n ```\n* **Response**:\n ```json\n {\n \"success\": true,\n \"applied_fixes\": [\"clear_dns_cache\", \"start_singbox\"],\n \"details\": \"DNS cache cleared. sing-box process restarted.\"\n }\n ```\n\n---\n\n## 4. Model Context Protocol (MCP) Tool Definitions\n\nFor MCP-compatible agents (Cursor, Claude Desktop), Tachyon exports tools via `GET /cgi-bin/tachyon-agent/tools`:\n\n```json\n[\n {\n \"name\": \"tachyon_diagnose\",\n \"description\": \"Run diagnostic checks on OpenWrt router network and proxy health\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {}", "embedding": []}, {"id": 37, "file": "13_REST_API_AND_MCP_SPECIFICATION.md", "heading": "4. Model Context Protocol (MCP) Tool Definitions", "text": "```json\n[\n {\n \"name\": \"tachyon_diagnose\",\n \"description\": \"Run diagnostic checks on OpenWrt router network and proxy health\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {}\n }\n },\n {\n \"name\": \"tachyon_apply_fix\",\n \"description\": \"Apply automated repair codes to fix router network or proxy issues\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"fix_codes\": {\n \"type\": \"string\",\n \"description\": \"Comma-separated list of fix codes (e.g. clear_dns_cache,restart_singbox)\"\n }\n },\n \"required\": [\"fix_codes\"]\n }\n },\n {\n \"name\": \"tachyon_switch_server\",\n \"description\": \"Switch active proxy server node\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"server_id\": {\n \"type\": \"string\",\n \"description\": \"Identifier of target proxy server\"\n }\n },\n \"required\": [\"server_id\"]\n }\n }\n]\n```", "embedding": []}, {"id": 38, "file": "14_ZAPRET2_DEEP_DIVE_MANUAL.md", "heading": "3.1. `multisplit` (Многосегментная фрагментация)", "text": "# 14. Руководство по Zapret v2 (nfqws2): Архитектура, Lua-десинхронизация и Стратегии\n\n## 1. Введение и Архитектурные отличия Zapret v2\n\nZapret v2 (`nfqws2`) — это эволюция классического `nfqws`, переписанная с акцентом на **модульную Lua-логику десинхронизации** и высокопроизводительное мультипрофилирование. В отличие от Zapret v1, где все параметры передавались через монолитные CLI-флаги `--dpi-desync-*`, в `nfqws2` обработка пакетов построена на вызове Lua-скриптов (`--lua-init`) и специализированных действий `--lua-desync`.\n\n### Ключевые преимущества `nfqws2`:\n1. **Мультипрофилирование в одном процессе:** возможность разделять правила для разных протоколов (HTTP, TLS, QUIC, UDP Voice) и диапазонов портов без запуска отдельных демонов.\n2. **Гибкое позиционирование фрагментов (`pos`):** поддержка составных позиций сплита (`pos=1,midsld,sniext+4`), позволяющих резать пакет ровно в уязвимых местах сигнатур DPI.\n3. **Управление перекрытием (`seqovl`):** внедрение контролируемого наложения TCP Sequence чисел (`seqovl=1..2`), сбивающего стейтфул-реассемблеры ТСПУ.\n4. **Контроль размера TCP окна (`wsize`):** принудительное занижение Window Size в исходящих пакетах (`wsize=1`), заставляющее сервер и стек дробить поток на однобайтовые сегменты.\n\n---\n\n## 2. Формат командной строки и Lua-инициализация\n\nTachyon запускает `nfqws2` со стандартным набором Lua-библиотек из `/opt/zapret2/lua/`:\n```bash\n/opt/zapret2/nfq2/nfqws2 \\\n --qnum= \\\n --fwmark= \\\n --lua-init=@/opt/zapret2/lua/zapret-lib.lua \\\n --lua-init=@/opt/zapret2/lua/zapret-antidpi.lua \\\n --lua-init=@/opt/zapret2/lua/zapret-auto.lua \\\n [СТРАТЕГИИ]\n```\n\n---\n\n## 3. Функции Lua-десинхронизации (`--lua-desync`)\n\nВ `nfqws2` действия десинхронизации задаются через параметр `--lua-desync=<функция>[:ключ=значение[:ключ2=значение2]]`.\n\n### 3.1. `multisplit` (Многосегментная фрагментация)\nОсновная и самая эффективная функция против современных ТСПУ.\n- **Синтаксис:** `--lua-desync=multisplit:pos=<позиции>[:seqovl=][:fooling=<метод>][:wsize=]`", "embedding": []}, {"id": 39, "file": "14_ZAPRET2_DEEP_DIVE_MANUAL.md", "heading": "4. Методы дурения DPI (`fooling`)", "text": "### 3.1. `multisplit` (Многосегментная фрагментация)\nОсновная и самая эффективная функция против современных ТСПУ.\n- **Синтаксис:** `--lua-desync=multisplit:pos=<позиции>[:seqovl=][:fooling=<метод>][:wsize=]`\n- **Параметры `pos`:**\n - `pos=1` — сплит на 1-м байте payload (режет TLS ClientHello на этапе Handshake Type).\n - `pos=midsld` — сплит посередине Second Level Domain внутри SNI (например, `you` | `tube.com`).\n - `pos=sniext` — сплит в начале блока расширений TLS SNI.\n - `pos=sniext+4` — сплит на 4 байта глубже расширения SNI (разрывает парсер расширений DPI).\n - `pos=1,midsld,sniext+2` — тройной сплит, создающий 3 фрагмента с высоким уровнем энтропии.\n- **Параметр `seqovl` (Sequence Overlap):**\n - `seqovl=1` или `seqovl=2` — второй фрагмент отправляется со сдвигом TCP Sequence назад на 1–2 байта. DPI видит конфликт перекрытия данных и пропускает поток, в то время как целевой сервер корректно отбрасывает дублирующийся байт.\n- **Параметр `wsize`:**\n - `wsize=1` — зажимает размер TCP-окна, препятствуя реассемблингу со стороны DPI.\n\n### 3.2. `fake` (Инжекция фейковых пакетов)\nОтправка ложного ClientHello с некорректным SNI или контрольной суммой перед настоящим пакетом.\n- **Синтаксис:** `--lua-desync=fake[:ttl=][:fooling=<метод>]`\n- **Параметры:**\n - `ttl=6` / `ttl=8` — Time-To-Live фейкового пакета. Должен быть достаточным, чтобы долететь до ТСПУ провайдера, но недостаточным, чтобы дойти до сервера назначения.\n - `fooling=badseq` — отправка фейка с невалидным TCP Sequence номером.\n - `fooling=md5sig` — добавление TCP Option 19 (MD5 Signature) в фейковый пакет. ТСПУ часто пассивно анализирует такой пакет и сбрасывает стейт сессии, а сервер назначения дропает его из-за отсутствия MD5-ключа.\n\n### 3.3. `split2` и `disorder2`\n- `split2:pos=` — классическое деление пакета на 2 части в указанной позиции.\n- `disorder2:pos=` — деление на 2 части с обратным порядком отправки (сначала хвост, затем голова).\n\n---\n\n## 4. Методы дурения DPI (`fooling`)", "embedding": []}, {"id": 40, "file": "14_ZAPRET2_DEEP_DIVE_MANUAL.md", "heading": "Instagram & Meta (TLS 1.3 / ECH)", "text": "- `split2:pos=` — классическое деление пакета на 2 части в указанной позиции.\n- `disorder2:pos=` — деление на 2 части с обратным порядком отправки (сначала хвост, затем голова).\n\n---\n\n## 4. Методы дурения DPI (`fooling`)\n\n| Метод | Механизм действия | Когда применять |\n|---|---|---|\n| `badseq` | Фейковый пакет имеет ACK/SEQ вне текущего окна TCP. | Универсально против большинства ТСПУ (Ростелеком, МТС, Мегафон, Билайн). |\n| `md5sig` | Пакет содержит TCP MD5 Signature Option (RFC 2385). | Эффективно, если ТСПУ валидирует опции TCP и дропает сессию. |\n| `badack` | Инвертированный или повреждённый ACK-номер. | Против DPI с жестким контролем двустороннего TCP-хэндшейка. |\n| `datanoack` | Данные в сегменте передаются без флага ACK. | Обход сигнатур, триггерящихся только на валидные ACK-сегменты. |\n\n---\n\n## 5. Готовые шаблоны стратегий под сервисы\n\n### YouTube 4K (GoogleVideo chunk stream)\n```text\n--lua-desync=multisplit:pos=1,midsld:seqovl=1:fooling=badseq\n```\n*Разрывает SNI googlevideo и ClientHello, предотвращая троттлинг видеопотока 2160p60.*\n\n### Discord (Gateway, API и Голосовые каналы UDP)\n```text\n--filter-tcp=443 --lua-desync=multisplit:pos=1,sniext+4:seqovl=1:fooling=badseq --new --filter-udp=50000-65535 --lua-desync=fake:ttl=8\n```\n*Комбинированный профиль: TCP 443 для шлюза сообщений и UDP-фейк для RTC Voice серверов.*\n\n### Instagram & Meta (TLS 1.3 / ECH)\n```text\n--lua-desync=fake:ttl=8 --lua-desync=multisplit:pos=midsld:fooling=badseq\n```\n*Низко-TTL фейк перегружает стейт ТСПУ, после чего фрагментированный TLS 1.3 хэндшейк проходит без сброса.*", "embedding": []}, {"id": 41, "file": "15_ZAPRET1_NFQWS_FIELD_GUIDE.md", "heading": "4. Перекрытие Sequence (`--dpi-desync-split-seqovl`)", "text": "# 15. Руководство по Zapret v1 (nfqws): Полная спецификация и рецепты\n\n## 1. Архитектура и принцип работы `nfqws` (Zapret v1)\n\nКлассический `nfqws` — это высокопроизводительный демон перехвата пакетов через Linux Netfilter Queue (`NFQUEUE`). Он работает на уровне ядра и L4/L7 сетевого стека, перехватывая исходящие TCP и UDP соединения до отправки в физический сетевой интерфейс и модифицируя структуру пакетов.\n\n---\n\n## 2. Основные параметры десинхронизации (`--dpi-desync`)\n\nВ Zapret v1 режим десинхронизации задается флагом `--dpi-desync=<режим1>,<режим2>`.\n\n| Режим | Описание | Механика |\n|---|---|---|\n| `split2` | Деление пакета на 2 части | Пакет режется на 2 TCP-сегмента по указанной позиции. |\n| `disorder2` | Деление с обратной отправкой | Сегменты отправляются в порядке [хвост, голова]. |\n| `fake` | Инжекция фейкового пакета | Перед реальным запросом отправляется ложный payload с низким TTL. |\n| `multisplit` | Множественная фрагментация | Пакет делится на 3+ сегмента по списку позиций. |\n| `ipfrag2` | IP-фрагментация | Фрагментация на сетевом уровне L3 (IP-пакет делится на части). |\n| `syndata` | Данные в SYN пакете | Внедрение полезной нагрузки в первый TCP SYN пакет (TCP Fast Open). |\n\n---\n\n## 3. Позиционирование сплита (`--dpi-desync-split-pos`)\n\nПараметр `--dpi-desync-split-pos` определяет точное смещение (байт), по которому происходит разрезание TCP-сегмента:\n- `--dpi-desync-split-pos=1` — сплит на 1-м байте payload. Разрывает первый байт TLS Content Type (`0x16`).\n- `--dpi-desync-split-pos=2` — сплит на 2-м байте. Разрывает версию TLS (`0x0301`).\n- `--dpi-desync-split-pos=midsld` — сплит посередине доменного имени второго уровня в SNI.\n- `--dpi-desync-split-pos=sniext+4` — сплит в блоке TLS расширений.\n- `--dpi-desync-split-pos=1,midsld` — комбинированное разделение.\n\n---\n\n## 4. Перекрытие Sequence (`--dpi-desync-split-seqovl`)\n\n- `--dpi-desync-split-seqovl=1` или `2` — при сплите второй сегмент имеет начальный Sequence номер, заходящий на N байт назад (перекрывает конец первого сегмента).", "embedding": []}, {"id": 42, "file": "15_ZAPRET1_NFQWS_FIELD_GUIDE.md", "heading": "3. State-DPI Bypass (Перекрытие TCP Sequence)", "text": "## 4. Перекрытие Sequence (`--dpi-desync-split-seqovl`)\n\n- `--dpi-desync-split-seqovl=1` или `2` — при сплите второй сегмент имеет начальный Sequence номер, заходящий на N байт назад (перекрывает конец первого сегмента).\n- ТСПУ видит коллизию данных в потоке и сбрасывает проверку, а сервер назначения корректно дедуплицирует байты по RFC 793.\n\n---\n\n## 5. Методы дурения ТСПУ (`--dpi-desync-fooling`)\n\n- `badseq` — отправка фейка с невалидным Sequence номером.\n- `md5sig` — добавление опции TCP MD5 signature, заставляющей DPI дропнуть фейк или пропустить сессию.\n- `badack` — невалидный номер подтверждения ACK.\n- `hopbyhop` — добавление IPv6 Hop-by-Hop extension header.\n\n---\n\n## 6. Проверенные рецепты для Zapret v1\n\n### 1. YouTube 4K / Web\n```text\n--dpi-desync=fake,split2 --dpi-desync-split-pos=1 --dpi-desync-ttl=8 --dpi-desync-fooling=badseq\n```\n\n### 2. RuTracker & Заблокированные HTTP/HTTPS ресурсы\n```text\n--dpi-desync=disorder2 --dpi-desync-split-pos=1 --dpi-desync-fooling=badseq\n```\n\n### 3. State-DPI Bypass (Перекрытие TCP Sequence)\n```text\n--dpi-desync=split2 --dpi-desync-split-seqovl=1 --dpi-desync-fooling=badseq\n```", "embedding": []}, {"id": 43, "file": "16_BYEDPI_CIADPI_REFERENCE.md", "heading": "2.6. Дополнительные опции", "text": "# 16. Справочник по ByeDPI (ciadpi): SOCKS5/TProxy десинхронизация\n\n## 1. Архитектура и принцип работы ByeDPI (`ciadpi`)\n\n`ciadpi` (ByeDPI) — это легковесный локальный прокси-сервер (SOCKS5 / Transparent TCP), который принимает исходящий трафик и выполняет фрагментацию и манипуляцию пакетами на сокетовом уровне (L7/L4). \n\n### Ключевое отличие от Zapret:\n- Zapret работает через перехват `NFQUEUE` (L3/L4 фильтрация ядра).\n- ByeDPI работает как SOCKS5 прокси (по умолчанию порт `4539` в Tachyon) или прозрачный прокси, модифицируя TCP payload непосредственно перед системным вызовом `send()`/`write()`.\n\n---\n\n## 2. Основные параметры командной строки ByeDPI\n\n### 2.1. Фрагментация (`--split` / `-s`)\n- `--split <позиция>` или `-s <позиция>`\n- **Значения позиции:**\n - `1` — сплит на 1-м байте payload.\n - `2` — сплит на 2-м байте.\n - `1+sniext` — сплит в начале блока TLS SNI расширений.\n - `midsld` — сплит посередине SLD домена.\n\n### 2.2. Изменение порядка сегментов (`--disorder` / `-d`)\n- `--disorder <позиция>` или `-d <позиция>`\n- Отправляет первый сегмент с задержкой или после второго сегмента (out-of-order delivery).\n\n### 2.3. Инжекция фейковых пакетов (`--fake` / `-f` и `--ttl` / `-t`)\n- `--fake <смещение>` или `-f <смещение>` — смещение вставки фейкового пакета (`-1` = перед началом реального запроса).\n- `--ttl ` или `-t ` — Time-To-Live для фейковых пакетов (обычно `4..8` в зависимости от провайдера).\n\n### 2.4. Out-of-Band данные (`--oob` / `-o`)\n- `--oob <смещение>` или `-o <смещение>` — отправка одного срочного байта TCP OOB (Urgent Pointer) на указанном смещении. Ломает разбор буфера в DPI, заставляя его пропустить пакет.\n\n### 2.5. Автоматический режим (`--auto` / `-a`)\n- `--auto=t,r,a,s`\n- Адаптивный режим подбора: ByeDPI автоматически пробует комбинации флагов при обнаружении сброса соединения или таймаута:\n - `t` — TLS Record splitting\n - `r` — Reverse disorder\n - `a` — Auto-ttl\n - `s` — Simple split\n\n### 2.6. Дополнительные опции\n- `--tlsrec ` / `-r ` — деление одного ClientHello на несколько независимых TLS Records.", "embedding": []}, {"id": 44, "file": "16_BYEDPI_CIADPI_REFERENCE.md", "heading": "4. Агрессивный низко-TTL фейк", "text": "- `t` — TLS Record splitting\n - `r` — Reverse disorder\n - `a` — Auto-ttl\n - `s` — Simple split\n\n### 2.6. Дополнительные опции\n- `--tlsrec ` / `-r ` — деление одного ClientHello на несколько независимых TLS Records.\n- `--ip-frag` — включение фрагментации на уровне IP.\n- `--mod-http` / `-M` — модификация HTTP заголовков (манипуляция Host/символами переноса строки).\n\n---\n\n## 3. Рецепты ByeDPI\n\n### 1. Универсальный адаптивный авто-режим\n```text\n-o 2 --auto=t,r,a,s -d 2\n```\n\n### 2. Disorder + Fake с контролем TTL\n```text\n--split 1 --disorder 1 --fake -1 --ttl 8\n```\n\n### 3. SNI Extension Split + Fake\n```text\n-s 1+sniext -f -1 -t 6\n```\n\n### 4. Агрессивный низко-TTL фейк\n```text\n--fake -1 --ttl 4 --disorder 1 --split 1\n```", "embedding": []}, {"id": 45, "file": "17_TSPU_DPI_SIGNATURES_AND_COUNTERS.md", "heading": "2.3. Instagram & Meta (TLS 1.3 / ECH)", "text": "# 17. Сигнатуры ТСПУ (РКН) и методы противодействия десинхронизацией\n\n## 1. Архитектура и принципы работы ТСПУ\n\nТСПУ (Технические средства противодействия угрозам) — это аппаратно-программные комплексы глубокого анализа пакетов (DPI), установленные на сетях операторов связи в РФ. \n\n### Основные режимы фильтрации:\n1. **Пассивный анализ (In-line / TAP):** ТСПУ прослушивает зеркалированный трафик. При обнаружении запрещенного SNI или URL генерирует и инжектирует TCP RST пакет в обе стороны соединения.\n2. **Активный дроп (In-line Drop):** ТСПУ установлен в разрыв канала и физически отбрасывает пакеты сессии, вызывая `Connection Timeout` или `EOF`.\n3. **Троттлинг (Шейпинг по L7-сигнатурам):** Ограничение пропускной способности (например, до 128 Кбит/с) при обнаружении определённых потоков данных (YouTube `googlevideo.com` CDN).\n\n---\n\n## 2. Анализ блокировок по ключевым сервисам\n\n### 2.1. YouTube (GoogleVideo 4K троттлинг)\n- **Механика блокировки:** ТСПУ анализирует TLS ClientHello при обращении к CDN-нодам `rr*.googlevideo.com`. При совпадении сигнатуры ТСПУ не закрывает соединение сразу, а переводит TCP-сессию в режим искусственного ограничения скорости или отбрасывает чанки видео.\n- **Эффективное противодействие:**\n - `multisplit:pos=1,midsld:seqovl=1:fooling=badseq` (Zapret v2)\n - `fake,split2:pos=1:ttl=8:fooling=badseq` (Zapret v1)\n - Сплит на `midsld` разрывает домен `googlevideo` пополам, предотвращая сработку строкового парсера ТСПУ.\n\n### 2.2. Discord (Gateway + Голосовые каналы RTC)\n- **Механика блокировки:** Блокировка состоит из двух компонентов:\n 1. TCP 443 — шлюз сообщений и API (`discord.com`, `gateway.discord.gg`).\n 2. UDP 50000-65535 — голосовые сессии WebRTC / Voice.\n- **Эффективное противодействие:**\n - Мультипрофиль `zapret2`:\n - Для TCP 443: `--filter-tcp=443 --lua-desync=multisplit:pos=1,sniext+4:seqovl=1:fooling=badseq`\n - Для UDP Voice: `--filter-udp=50000-65535 --lua-desync=fake:ttl=8`\n\n### 2.3. Instagram & Meta (TLS 1.3 / ECH)\n- **Механика блокировки:** ТСПУ сбрасывает TCP-соединение инжекцией RST-пакета сразу после получения первого ClientHello с открытым SNI `instagram.com`.", "embedding": []}, {"id": 46, "file": "17_TSPU_DPI_SIGNATURES_AND_COUNTERS.md", "heading": "3. Вычисление оптимального TTL до ТСПУ", "text": "- Для UDP Voice: `--filter-udp=50000-65535 --lua-desync=fake:ttl=8`\n\n### 2.3. Instagram & Meta (TLS 1.3 / ECH)\n- **Механика блокировки:** ТСПУ сбрасывает TCP-соединение инжекцией RST-пакета сразу после получения первого ClientHello с открытым SNI `instagram.com`.\n- **Эффективное противодействие:**\n - Низко-TTL фейк с `fooling=badseq` или `fooling=md5sig`, за которым следует сегментированный TLS-хэндшейк. ТСПУ «съедает» фейковый пакет и блокирует его, игнорируя последующий настоящий запрос.\n\n### 2.4. RuTracker & Сайты из реестра РКН\n- **Механика блокировки:** HTTP перенаправление на заглушку провайдера (302 Redirect) или TCP RST на HTTPS SNI.\n- **Эффективное противодействие:**\n - `disorder2:pos=1` или `split2:pos=1:seqovl=1` нарушает сборку HTTP/TLS заголовка в DPI.\n\n---\n\n## 3. Вычисление оптимального TTL до ТСПУ\n\nДля стратегий с инжекцией фейковых пакетов (`fake`) критически важно подобрать параметр `ttl`:\n- **Слишком маленький TTL (< 3):** фейковый пакет умирает на маршрутизаторах провайдера до того, как долетит до ТСПУ. ТСПУ видит реальный пакет и блокирует сессию.\n- **Слишком большой TTL (> 15):** фейковый пакет долетает до сервера назначения, и сервер разрывает соединение из-за невалидного хэндшейка.\n- **Оптимальный диапазон:** `TTL = 6..8` для большинства магистральных операторов РФ.", "embedding": []}, {"id": 47, "file": "INDEX.md", "heading": "📚 Knowledge Base Table of Contents", "text": "# Tachyon Knowledge Base & Architecture Index\n\nWelcome to the comprehensive technical knowledge base for **Tachyon**. This directory contains deep architectural specifications, module references, packet flow maps, and developer guidelines compiled directly from the codebase.\n\n---\n\n## 📚 Knowledge Base Table of Contents\n\n| Document | Description | Key Topics Covered |\n|---|---|---|\n| [**01. System Architecture**](01_SYSTEM_ARCHITECTURE.md) | High-level system architecture & control plane | ucode runtime, atomic writes, repository layout, daemon lifecycle |\n| [**02. ucode Module Reference**](02_UCODE_MODULE_REFERENCE.md) | Comprehensive reference for all 60+ `.uc` files | `core/`, `service/`, `diagnostics/`, `singbox/`, `providers/`, `nft/`, `dns/` |\n| [**03. Networking & nftables**](03_NETWORKING_NFTABLES_AND_ROUTING.md) | Packet lifecycle, firewall tables & DNS routing | `inet TachyonTable`, fwmark bitmasks, TProxy, bootstrap DNS loops |\n| [**04. DPI Bypass Engines**](04_DPI_BYPASS_ENGINES.md) | Local packet desynchronization deep dive | Zapret v1 (`nfqws`), Zapret v2 (`nfqws2`), ByeDPI (`ciadpi`), multisplit, seqovl |\n| [**05. AI Stack & AI Doctor**](05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md) | AI Doctor v2.5, Watchdog & REST Agent API | 13 Quick Fixes, Local Rule Doctor, NTP/MTU tuning, OpenAPI 3.0.3, REST API |\n| [**06. Frontend LuCI Architecture**](06_FRONTEND_LUCI_TYPESCRIPT.md) | TypeScript SPA & LuCI view integration | `baseclass.extend` patch, reactive stores, live log streaming modal |\n| [**07. Build & Testing Pipeline**](07_BUILD_TESTS_AND_DEPLOYMENT.md) | Compilation, testing & release workflows | `build.sh` (ipk/apk), `install.sh`, Docker CI container, vitest tests |\n| [**08. UCI Configuration Schema**](08_UCI_CONFIGURATION_SCHEMA.md) | Complete `/etc/config/tachyon` reference | All UCI sections, options, validators, default values, ready recipes |\n| [**09. Telegram Bot Architecture**](09_TELEGRAM_BOT_ARCHITECTURE.md) | Remote Telegram control daemon protocol | Long-polling model, inline keyboards, callback query routing, security |", "embedding": []}, {"id": 48, "file": "INDEX.md", "heading": "Diagnostics & AI", "text": "| [**08. UCI Configuration Schema**](08_UCI_CONFIGURATION_SCHEMA.md) | Complete `/etc/config/tachyon` reference | All UCI sections, options, validators, default values, ready recipes |\n| [**09. Telegram Bot Architecture**](09_TELEGRAM_BOT_ARCHITECTURE.md) | Remote Telegram control daemon protocol | Long-polling model, inline keyboards, callback query routing, security |\n| [**10. Hosts Engine & Blocklists**](10_HOSTS_ENGINE_AND_BLOCKLISTS.md) | Hosts ingestion, parsing & smart caching | `combined.txt`, multi-format parsing, GitHub mirror retry resiliency |\n| [**11. Troubleshooting Manual**](11_TROUBLESHOOTING_AND_FIELD_MANUAL.md) | Field diagnostics & emergency recovery | Symptom resolution matrix, diagnostic commands, log inspection paths |\n| [**12. ucode Programming Patterns**](12_UCODE_PROGRAMMING_PATTERNS.md) | Developer guidelines for OpenWrt ucode | Atomic file writes, shell quoting, libuci bindings, RAM efficiency |\n| [**13. REST API & MCP Specification**](13_REST_API_AND_MCP_SPECIFICATION.md) | REST Agent API & MCP tool definitions | OpenAPI 3.0.3, Bearer Auth, OpenAI Function Calling, MCP JSON schema |\n| [**14. Zapret v2 (nfqws2) Deep Dive**](14_ZAPRET2_DEEP_DIVE_MANUAL.md) | Comprehensive Zapret v2 Lua manual | Lua desync functions, multisplit, seqovl, wsize, fooling, multi-profiles |\n| [**15. Zapret v1 (nfqws) Field Guide**](15_ZAPRET1_NFQWS_FIELD_GUIDE.md) | Complete Zapret v1 CLI specification | NFQUEUE desync modes, split-pos, seqovl, syndata, ipfrag, fooling |\n| [**16. ByeDPI (ciadpi) Reference**](16_BYEDPI_CIADPI_REFERENCE.md) | Complete ByeDPI SOCKS5/TProxy manual | Split, disorder, fake, ttl, auto-mode, oob, tlsrec, ip-frag |\n| [**17. TSPU / DPI Signatures & Counters**](17_TSPU_DPI_SIGNATURES_AND_COUNTERS.md) | TSPU filtering mechanics and counters | GoogleVideo 4K, Discord WebRTC, TLS 1.3 RST, TTL distance calculation |\n\n---\n\n## ⚡ Quick Operational Cheat Sheet\n\n### Common CLI Commands\n```sh\n# Diagnostics & AI\ntachyon doctor # Local offline rule diagnostics", "embedding": []}, {"id": 49, "file": "INDEX.md", "heading": "Full backend suite in Docker CI", "text": "| [**17. TSPU / DPI Signatures & Counters**](17_TSPU_DPI_SIGNATURES_AND_COUNTERS.md) | TSPU filtering mechanics and counters | GoogleVideo 4K, Discord WebRTC, TLS 1.3 RST, TTL distance calculation |\n\n---\n\n## ⚡ Quick Operational Cheat Sheet\n\n### Common CLI Commands\n```sh\n# Diagnostics & AI\ntachyon doctor # Local offline rule diagnostics\ntachyon ai_doctor # AI Doctor LLM analysis\ntachyon apply_quick_fix # Apply automated repair codes\ntachyon restore_native_internet # 1-Click emergency WAN restore\n\n# Service & Watchdog\ntachyon ai_heal # Trigger immediate self-healing cycle\ntachyon ai_status # Concise Watchdog status JSON\ntachyon ai_status_full # Full Watchdog telemetry JSON\n\n# Component Management\ntachyon check_update # Check for component updates\ntachyon component_action install # Install or update component\n```\n\n### Local Test Execution\n```sh\n# Frontend vitest suite\nnpm --prefix fe-app-tachyon test\n\n# Full backend suite in Docker CI\ndocker run --rm -v \"$(pwd):/mnt\" -w /mnt ucode-ci-img:latest bash tests/run_all.sh\n```", "embedding": []}]} \ No newline at end of file diff --git a/tachyon/files/usr/lib/service/event_controller.uc b/tachyon/files/usr/lib/service/event_controller.uc index 0a8ae32d..b77ed3a6 100644 --- a/tachyon/files/usr/lib/service/event_controller.uc +++ b/tachyon/files/usr/lib/service/event_controller.uc @@ -559,11 +559,26 @@ function controller(bus, opts) { let started = time(); let ok = command_success_from_args([ - "curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", + "curl", "-s", "-o", "/dev/null", "--connect-timeout", "3", "--max-time", "5", "--proxy", "http://" + host + ":" + port, check_url ]); + + // Fallback confirmation: never declare proxy down based on a single URL. + // Cloudflare or specific CDN endpoints can encounter rate limits or transient DPI packet loss. + let fallback_url = null; + if (!ok) { + fallback_url = index(check_url, "gstatic.com") >= 0 + ? "https://detectportal.firefox.com/success.txt" + : "https://connectivitycheck.gstatic.com/generate_204"; + ok = command_success_from_args([ + "curl", "-s", "-o", "/dev/null", + "--connect-timeout", "3", "--max-time", "5", + "--proxy", "http://" + host + ":" + port, + fallback_url + ]); + } let elapsed = (time() - started) * 1000; state.proxy_latency_history = push_history(state.proxy_latency_history, @@ -579,13 +594,18 @@ function controller(bus, opts) { // Distinguish "proxy is broken" from "the whole uplink is down": only // the former is worth restarting sing-box over. - // Use the same URL as the proxy check so the two measurements are - // comparable: if the user changed ai_proxy_health_url, direct_ok - // must probe the same target, not always fall back to Cloudflare. + // Check primary URL, and if that fails, check fallback URL directly too + // in case the primary URL is blocked directly on the ISP WAN. let direct_ok = command_success_from_args([ "curl", "-s", "-I", "--connect-timeout", "3", "--max-time", "5", check_url ]); + if (!direct_ok && fallback_url != null) { + direct_ok = command_success_from_args([ + "curl", "-s", "-I", "--connect-timeout", "3", "--max-time", "5", + fallback_url + ]); + } bus.emit(EV.PROXY_DOWN, { host: host, diff --git a/tachyon/files/usr/lib/service/lifecycle.uc b/tachyon/files/usr/lib/service/lifecycle.uc index bd8cd976..865564c4 100644 --- a/tachyon/files/usr/lib/service/lifecycle.uc +++ b/tachyon/files/usr/lib/service/lifecycle.uc @@ -698,7 +698,9 @@ function singbox_init_config() { subscription_runtime_no_refresh ]); if (result.status == 0) { - subscription_deferred_sections = trim(result.output); + let out = trim(result.output); + if (out != "") + subscription_deferred_sections = out; subscription_caches_prepared = "1"; } return result.status; @@ -1119,6 +1121,8 @@ function start() { return status; } + module_status(STATE_UC, [ "run-pending-reload-if-requested", PENDING_RELOAD_FILE, SERVICE_INIT ]); + return 0; } diff --git a/tachyon/files/usr/lib/service/parental_quota.uc b/tachyon/files/usr/lib/service/parental_quota.uc index 1f5af6fb..af8fe419 100644 --- a/tachyon/files/usr/lib/service/parental_quota.uc +++ b/tachyon/files/usr/lib/service/parental_quota.uc @@ -256,9 +256,9 @@ function send_notification(message) { system(common.background_command(TACHYON_BIN + " telegram send " + shell_quote(message))); } -function nft_chain_has_quota(chain) { +function nft_chain_has_quota(chain, match_type) { let output = command_output_from_args([ "nft", "list", "chain", "inet", NFT_TABLE_NAME, chain ]) || ""; - return index(output, "tachyon-quota") >= 0; + return index(output, "tachyon-quota-" + match_type) >= 0; } function nft_table_exists() { @@ -282,7 +282,7 @@ function nft_create_set(set_name, set_type) { function nft_insert_quota_rule(chain, match_type) { let set_name = match_type == "ether" ? SET_ETHER : SET_IP; let addr_type = match_type == "ether" ? "ether" : "ip"; - let cmd = "nft add rule inet " + NFT_TABLE_NAME + " " + chain + " " + addr_type + " saddr @" + set_name + " counter drop comment \"tachyon-quota\""; + let cmd = "nft add rule inet " + NFT_TABLE_NAME + " " + chain + " " + addr_type + " saddr @" + set_name + " counter drop comment \"tachyon-quota-" + match_type + "\""; let rc = command_status(cmd + " 2>/dev/null"); if (rc != 0) log_message("failed to insert quota rule in " + chain + " for " + match_type + ": " + as_string(rc), "warn"); @@ -302,23 +302,24 @@ function ensure_nft_rules() { nft_create_set(SET_IP, "ipv4_addr"); // Insert drop rules into parental chains (idempotent via comment check) - if (!nft_chain_has_quota("parental_control")) + if (!nft_chain_has_quota("parental_control", "ether")) nft_insert_quota_rule("parental_control", "ether"); - if (!nft_chain_has_quota("parental_control")) + if (!nft_chain_has_quota("parental_control", "ip")) nft_insert_quota_rule("parental_control", "ip"); - if (!nft_chain_has_quota("parental_forward")) + if (!nft_chain_has_quota("parental_forward", "ether")) nft_insert_quota_rule("parental_forward", "ether"); - if (!nft_chain_has_quota("parental_forward")) + if (!nft_chain_has_quota("parental_forward", "ip")) nft_insert_quota_rule("parental_forward", "ip"); return true; } function sync_block_set(set_name, idents) { - command_status(command_from_args([ "nft", "flush", "set", "inet", NFT_TABLE_NAME, set_name ]) + " >/dev/null 2>&1"); + command_status("nft flush set inet " + NFT_TABLE_NAME + " " + set_name + " >/dev/null 2>&1"); if (length(idents) > 0) { - let cmd = command_from_args([ "nft", "add", "element", "inet", NFT_TABLE_NAME, set_name, "{ " + join(", ", idents) + " }" ]); - if (!command_success_from_args(cmd)) - log_message("failed to sync nft set " + set_name + " with " + as_string(length(idents)) + " elements", "warn"); + let cmd = "nft add element inet " + NFT_TABLE_NAME + " " + set_name + " { " + join(", ", idents) + " }"; + let rc = command_status(cmd + " 2>/dev/null"); + if (rc != 0) + log_message("failed to sync nft set " + set_name + " with " + as_string(length(idents)) + " elements: " + as_string(rc), "warn"); } } @@ -550,17 +551,27 @@ function status_json() { }); } +function reset_quotas() { + let today = today_str(); + write_state({ day: today, devices: {}, guest_devices: {} }); + sync_enforcement([], []); + log_message("quotas have been manually reset", "info"); + return 0; +} + let mode = ARGV[0] || ""; if (mode == "tick") exit(tick()); else if (mode == "status") status_json(); +else if (mode == "reset") + exit(reset_quotas()); else if (mode == "install-cron") exit(install_cron()); else if (mode == "remove-cron") exit(remove_cron()); else { - warn("Usage: service/parental_quota.uc \n"); + warn("Usage: service/parental_quota.uc \n"); exit(1); } diff --git a/tachyon/files/usr/lib/service/watchdog.uc b/tachyon/files/usr/lib/service/watchdog.uc index bbca7518..0fe1851c 100644 --- a/tachyon/files/usr/lib/service/watchdog.uc +++ b/tachyon/files/usr/lib/service/watchdog.uc @@ -855,6 +855,10 @@ function heal_dns_stall(ev) { // would drop live connections for nothing. function heal_proxy_connectivity(ev) { if (settings().recovery_bypass == "1") return; + // When dedicated proxy health monitoring is enabled, heal_proxy_health owns + // the threshold, config validation, and reporting. heal_proxy_connectivity + // acts as fallback when ai_proxy_health_enabled is "0". + if (settings().ai_proxy_health_enabled != "0") return; if (!ev.payload.direct_ok) return; // Two consecutive failures before acting: a single brief proxy-node timeout // (e.g. URLTest selecting a slow node for 5–10s) must not wipe cache.db and @@ -877,6 +881,7 @@ function heal_proxy_connectivity(ev) { "Очищена база cache.db; перезапуск пропущен по лимиту частоты", "skipped"); return; } + controller.reset_proxy_consecutive(); watch_recovery("proxy", incident, "proxy_connectivity"); } @@ -1026,6 +1031,11 @@ function validate_singbox_config() { // of failures and validates the sing-box config before restarting. function heal_proxy_health(ev) { if (settings().ai_proxy_health_enabled == "0") return; + if (settings().recovery_bypass == "1") return; + // Only a proxy that fails while direct access works is worth restarting + // over: when direct access is down too, the fault is upstream/WAN and a + // restart would drop live connections for nothing. + if (!ev.payload.direct_ok) return; let threshold = int(settings().ai_proxy_health_fail_threshold || "3"); let fails = int(ev.payload.streak); @@ -1034,8 +1044,8 @@ function heal_proxy_health(ev) { let incident = { type: "proxy_health", - description: sprintf("Proxy health check failed %d times consecutively (port %s)", fails, as_string(ev.payload.port)), - resolution: "Restarting Tachyon to restore proxy connectivity" + description: sprintf("Прокси не отвечает на запросы проверки доступности (%d сбоя подряд, порт %s)", fails, as_string(ev.payload.port)), + resolution: "Выполнен перезапуск sing-box" }; // A restart on a config sing-box will refuse to load leaves the proxy down @@ -1761,7 +1771,7 @@ function register_subscribers() { subscribe(EV.PROXY_DOWN, heal_proxy_connectivity, { name: "heal_proxy_connectivity", priority: PRIORITY_PROXY, cooldown: 120 }); subscribe(EV.PROXY_DOWN, heal_proxy_health, - { name: "heal_proxy_health", priority: PRIORITY_PROXY + 1 }); + { name: "heal_proxy_health", priority: PRIORITY_PROXY + 1, cooldown: 120 }); // Same split for DNS: ai_heal_dns_continuous was fast, ai_heal_dns was part // of the normal-tier audit. The streak the stall healer thresholds on is diff --git a/tachyon/files/usr/lib/singbox/generator.uc b/tachyon/files/usr/lib/singbox/generator.uc index b2daa2cd..a049e19f 100644 --- a/tachyon/files/usr/lib/singbox/generator.uc +++ b/tachyon/files/usr/lib/singbox/generator.uc @@ -22,6 +22,8 @@ let fixture_uci_data = null; let runtime_settings_cache = null; let runtime_ruleset_folder = runtime_constants.TMP_RULESET_FOLDER; let runtime_supports_xhttp = true; +const TACHYON_RUNTIME_STATE_DIR = getenv("TACHYON_RUNTIME_STATE_DIR") || "/var/run/tachyon"; +const TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE = getenv("TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE") || TACHYON_RUNTIME_STATE_DIR + "/deferred-sections"; let as_string = common.as_string; let read_json_file = common.read_json_file; @@ -49,6 +51,22 @@ let url_query_params = runtime_url.query_params; const CONFIG_NAME = "tachyon"; +function parse_deferred_sections(deferred_sections) { + let raw = trim(as_string(deferred_sections || getenv("TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS") || "")); + if (raw == "" && fs.stat(TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE) != null) { + raw = trim(as_string(fs.readfile(TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE)) || ""); + } + let res = {}; + if (raw != "") { + for (let s in split(raw, /[ \t\r\n]+/)) { + s = trim(s); + if (s != "") + res[s] = true; + } + } + return res; +} + // UCI stores values written as '' strings as binary, which when // serialized back to JSON appear as '' — invalid for sing-box. function uci_bin_to_hex(val) { @@ -626,6 +644,8 @@ function mixed_proxy_enabled_action(action) { function add_mixed_proxy_for_section(config, section, service_address) { if (!bool_option(section, "mixed_proxy_enabled", false)) return; + if (ctx.deferred_sections && ctx.deferred_sections[section[".name"]]) + return; let action = option(section, "action", ""); if (!mixed_proxy_enabled_action(action)) @@ -744,6 +764,8 @@ function add_global_download_service_mixed_proxy(config, settings, purpose) { function add_subscription_download_service_mixed_proxies(config, sections) { for (let target in connections.subscription_download_targets(sections)) { + if (ctx.deferred_sections && ctx.deferred_sections[target]) + continue; let port = connections.subscription_download_target_port(sections, target, runtime_constants.SERVICE_MIXED_INBOUND_PORT); if (port <= 0) runtime_generate_unsupported("subscription download proxy port could not be resolved"); @@ -924,8 +946,13 @@ function schedule_blocked_domains(schedule) { function enabled_content_block_schedules() { let result = []; ctx.uci_cursor().foreach(CONFIG_NAME, "schedule", function(schedule) { - if (section_enabled(schedule) && length(schedule_blocked_domains(schedule)) > 0) + let quota_minutes = int(option(schedule, "daily_quota_minutes", 0)); + let has_interval = trim(option(schedule, "start_time", "")) != "" || trim(option(schedule, "end_time", "")) != ""; + if (section_enabled(schedule) && length(schedule_blocked_domains(schedule)) > 0) { + if (!has_interval && quota_minutes > 0) + return; push(result, schedule); + } }); return result; } @@ -1234,7 +1261,8 @@ function add_excluded_clients_route_rule(config, settings) { }); } -function generate_config(output_path, service_address, mwan3_active, supports_xhttp) { +function generate_config(output_path, service_address, mwan3_active, supports_xhttp, deferred_sections) { + ctx.deferred_sections = parse_deferred_sections(deferred_sections); ctx.runtime_ruleset_folder = runtime_ruleset_folder; runtime_supports_xhttp = supports_xhttp == null || as_string(supports_xhttp) == "" ? true @@ -1311,11 +1339,11 @@ function generate_config(output_path, service_address, mwan3_active, supports_xh } } -function generate_config_fixture(fixture_path, output_path, service_address, mwan3_active, supports_xhttp) { +function generate_config_fixture(fixture_path, output_path, service_address, mwan3_active, supports_xhttp, deferred_sections) { use_fixture_cursor(fixture_path); runtime_subscription.set_section_cache_dir(output_path + ".section-cache"); runtime_ruleset_folder = output_path + ".rulesets"; - generate_config(output_path, service_address, mwan3_active, supports_xhttp); + generate_config(output_path, service_address, mwan3_active, supports_xhttp, deferred_sections); } function stdin_length() { @@ -1452,9 +1480,9 @@ ensure_custom_ruleset = generator_routes.ensure_custom_ruleset; let mode = ARGV[0] || ""; if (mode == "generate-config") - generate_config(ARGV[1], ARGV[2], ARGV[3], ARGV[4]); + generate_config(ARGV[1], ARGV[2], ARGV[3], ARGV[4], ARGV[5]); else if (mode == "generate-config-fixture") - generate_config_fixture(ARGV[1], ARGV[2], ARGV[3], ARGV[4], ARGV[5]); + generate_config_fixture(ARGV[1], ARGV[2], ARGV[3], ARGV[4], ARGV[5], ARGV[6]); else if (mode == "stdin-length") stdin_length(); else if (mode == "stdin-contains") diff --git a/tachyon/files/usr/lib/singbox/generator_outbounds.uc b/tachyon/files/usr/lib/singbox/generator_outbounds.uc index 1e8123b6..4f485c1f 100644 --- a/tachyon/files/usr/lib/singbox/generator_outbounds.uc +++ b/tachyon/files/usr/lib/singbox/generator_outbounds.uc @@ -1388,8 +1388,11 @@ function add_connections_outbound(config, section, taken) { add_connection_interfaces(config, state, section, taken, selector_tags, urltest_candidate_tags); add_connection_json_outbounds(config, state, section, taken, selector_tags, urltest_candidate_tags); - if (length(selector_tags) == 0) + if (length(selector_tags) == 0) { + if (ctx.deferred_sections && ctx.deferred_sections[section_name]) + return; ctx.runtime_generate_unsupported("connection section has no usable outbounds"); + } if (ctx.routes.section_needs_country_is(section)) { let previous_state = read_json_file(runtime_subscription.section_cache_path(section_name)); diff --git a/tachyon/files/usr/lib/singbox/generator_routes.uc b/tachyon/files/usr/lib/singbox/generator_routes.uc index 32f2aa6d..563a130e 100644 --- a/tachyon/files/usr/lib/singbox/generator_routes.uc +++ b/tachyon/files/usr/lib/singbox/generator_routes.uc @@ -1681,8 +1681,10 @@ function unsupported_matcher_key(section) { } function add_outbound_for_section(config, section, taken, sections) { - let action = option(section, "action", ""); let section_name = section[".name"]; + if (ctx.deferred_sections && ctx.deferred_sections[section_name]) + return; + let action = option(section, "action", ""); if (!valid_section_name(section_name)) ctx.runtime_generate_unsupported("section name is not safe for sing-box config generation"); let unsupported_matcher = unsupported_matcher_key(section); @@ -1758,6 +1760,8 @@ function reserve_section_outbound_tags(sections, taken) { } function add_route_for_section(config, section) { + if (ctx.deferred_sections && ctx.deferred_sections[section[".name"]]) + return; let action = option(section, "action", ""); if (action == "dns") add_dns_action_rules_for_section(config, section); @@ -1771,6 +1775,8 @@ function add_route_for_section(config, section) { function failover_candidate(sections) { let result = []; for (let section in sections) { + if (ctx.deferred_sections && ctx.deferred_sections[section[".name"]]) + continue; let action = option(section, "action", ""); if (connections.is_connections_action(action) || action == "awg" || action == "warp" || action == "byedpi" || action == "zapret" || action == "zapret2" || diff --git a/tachyon/files/usr/lib/singbox/runtime.uc b/tachyon/files/usr/lib/singbox/runtime.uc index 92dd7ab3..1e0b65e8 100644 --- a/tachyon/files/usr/lib/singbox/runtime.uc +++ b/tachyon/files/usr/lib/singbox/runtime.uc @@ -900,7 +900,8 @@ function init_config(populate_nft, caches_prepared, no_refresh) { temp_config, service_listen_address_value(settings), mwan3_active ? "1" : "0", - sing_box_supports_xhttp(sing_box_version()) ? "1" : "0" + sing_box_supports_xhttp(sing_box_version()) ? "1" : "0", + deferred_sections ]) + " >" + shell_quote(runtime_log) + " 2>&1" ); if (generate_status != 0) { diff --git a/tachyon/files/usr/lib/subscription/cache.uc b/tachyon/files/usr/lib/subscription/cache.uc index 4b7e5150..6d1ae257 100644 --- a/tachyon/files/usr/lib/subscription/cache.uc +++ b/tachyon/files/usr/lib/subscription/cache.uc @@ -42,6 +42,7 @@ const TACHYON_PERSISTENT_SUBSCRIPTION_CACHE_FORMAT = getenv("TACHYON_PERSISTENT_ const TACHYON_SUBSCRIPTION_BOOTSTRAP_RETRY_PID_FILE = getenv("TACHYON_SUBSCRIPTION_BOOTSTRAP_RETRY_PID_FILE") || TACHYON_RUNTIME_STATE_DIR + "/subscription-bootstrap-retry.pid"; const TACHYON_SUBSCRIPTION_UPDATE_LOCK_DIR = getenv("TACHYON_SUBSCRIPTION_UPDATE_LOCK_DIR") || TACHYON_RUNTIME_STATE_DIR + "/subscription-update.lock"; const TACHYON_PENDING_RELOAD_FILE = getenv("TACHYON_PENDING_RELOAD_FILE") || TACHYON_RUNTIME_STATE_DIR + "/reload.pending"; +const TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE = getenv("TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE") || TACHYON_RUNTIME_STATE_DIR + "/deferred-sections"; const TACHYON_SERVICE_INIT = getenv("TACHYON_SERVICE_INIT") || "/etc/init.d/tachyon"; const SB_SERVICE_MIXED_INBOUND_ADDRESS = getenv("SB_SERVICE_MIXED_INBOUND_ADDRESS") || "127.0.0.1"; const SB_SERVICE_MIXED_INBOUND_PORT = getenv("SB_SERVICE_MIXED_INBOUND_PORT") || "4534"; @@ -1687,12 +1688,10 @@ function subscription_config_is_current(section_name_value, subscription_url, su function get_subscription_download_proxy_address(section_name_value, sections, parsed, phase) { let download_section = as_string(object_or_empty(parsed).download_section); - if (download_section == "" || download_section == as_string(section_name_value)) + if (download_section == "") return ""; - let port = connections.subscription_download_target_port(sections, download_section, int(SB_SERVICE_MIXED_INBOUND_PORT)); - if (port <= 0) - return ""; + let is_self = (download_section == as_string(section_name_value)); if (!sing_box_service_running()) { if (phase == "startup") @@ -1702,6 +1701,14 @@ function get_subscription_download_proxy_address(section_name_value, sections, p return ""; } + let port = connections.subscription_download_target_port(sections, download_section, int(SB_SERVICE_MIXED_INBOUND_PORT)); + if (port <= 0) { + if (is_self) + port = int(SB_SERVICE_MIXED_INBOUND_PORT); + else + return ""; + } + let address = SB_SERVICE_MIXED_INBOUND_ADDRESS + ":" + as_string(port); // Verify the proxy port is actually accepting connections — the sing-box // process may be running but the mixed inbound not yet ready after a @@ -1744,6 +1751,11 @@ function download_subscription_into_cache(section_name_value, subscription_url, let effective_hwid = get_subscription_hwid(subscription_hwid); let download_status = download_subscription(subscription_url, raw_tmpfile, service_proxy_address_value, headers_tmpfile, effective_user_agent, effective_hwid, subscription_device_headers, allow_insecure); + if (download_status != 0 && service_proxy_address_value == "" && sing_box_service_running()) { + let fallback_proxy = SB_SERVICE_MIXED_INBOUND_ADDRESS + ":" + SB_SERVICE_MIXED_INBOUND_PORT; + log_message("Direct subscription download failed for rule '" + section_name_value + "'; retrying via active service proxy " + fallback_proxy, "info"); + download_status = download_subscription(subscription_url, raw_tmpfile, fallback_proxy, headers_tmpfile, effective_user_agent, effective_hwid, subscription_device_headers, allow_insecure); + } if (download_status != 0) { if (metadata_output_path != "") unlink_path(metadata_output_path); @@ -2340,7 +2352,8 @@ function prepare_subscription_caches(phase, already_prepared, no_refresh) { let sections = uci_sections(); if (prepared_runtime_cache_should_skip(sections, TACHYON_SECTION_CACHE_DIR, phase, already_prepared)) { - print("\n"); + let saved_deferred = trim(as_string(fs.readfile(TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE)) || ""); + print(saved_deferred, "\n"); return 0; } @@ -2363,12 +2376,14 @@ function prepare_subscription_caches(phase, already_prepared, no_refresh) { return 1; if (state.startup_blocked_sections == "") { + unlink_path(TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE); print("\n"); return 0; } - if (phase == "startup" && subscription_bootstrap_download_section_is_ready(sections, state.startup_blocked_sections, get_subscription_user_agent(""))) { + if ((phase == "startup" || phase == "runtime") && subscription_bootstrap_download_section_is_ready(sections, state.startup_blocked_sections, get_subscription_user_agent(""))) { log_message("Starting temporarily without subscription-only rule(s): " + state.startup_blocked_sections + ". They will be retried through the service proxy after sing-box starts", "warn"); + write_file(TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE, state.startup_blocked_sections + "\n"); print(state.startup_blocked_sections, "\n"); return 0; } @@ -2436,6 +2451,11 @@ function subscription_bootstrap_retry_result(deferred_sections) { log_message("Deferred subscription rule '" + section + "' is still unavailable; keeping it disabled for this startup", "warn"); } + if (result.remaining != "") + write_file(TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE, result.remaining + "\n"); + else + unlink_path(TACHYON_SUBSCRIPTION_DEFERRED_SECTIONS_FILE); + return result; } diff --git a/tests/ruleset_download_detour.sh b/tests/ruleset_download_detour.sh index bbf96942..7476c291 100644 --- a/tests/ruleset_download_detour.sh +++ b/tests/ruleset_download_detour.sh @@ -118,7 +118,10 @@ if grep -q '"dial_detour"' "$output_v14"; then fail "sing-box 1.14+ must NEVER contain 'dial_detour' in http_clients (causes fatal unknown field crash)" fi if command -v sing-box >/dev/null 2>&1; then - sing-box check -c "$output_v14" || fail "sing-box 1.14+ config check failed" + INSTALLED_SB_VER="$(sing-box version 2>/dev/null | head -n1 | grep -oE '[0-9]+\.[0-9]+' | head -n1 || echo '0.0')" + if [ "$(printf '%s\n1.14\n' "$INSTALLED_SB_VER" | sort -V | head -n1)" = "1.14" ]; then + sing-box check -c "$output_v14" || fail "sing-box 1.14+ config check failed" + fi fi output_detour_v14="$WORK_DIR/out_detour_v14.json" @@ -133,7 +136,10 @@ fi grep -q '"detour": "first_proxy-out"' "$output_detour_v14" || \ fail "sing-box 1.14+ http_clients must configure 'detour' field when download_lists_via_proxy is enabled" if command -v sing-box >/dev/null 2>&1; then - sing-box check -c "$output_detour_v14" || fail "sing-box 1.14+ detour config check failed" + INSTALLED_SB_VER="$(sing-box version 2>/dev/null | head -n1 | grep -oE '[0-9]+\.[0-9]+' | head -n1 || echo '0.0')" + if [ "$(printf '%s\n1.14\n' "$INSTALLED_SB_VER" | sort -V | head -n1)" = "1.14" ]; then + sing-box check -c "$output_detour_v14" || fail "sing-box 1.14+ detour config check failed" + fi fi # 4. Verify zapret section with community_lists does NOT use zapret-out as download_detour diff --git a/tests/snapshot_contract.sh b/tests/snapshot_contract.sh index 7e771750..c10ac51e 100644 --- a/tests/snapshot_contract.sh +++ b/tests/snapshot_contract.sh @@ -135,7 +135,7 @@ grep -Fq '"success": true' "$WORK_DIR/result.json" || fail "snapshot-restore must report success" for _ in $(seq 1 30); do grep -Fxq 'restart' "$WORK_DIR/bin.log" 2>/dev/null && break - sleep 0.1 + sleep 1 done grep -Fxq 'restart' "$WORK_DIR/bin.log" || fail "snapshot-restore must restart the service through the backend entrypoint" diff --git a/tests/subscription_bootstrap_deadlock.sh b/tests/subscription_bootstrap_deadlock.sh new file mode 100644 index 00000000..5df3d460 --- /dev/null +++ b/tests/subscription_bootstrap_deadlock.sh @@ -0,0 +1,160 @@ +#!/usr/bin/env bash +set -eo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +LIB_DIR="$ROOT_DIR/tachyon/files/usr/lib" +VALIDATOR="$LIB_DIR/config/validator.uc" +GENERATOR="$LIB_DIR/singbox/generator.uc" +WORK_DIR="$(mktemp -d)" + +cleanup() { + rm -rf "$WORK_DIR" +} +trap cleanup EXIT + +fail() { + printf 'FAIL: %s\n' "$1" >&2 + exit 1 +} + +assert_eq() { + local expected="$1" + local actual="$2" + local message="$3" + if [ "$expected" != "$actual" ]; then + printf 'FAIL: %s: expected "%s", got "%s"\n' "$message" "$expected" "$actual" >&2 + exit 1 + fi +} + +# 1. Test validator accepts a section downloading through itself +printf 'Testing validator allows section downloading through itself...\n' +cat >"$WORK_DIR/self_download.json" <<'JSON' +{ + "settings": { + ".name": "settings", + ".type": "settings", + "dns_server": ["77.88.8.8"], + "bootstrap_dns_server": ["77.88.8.8"] + }, + "section": [ + { + ".name": "vpn1", + ".type": "section", + "enabled": "1", + "action": "proxy", + "subscription_urls": [ "https://example.com/sub" ], + "subscription_url_settings": "{\"https://example.com/sub\":{\"download_via_proxy_section\":\"vpn1\"}}" + } + ] +} +JSON + +TACHYON_LIB="$LIB_DIR" ucode -L "$LIB_DIR" "$VALIDATOR" validate-runtime-fixture "$WORK_DIR/self_download.json" "{}" >"$WORK_DIR/val.out" 2>"$WORK_DIR/val.err" + +printf 'Validator successfully accepted self-download configuration.\n' + +# 2. Test connections.uc includes self-target in subscription_download_targets +printf 'Testing connections.uc subscription_download_targets includes self-target...\n' +ucode -L "$LIB_DIR" -e ' +let connections = require("config.connections"); +let sections = [ + { + ".name": "vpn1", + ".type": "section", + "enabled": "1", + "action": "proxy", + "subscription_urls": [ "https://example.com/sub" ], + "subscription_url_settings": "{\"https://example.com/sub\":{\"download_via_proxy_enabled\":\"1\",\"download_via_proxy_section\":\"vpn1\"}}" + } +]; +let targets = connections.subscription_download_targets(sections); +for (let t in targets) + print(t, "\n"); +' > "$WORK_DIR/targets.out" + +assert_eq "vpn1" "$(cat "$WORK_DIR/targets.out")" "subscription_download_targets should include vpn1" + +# 3. Test singbox config generator with deferred section +printf 'Testing singbox config generator skips deferred section...\n' +mkdir -p "$WORK_DIR/runtime" + +cat > "$WORK_DIR/fixture.json" <<'JSON' +{ + "settings": { + ".name": "settings", + ".type": "settings", + "enabled": "1", + "dns_server": "1.1.1.1" + }, + "sections": [ + { + ".name": "vpn1", + ".type": "section", + "enabled": "1", + "action": "proxy", + "selector_proxy_links": [ "socks5://127.0.0.1:1080#node1" ] + }, + { + ".name": "vpn2", + ".type": "section", + "enabled": "1", + "action": "proxy", + "subscription_urls": [ "https://example.com/sub2" ], + "subscription_url_settings": "{\"https://example.com/sub2\":{\"download_via_proxy_enabled\":\"1\",\"download_via_proxy_section\":\"vpn1\"}}" + } + ] +} +JSON + +# A: Generating config WITHOUT deferring vpn2 must fail (vpn2 has 0 outbounds) +set +e +mkdir -p "$WORK_DIR/config_fail.json.section-cache" "$WORK_DIR/config_fail.json.rulesets" +TACHYON_RUNTIME_STATE_DIR="$WORK_DIR/runtime" \ +ucode -L "$LIB_DIR" "$GENERATOR" generate-config-fixture \ + "$WORK_DIR/fixture.json" "$WORK_DIR/config_fail.json" "127.0.0.1" "0" "1" "" >"$WORK_DIR/gen_fail.out" 2>"$WORK_DIR/gen_fail.err" +STATUS_FAIL=$? +set -e +if [ "$STATUS_FAIL" -eq 0 ]; then + fail "generator should have failed when vpn2 has no outbounds and is not deferred" +fi +if ! grep -Fq "connection section has no usable outbounds" "$WORK_DIR/gen_fail.err"; then + printf 'gen_fail.err:\n%s\ngen_fail.out:\n%s\n' "$(cat "$WORK_DIR/gen_fail.err")" "$(cat "$WORK_DIR/gen_fail.out")" >&2 + fail "expected 'connection section has no usable outbounds' in error output" +fi + +# B: Generating config WITH deferred_sections='vpn2' must SUCCEED! +mkdir -p "$WORK_DIR/config_pass.json.section-cache" "$WORK_DIR/config_pass.json.rulesets" +TACHYON_RUNTIME_STATE_DIR="$WORK_DIR/runtime" \ +ucode -L "$LIB_DIR" "$GENERATOR" generate-config-fixture \ + "$WORK_DIR/fixture.json" "$WORK_DIR/config_pass.json" "127.0.0.1" "0" "1" "vpn2" >"$WORK_DIR/gen_pass.out" 2>"$WORK_DIR/gen_pass.err" + +if [ ! -s "$WORK_DIR/config_pass.json" ]; then + fail "generator failed to produce config when vpn2 is deferred" +fi + +# Verify generated config has outbounds for vpn1 and NOT broken references to vpn2 +node - "$WORK_DIR/config_pass.json" <<'NODE' +const fs = require('fs'); +const cfg = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')); +const tags = (cfg.outbounds || []).map(o => o.tag); +console.log("outbound tags:", JSON.stringify(tags)); +if (!tags.includes('vpn1-out')) { + console.error("Generated config must include vpn1-out outbound"); + process.exit(1); +} +if (tags.includes('vpn2-out')) { + console.error("Generated config must NOT include deferred vpn2-out outbound"); + process.exit(1); +} + +const inbounds = (cfg.inbounds || []).map(i => i.tag); +console.log("inbound tags:", JSON.stringify(inbounds)); +if (!inbounds.includes('service-subscription-vpn1-in')) { + console.error("Generated config must include service-subscription-vpn1-in inbound for subscription download"); + process.exit(1); +} +console.log("CONFIG_VERIFIED_OK"); +NODE + +printf 'subscription_bootstrap_deadlock tests passed successfully\n' diff --git a/tests/wan_monitor_hotplug.sh b/tests/wan_monitor_hotplug.sh index 6e07667d..4404a6ba 100644 --- a/tests/wan_monitor_hotplug.sh +++ b/tests/wan_monitor_hotplug.sh @@ -81,10 +81,19 @@ echo "$@" >> "${TEST_LOG_FILE}" EOF chmod +x "$BIN_DIR/logger" +# Mock tachyon init.d script +cat > "$BIN_DIR/initd_tachyon" << 'EOF' +#!/bin/sh +exit 0 +EOF +chmod +x "$BIN_DIR/initd_tachyon" + # Mock tachyon cli (for send_telegram_notification) cat > "$BIN_DIR/tachyon" << 'EOF' #!/bin/sh -echo "$@" >> "${TEST_TELEGRAM_LOG}" +if [ "$1" = "telegram" ]; then + echo "$@" >> "${TEST_TELEGRAM_LOG}" +fi exit 0 EOF chmod +x "$BIN_DIR/tachyon" @@ -95,12 +104,14 @@ export TEST_LOG_FILE="$TMP_DIR/logger.log" export TEST_TELEGRAM_LOG="$TMP_DIR/telegram.log" mkdir -p "$TEST_UCI_DIR" -# Patch monitor script temporarily to use our isolated /var/run/tachyon dir and fast debounce (0.05s instead of 2s) +# Patch monitor script temporarily to use our isolated /var/run/tachyon dir and fast debounce (sleep 0 instead of 2s) TEST_MONITOR="$TMP_DIR/monitor_under_test.sh" # shellcheck disable=SC2016 sed -e "s|/var/run/tachyon|${VAR_RUN}|g" \ - -e 's|sleep "\$DELAY_SEC"|sleep 0.05|g' \ - -e 's|sleep 2|sleep 0.05|g' \ + -e "s|/usr/bin/tachyon|${BIN_DIR}/tachyon|g" \ + -e "s|/etc/init.d/tachyon|${BIN_DIR}/initd_tachyon|g" \ + -e 's|sleep "\$DELAY_SEC"|sleep 0|g' \ + -e 's|sleep 2|sleep 0|g' \ "$MONITOR_SCRIPT" > "$TEST_MONITOR" chmod +x "$TEST_MONITOR" @@ -111,14 +122,12 @@ echo "wan" > "$TEST_UCI_DIR/monitored_ifaces" echo "down" > "$TEST_UCI_DIR/ubus_state_wan" ACTION="ifdown" INTERFACE="wan" sh "$TEST_MONITOR" -sleep 0.2 [ ! -f "$TEST_TELEGRAM_LOG" ] || fail "Test 1 failed: notification sent when enable_badwan=0" # Test 2: Telegram disabled (telegram_enabled = 0) echo "1" > "$TEST_UCI_DIR/enable_badwan" echo "0" > "$TEST_UCI_DIR/telegram_enabled" ACTION="ifdown" INTERFACE="wan" sh "$TEST_MONITOR" -sleep 0.2 [ ! -f "$TEST_TELEGRAM_LOG" ] || fail "Test 2 failed: notification sent when telegram.enabled=0" # Test 3: Unmonitored interface (wan6 triggered, only wan is monitored) @@ -127,7 +136,6 @@ echo "1" > "$TEST_UCI_DIR/telegram_enabled" echo "wan" > "$TEST_UCI_DIR/monitored_ifaces" echo "down" > "$TEST_UCI_DIR/ubus_state_wan6" ACTION="ifdown" INTERFACE="wan6" sh "$TEST_MONITOR" -sleep 0.2 [ ! -f "$TEST_TELEGRAM_LOG" ] || fail "Test 3 failed: notification sent for unmonitored interface wan6" # Test 4: Monitored interface drops (wan ifdown, initial up -> down transition) @@ -139,7 +147,7 @@ echo "down" > "$TEST_UCI_DIR/ubus_state_wan" ACTION="ifdown" INTERFACE="wan" sh "$TEST_MONITOR" # Wait for background verification -sleep 0.3 +sleep 1 [ -f "$TEST_TELEGRAM_LOG" ] || fail "Test 4 failed: no notification sent on UP -> DOWN transition" grep -Fq "Интерфейс *wan* упал!" "$TEST_TELEGRAM_LOG" || fail "Test 4 failed: expected drop message not found in log" @@ -148,7 +156,7 @@ grep -Fq "Интерфейс *wan* упал!" "$TEST_TELEGRAM_LOG" || fail "Test # Test 5: Duplicate hotplug ifdown while state is already down (NO repeated spam) rm -f "$TEST_TELEGRAM_LOG" ACTION="ifdown" INTERFACE="wan" sh "$TEST_MONITOR" -sleep 0.3 +sleep 1 [ ! -f "$TEST_TELEGRAM_LOG" ] || fail "Test 5 failed: duplicate notification sent on repeated ifdown without state change" @@ -157,7 +165,7 @@ rm -f "$TEST_TELEGRAM_LOG" echo "up" > "$TEST_UCI_DIR/ubus_state_wan" ACTION="ifup" INTERFACE="wan" sh "$TEST_MONITOR" -sleep 0.3 +sleep 1 [ -f "$TEST_TELEGRAM_LOG" ] || fail "Test 6 failed: no notification sent on DOWN -> UP recovery" grep -Fq "Интерфейс *wan* поднялся!" "$TEST_TELEGRAM_LOG" || fail "Test 6 failed: expected recovery message not found in log" @@ -166,7 +174,7 @@ grep -Fq "Интерфейс *wan* поднялся!" "$TEST_TELEGRAM_LOG" || fa # Test 7: Duplicate hotplug ifup while state is already up (NO duplicate message) rm -f "$TEST_TELEGRAM_LOG" ACTION="ifup" INTERFACE="wan" sh "$TEST_MONITOR" -sleep 0.3 +sleep 1 [ ! -f "$TEST_TELEGRAM_LOG" ] || fail "Test 7 failed: duplicate notification sent on repeated ifup without state change" diff --git a/tests/wget_flag_hardening.sh b/tests/wget_flag_hardening.sh index baa57eaa..5ad1f032 100644 --- a/tests/wget_flag_hardening.sh +++ b/tests/wget_flag_hardening.sh @@ -11,8 +11,8 @@ fail() { # BusyBox wget in OpenWrt 25.12+ no longer supports -t (retries). Tachyon # handles retries explicitly in a while loop, so the flag is unnecessary and # breaks downloads on recent OpenWrt releases. -if grep -rn --exclude='*.json' --fixed-strings 'wget' "$ROOT_DIR/tachyon/files" | grep -E -- '(^|[^-a-z])(-t[^a-z]|-t")' >/dev/null 2>&1; then - grep -rn --exclude='*.json' --fixed-strings 'wget' "$ROOT_DIR/tachyon/files" | grep -E -- '(^|[^-a-z])(-t[^a-z]|-t")' >&2 +if find "$ROOT_DIR/tachyon/files" -type f ! -name '*.json' -exec grep -Hn -F 'wget' {} + 2>/dev/null | grep -E -- '(^|[^-a-z])(-t[^a-z]|-t")' >/dev/null 2>&1; then + find "$ROOT_DIR/tachyon/files" -type f ! -name '*.json' -exec grep -Hn -F 'wget' {} + | grep -E -- '(^|[^-a-z])(-t[^a-z]|-t")' >&2 fail "wget -t is incompatible with OpenWrt 25.12+ BusyBox; use explicit retry loops instead" fi