zapret2-mcp 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,11 +1,29 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
3
+ ## [0.3.5] - 2026-02-19
4
+
5
+ ### Added
6
+ - **Новый промпт `strategy-knowledge`** — полный справочник по стратегиям обхода DPI для LLM: все семейства стратегий (TCP сегментация, фейки, HTTP, window, UDP/QUIC, circular оркестрация), fooling-опции (md5sig, badsum, ip_autottl, tcp_ts), маркеры позиций, типы DPI с рекомендованными подходами, протокол-специфичные заметки (TLS 1.2 vs 1.3, QUIC, HTTP)
7
+
8
+ ### Changed
9
+ - **Промпт `find-bypass-strategy` обогащён knowledge base** — добавлены: как читать результаты blockcheck (AVAILABLE/UNAVAILABLE), критерии выбора стратегии (стабильность > скорость), как конструировать NFQWS2_OPT из результатов, рекомендации по fooling-методам, circular orchestration для отказоустойчивости
10
+ - **Промпт `troubleshoot` обогащён диагностикой** — добавлена секция типичных причин неработающих стратегий: IP-блокировка vs DPI, неправильный fooling для фейков, проблемы с TTL (autottl vs фиксированный), устаревшие стратегии, отсутствие NFQUEUE-модуля
11
+
12
+ ## [0.3.4] - 2026-02-18
4
13
 
5
14
  ### Added
6
15
  - **`removeZapret2` tool** — полный откат установки zapret2: остановка сервиса (init script + systemd), удаление systemd unit, принудительное завершение nfqws2, очистка firewall-правил (nftables/iptables), удаление `/opt/zapret2`. DNS-настройки не откатываются.
7
16
  - **Unit-тест `removeZapret2`** — 5 тестов: успешное удаление, отсутствие установки, содержимое скрипта, таймаут 60 с, обработка ошибки.
8
17
 
18
+ ### Changed
19
+ - **`verifyBypass` — улучшена точность проверки**:
20
+ - Добавлен параметр `interface` — явное указание WAN-интерфейса для curl; если не задан, читается `IFACE_WAN` из `/opt/zapret2/config`
21
+ - Добавлены поля в ответ: `wanInterface` (использованный интерфейс), `routeTo` (маршрут до IP домена)
22
+ - `bypassConfirmed` теперь определяется только по HTTP-коду (`!= 0` и `!= 000`), а не по состоянию zapret2 — корректно отражает реальную доступность сайта
23
+ - curl теперь всегда использует `--noproxy '*'` чтобы исключить влияние системных прокси
24
+ - Убран FIXME-комментарий
25
+ - **Тесты `verifyBypass`** — добавлено 5 новых тестов: `interface` arg, `--noproxy`, `bypassConfirmed=true`, `bypassConfirmed=false`, чтение `IFACE_WAN` из конфига; обновлены ожидаемые поля в существующем тесте
26
+
9
27
  ## [0.3.3] - 2026-02-18
10
28
 
11
29
  ### Fixed
package/build/prompts.js CHANGED
@@ -38,12 +38,41 @@ Follow these steps:
38
38
 
39
39
  1. Run getStatus to check current state. If zapret2 is running, run stopService (blockcheck requires zapret2 to be stopped).
40
40
  2. Run runBlockcheck with the target domain. This is a heavy operation (~5 min). The full log is saved as a resource.
41
- 3. Read the blockcheck log resource to analyze AVAILABLE strategies. Look for lines with "AVAILABLE" status — these are working bypass methods.
42
- 4. Choose the best strategy and run updateConfig with key="NFQWS2_OPT" and the selected nfqws2 parameters as value.
41
+ 3. Read the blockcheck log resource to analyze AVAILABLE strategies.
42
+ 4. Choose the best strategy using the knowledge below, and run updateConfig with key="NFQWS2_OPT" and the selected nfqws2 parameters as value.
43
43
  5. Run restartService to apply the new configuration.
44
44
  6. Run verifyBypass with the target domain to confirm the bypass works.
45
45
 
46
- Report the chosen strategy and verification results to the user.`,
46
+ Report the chosen strategy and verification results to the user.
47
+
48
+ ## How to read blockcheck results
49
+
50
+ Blockcheck tests multiple bypass strategies against the target domain. In the output:
51
+ - **AVAILABLE** — strategy works, the site is reachable with these parameters.
52
+ - **UNAVAILABLE** — strategy failed.
53
+ - Each AVAILABLE line shows the exact nfqws2 parameters that worked.
54
+
55
+ When multiple strategies are AVAILABLE, choose based on these criteria (in priority order):
56
+ 1. **Stability** — prefer strategies without fragile TTL tricks (avoid fixed ip_ttl, prefer ip_autottl or non-TTL fooling).
57
+ 2. **Simplicity** — fewer parameters = more robust. Prefer \`--dpi-desync=split2\` over complex multi-strategy chains.
58
+ 3. **Protocol coverage** — if the domain uses both HTTPS and HTTP, ensure the strategy covers both.
59
+ 4. **TLS version awareness** — TLS 1.3 is easier to bypass (less metadata exposed). TLS 1.2 may need additional work with server response.
60
+
61
+ ## Constructing NFQWS2_OPT from blockcheck results
62
+
63
+ Take the parameters from the AVAILABLE line and use them as NFQWS2_OPT value. For example:
64
+ - Blockcheck shows: \`nfqws2 --dpi-desync=fake,split2 --dpi-desync-split-pos=1 --dpi-desync-fooling=md5sig\`
65
+ - Set NFQWS2_OPT to: \`--dpi-desync=fake,split2 --dpi-desync-split-pos=1 --dpi-desync-fooling=md5sig\`
66
+
67
+ If multiple AVAILABLE strategies exist, prefer those using:
68
+ - \`split2\` or \`disorder2\` (TCP segmentation without fakes — simplest)
69
+ - \`fake,split2\` with \`md5sig\` or \`badsum\` fooling (reliable fake disposal)
70
+ - \`multisplit\` or \`multidisorder\` for complex DPI that reassembles segments
71
+ - Avoid strategies relying solely on \`ip_ttl\` — TTL varies across networks and may break on path changes.
72
+
73
+ For resilience, consider using circular orchestration:
74
+ \`--dpi-desync=fake,split2 --dpi-desync-fooling=md5sig --dpi-desync-circular-strategy=3\`
75
+ This rotates through N strategies automatically if the current one stops working.`,
47
76
  },
48
77
  },
49
78
  ],
@@ -75,7 +104,32 @@ Analyze the results and report:
75
104
  - Is NFQWS2_OPT configured with bypass parameters?
76
105
  - Can the domain be resolved and reached?
77
106
  - Is DNS configured correctly? Consider using configureDns if DNS is unreliable.
78
- - What is the likely root cause and recommended fix?`,
107
+ - What is the likely root cause and recommended fix?
108
+
109
+ ## Common failure causes
110
+
111
+ **IP-level blocking (not DPI):**
112
+ - If the domain's IP is blocked entirely, zapret2 cannot help — it only works against DPI inspection.
113
+ - Symptom: DNS resolves, but connection times out regardless of strategy. Try accessing via VPN to confirm.
114
+
115
+ **Wrong fooling for fakes:**
116
+ - If using fake-based strategies (fake, fakedsplit, fakeddisorder), the fake packet must be discarded by the server but accepted by the DPI.
117
+ - If fakes reach the server, it breaks the connection. Symptoms: connection reset, TLS handshake failure.
118
+ - Fix: switch fooling method. Try md5sig → badsum → ip_autottl. Use ip_autottl instead of fixed ip_ttl.
119
+
120
+ **TTL issues:**
121
+ - Fixed ip_ttl too low → fakes don't reach DPI, bypass fails.
122
+ - Fixed ip_ttl too high → fakes reach the server, connection breaks.
123
+ - Fix: use \`--dpi-desync-fooling=ip_autottl\` which auto-detects the right TTL hop count.
124
+
125
+ **Strategy stopped working:**
126
+ - DPI systems get updated. A strategy that worked yesterday may fail today.
127
+ - Fix: re-run blockcheck (find-bypass-strategy prompt) to discover new working strategies.
128
+ - For resilience, use \`--dpi-desync-circular-strategy=N\` to auto-rotate between strategies.
129
+
130
+ **NFQUEUE module not loaded:**
131
+ - If detectSystem shows nfqueueAvailable=false, nfqws2 cannot intercept packets.
132
+ - Fix: \`modprobe nfnetlink_queue\` or install the kernel module package.`,
79
133
  },
80
134
  },
81
135
  ],
@@ -104,6 +158,94 @@ If any step fails, report the error and suggest remediation before proceeding.`,
104
158
  },
105
159
  ],
106
160
  }));
161
+ server.prompt("strategy-knowledge", "Reference guide: all DPI bypass strategy families, nfqws2 parameters, fooling options, and protocol-specific recommendations", () => ({
162
+ messages: [
163
+ {
164
+ role: "user",
165
+ content: {
166
+ type: "text",
167
+ text: `Provide the full reference guide for zapret2 DPI bypass strategies.
168
+
169
+ ## Strategy Families
170
+
171
+ ### TCP Segmentation (splitting outgoing packets)
172
+ - **split2** / **disorder2** — split TCP segment at a position. disorder2 sends segments out of order. Simplest strategies, no fakes involved.
173
+ - **multisplit** / **multidisorder** — split at multiple positions. For DPI that reassembles single-split segments.
174
+ - **fakedsplit** / **fakeddisorder** — split with a fake segment inserted between real parts. Fake confuses DPI reassembly.
175
+ - **hostfakesplit** — split only at the Host header position in HTTP.
176
+
177
+ Key parameters for segmentation:
178
+ - \`--dpi-desync-split-pos=N\` — byte offset to split at. Special values: \`host\` (start of Host/SNI), \`endhost\` (end of Host/SNI), \`midsld\` (middle of SLD in SNI).
179
+ - \`--dpi-desync-split-seqovl=N\` — TCP sequence number overlap. Confuses DPI that tracks sequences. Requires \`--dpi-desync-split-pos\` > N.
180
+ - \`--dpi-desync-split-http-req=method+host\` — split HTTP request at method and host boundaries.
181
+
182
+ ### Fake Packets (injecting decoy packets that DPI processes but server ignores)
183
+ - **fake** — send a fake packet before the real one. DPI processes the fake and misses the real data.
184
+ - **rst** / **rstack** — send fake RST to make DPI think connection closed.
185
+ - **syndata** — send data in SYN packet (unusual, confuses some DPI).
186
+
187
+ Key parameters for fakes:
188
+ - \`--dpi-desync-fake-tls=<file>\` — custom fake TLS ClientHello payload.
189
+ - \`--dpi-desync-fake-http=<file>\` — custom fake HTTP request payload.
190
+
191
+ ### Fooling Options (making fakes invisible to the server)
192
+ Fakes MUST be discarded by the server but processed by the DPI. Fooling options ensure this:
193
+ - \`--dpi-desync-fooling=md5sig\` — add fake TCP MD5 signature option. Server drops packets with wrong MD5. Most reliable on Linux servers.
194
+ - \`--dpi-desync-fooling=badsum\` — corrupt TCP checksum. Server's NIC drops bad checksum. Does NOT work if server has checksum offload disabled.
195
+ - \`--dpi-desync-fooling=ip_autottl\` — auto-detect TTL so fake expires before reaching server but passes DPI. Best TTL-based option.
196
+ - \`--dpi-desync-fooling=ip_ttl=N\` — fixed TTL for fakes. Fragile — depends on hop count to DPI vs server.
197
+ - \`--dpi-desync-fooling=tcp_ts\` — shift TCP timestamp far in the past. Server drops stale timestamps.
198
+ - Multiple fooling methods can be combined: \`--dpi-desync-fooling=md5sig,badsum\`
199
+
200
+ ### HTTP-Specific Strategies
201
+ - \`--hostcase\` — change Host header case (e.g., "Host:" → "hOsT:"). Simple, effective against basic DPI.
202
+ - \`--domcase\` — randomize domain case in Host header. DPI can't match domain name.
203
+ - \`--methodeol\` — add extra line ending after HTTP method.
204
+
205
+ ### TCP Window Manipulation
206
+ - \`--wsize=N\` — set TCP window size to force small segments from the server.
207
+ - \`--wssize=N\` — set TCP window scale factor.
208
+
209
+ ### UDP/QUIC Strategies
210
+ - \`--dpi-desync-udplen-increment=N\` — pad UDP packets. Changes packet signature.
211
+ - \`--dpi-desync-fake-quic=<file>\` — custom fake QUIC Initial payload.
212
+ - IP fragmentation (\`ipfrag2\`) — fragment IP packets so DPI can't reassemble.
213
+
214
+ ### Orchestration (circular)
215
+ - \`--dpi-desync-circular-strategy=N\` — rotate through N different strategies automatically.
216
+ - When current strategy fails, nfqws2 switches to the next one.
217
+ - Provides resilience against DPI updates without manual intervention.
218
+
219
+ ## DPI Types and Recommended Approaches
220
+
221
+ **Domain-based DPI (inspects SNI/Host):**
222
+ → TCP segmentation at SNI position: \`--dpi-desync=split2 --dpi-desync-split-pos=host\`
223
+ → Or with sequence overlap: \`--dpi-desync=split2 --dpi-desync-split-pos=host --dpi-desync-split-seqovl=1\`
224
+
225
+ **Stateful DPI (tracks TCP state):**
226
+ → Fakes + fooling: \`--dpi-desync=fake,split2 --dpi-desync-fooling=md5sig\`
227
+ → RST injection: \`--dpi-desync=rst --dpi-desync-fooling=ip_autottl\`
228
+
229
+ **Stateless DPI (inspects individual packets):**
230
+ → IP fragmentation: \`--dpi-desync=ipfrag2\`
231
+ → Padding/disorder: \`--dpi-desync=disorder2\`
232
+
233
+ **HTTP-only DPI:**
234
+ → \`--hostcase --dpi-desync=split2 --dpi-desync-split-http-req=method+host\`
235
+
236
+ ## Protocol-Specific Notes
237
+
238
+ **TLS 1.3:** Minimal metadata exposed. Usually \`split2\` at SNI position is enough.
239
+
240
+ **TLS 1.2:** Server certificate is visible. May need strategies for both ClientHello and ServerHello directions. More complex to bypass.
241
+
242
+ **QUIC/UDP:** IP fragmentation (\`ipfrag2\`) or \`udplen\` padding. Fake-based strategies with ipfrag. QUIC is harder to intercept because it's encrypted from the start.
243
+
244
+ **HTTP:** Easiest to bypass. \`--hostcase\` alone often works. Combine with split for robust bypass.`,
245
+ },
246
+ },
247
+ ],
248
+ }));
107
249
  server.prompt("overview", "Quick reference: all available tools, resources, and typical workflows for zapret2-mcp", () => ({
108
250
  messages: [
109
251
  {
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,MAAM,CACX,cAAc,EACd,yIAAyI,EACzI,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;;;;;;;;;+EAW6D;iBACpE;aACF;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,sBAAsB,EACtB,gJAAgJ,EAChJ,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC,EAAE,EACtF,CAAC,IAAI,EAAE,EAAE;QACP,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM;YAC5B,CAAC,CAAC,eAAe,IAAI,CAAC,MAAM,oCAAoC;YAChE,CAAC,CAAC,sEAAsE,CAAC;QAE3E,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAe;oBACrB,OAAO,EAAE;wBACP,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,mDAAmD,UAAU;;;;;;;;;;;iEAWhB;qBACpD;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,cAAc,EACd,sGAAsG,EACtG,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC,EAAE,EAC9F,CAAC,IAAI,EAAE,EAAE;QACP,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM;YAC5B,CAAC,CAAC,+BAA+B,IAAI,CAAC,MAAM,IAAI;YAChD,CAAC,CAAC,sFAAsF,CAAC;QAE3F,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAe;oBACrB,OAAO,EAAE;wBACP,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,mDAAmD,UAAU;;;;;;;;;;;;;;;;qDAgB5B;qBACxC;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,eAAe,EACf,iMAAiM,EACjM,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;;;;;;;;;;+EAY6D;iBACpE;aACF;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,UAAU,EACV,wFAAwF,EACxF,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wGAqCsF;iBAC7F;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"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"}
@@ -5,16 +5,20 @@ export declare const verifyBypassTool: {
5
5
  schema: z.ZodObject<{
6
6
  domain: z.ZodDefault<z.ZodString>;
7
7
  timeout: z.ZodDefault<z.ZodNumber>;
8
+ interface: z.ZodOptional<z.ZodString>;
8
9
  }, "strip", z.ZodTypeAny, {
9
10
  domain: string;
10
11
  timeout: number;
12
+ interface?: string | undefined;
11
13
  }, {
12
14
  domain?: string | undefined;
13
15
  timeout?: number | undefined;
16
+ interface?: string | undefined;
14
17
  }>;
15
18
  handler: (args: {
16
19
  domain?: string;
17
20
  timeout?: number;
21
+ interface?: string;
18
22
  }) => Promise<{
19
23
  content: {
20
24
  type: "text";
@@ -1,16 +1,17 @@
1
1
  import { z } from "zod";
2
2
  import { getExecutor } from "../executorInstance.js";
3
- // FIXME: отшлёпывает 200 на любой запрос. Выяснить, в чём дело
4
3
  export const verifyBypassTool = {
5
4
  name: "verifyBypass",
6
5
  description: "Verify network connectivity: DNS resolution, HTTP request, and nfqws2 running status for a given domain. Use after startService or restartService to confirm zapret2 is working.",
7
6
  schema: z.object({
8
7
  domain: z.string().default("example.com").describe("Domain to verify bypass for (default: example.com)"),
9
8
  timeout: z.number().default(10).describe("HTTP request timeout in seconds (default: 10)"),
9
+ interface: z.string().optional().describe("WAN interface to bind curl to (e.g. wlp0s20f3). If omitted, reads IFACE_WAN from config."),
10
10
  }),
11
11
  handler: async (args) => {
12
12
  const domain = args.domain || "example.com";
13
13
  const timeout = args.timeout || 10;
14
+ const ifaceArg = args.interface || "";
14
15
  const script = `
15
16
  DNS_RESOLVED="false"
16
17
  DNS_IP=""
@@ -23,10 +24,33 @@ export const verifyBypassTool = {
23
24
  DNS_IP="$IP"
24
25
  fi
25
26
 
27
+ # Determine WAN interface: from argument, then from config
28
+ WAN_IFACE="${ifaceArg}"
29
+ if [ -z "$WAN_IFACE" ] && [ -f /opt/zapret2/config ]; then
30
+ WAN_IFACE=$(grep '^IFACE_WAN=' /opt/zapret2/config 2>/dev/null | head -1 | cut -d'=' -f2 | tr -d '"' | tr -d "'")
31
+ fi
32
+
33
+ # Route info for the resolved IP
34
+ ROUTE_TO=""
35
+ if [ -n "$DNS_IP" ] && command -v ip >/dev/null 2>&1; then
36
+ ROUTE_TO=$(ip route get "$DNS_IP" 2>/dev/null | head -1 || true)
37
+ fi
38
+
26
39
  HTTP_CODE="0"
27
- CURL_EXIT="0"
40
+ CURL_EXIT="1"
28
41
  if command -v curl >/dev/null 2>&1; then
29
- HTTP_CODE=$(curl -sL -o /dev/null -w '%{http_code}' --max-time ${timeout} "https://${domain}/" 2>/dev/null || true)
42
+ if [ -n "$WAN_IFACE" ]; then
43
+ HTTP_CODE=$(curl -sL -o /dev/null -w '%{http_code}' \
44
+ --max-time ${timeout} \
45
+ --interface "$WAN_IFACE" \
46
+ --noproxy '*' \
47
+ "https://${domain}/" 2>/dev/null || true)
48
+ else
49
+ HTTP_CODE=$(curl -sL -o /dev/null -w '%{http_code}' \
50
+ --max-time ${timeout} \
51
+ --noproxy '*' \
52
+ "https://${domain}/" 2>/dev/null || true)
53
+ fi
30
54
  CURL_EXIT=$?
31
55
  if [ -z "$HTTP_CODE" ]; then HTTP_CODE="0"; fi
32
56
  fi
@@ -50,15 +74,19 @@ export const verifyBypassTool = {
50
74
  fi
51
75
 
52
76
  BYPASS_CONFIRMED="false"
53
- if [ "$ZAPRET_RUNNING" = "true" ] && [ "$FW_RULES" -gt 0 ] && [ "$HTTP_CODE" != "0" ] && [ "$HTTP_CODE" != "" ]; then
77
+ if [ "$HTTP_CODE" != "0" ] && [ "$HTTP_CODE" != "000" ] && [ -n "$HTTP_CODE" ]; then
54
78
  BYPASS_CONFIRMED="true"
55
79
  fi
56
80
 
81
+ WAN_IFACE_JSON=\${WAN_IFACE:-""}
82
+
57
83
  cat <<EOJSON
58
84
  {
59
85
  "domain": "${domain}",
60
86
  "dnsResolved": $DNS_RESOLVED,
61
87
  "dnsIp": "$DNS_IP",
88
+ "wanInterface": "$WAN_IFACE_JSON",
89
+ "routeTo": "$ROUTE_TO",
62
90
  "httpCode": "$HTTP_CODE",
63
91
  "curlExit": "$CURL_EXIT",
64
92
  "zapretRunning": $ZAPRET_RUNNING,
@@ -1 +1 @@
1
- {"version":3,"file":"verifyBypass.js","sourceRoot":"","sources":["../../src/tools/verifyBypass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,kLAAkL;IAC/L,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,oDAAoD,CAAC;QACxG,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,+CAA+C,CAAC;KAC1F,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,IAA2C,EAAE,EAAE;QAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;QAEnC,MAAM,MAAM,GAAG;;;uBAGI,MAAM;;6BAEA,MAAM;;;;;;;;;;yEAUsC,OAAO,aAAa,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eA8BpF,MAAM;;;;;;;;;;KAUhB,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YAC1E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QACvE,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0D,CAAC;YACrE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,EAAE,CAAC;gBACvG,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"verifyBypass.js","sourceRoot":"","sources":["../../src/tools/verifyBypass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,kLAAkL;IAC/L,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,oDAAoD,CAAC;QACxG,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QACzF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0FAA0F,CAAC;KACtI,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,IAA+D,EAAE,EAAE;QACjF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;QAEtC,MAAM,MAAM,GAAG;;;uBAGI,MAAM;;6BAEA,MAAM;;;;;;;;mBAQhB,QAAQ;;;;;;;;;;;;;;;;yBAgBF,OAAO;;;uBAGT,MAAM;;;yBAGJ,OAAO;;uBAET,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAiCd,MAAM;;;;;;;;;;;;KAYhB,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YAC1E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QACvE,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA0D,CAAC;YACrE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,EAAE,CAAC;gBACvG,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapret2-mcp",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "MCP server for managing zapret2 network packet processing tool on OpenWrt routers and Linux desktops via Docker, SSH, or locally",
5
5
  "license": "MIT",
6
6
  "author": "Stanislav Zemlyakov",