These were inside a quoted heredoc (<<'CONFIG') which doesn't expand
variables, resulting in literal ${saved_...} in the config file.
Moved to unquoted heredoc (<<EOF) after the main block.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Strategy 1 is the exact flowseal FAKE TLS AUTO ALT3 equivalent.
Autocircular rotates to alternatives only if strategy 1 fails.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ports 19302-19309 and 3478 are already covered by Discord/STUN profile.
Dedicated Meet profile added unnecessary processing without proven benefit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Autocircular may falsely rotate away from a working strategy due to
UDP failure detection heuristics. Replaced with single fixed strategy
matching flowseal FAKE TLS AUTO ALT3 exactly:
fake, payload=all, repeats=10, autottl=2, cutoff=n2
Autocircular can be restored once game mode is validated working.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Discord profile uses --filter-l7=discord,stun which misses DTLS packets
that Google Meet uses for media. New profile targets Meet STUN ports
(19302-19309, 3478) with payload=all fake — no L7 protocol detection.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Excludes local networks (10.0.0.0/8, 192.168.0.0/16, etc.) from game
filter UDP processing. Matches flowseal ipset-exclude.txt exactly.
Installed automatically during setup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Flowseal's working Roblox strategy uses autottl=2 which sends fake
packets with TTL that expires before the server (DPI sees them, server
doesn't). Without autottl, our fakes reached the server and got dropped.
6 autocircular strategies now covering:
- autottl=2 with repeats 10/12/14 and cutoff n2/n3/n4 (strategies 1-4)
- no autottl with repeats 12/8 (strategies 5-6, for ISPs detecting TTL tricks)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces fixed Roblox-only strategy with autocircular that rotates 4
combinations of repeats (8/10/12/14) and cutoff (n2/n3/n4) on failure.
Uses UDP failure detection: 4+ packets out, ≤1 in = strategy failed.
Renamed [G] Roblox → Игровой режим — covers any game with custom UDP.
Config key remains ROBLOX_UDP_BYPASS for backward compatibility.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Roblox uses a custom UDP protocol that nfqws2 classifies as "unknown".
Without payload=all, the fake desync action silently skips these packets.
This is the equivalent of zapret1's --dpi-desync-any-protocol=1.
Also removed ipset dependency — Roblox IPs change frequently making the
static list unreliable. Port range 1024-65535 + out-range=-n2 is safe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
dry_run_nfqws fails during install because lua/blob files are not
yet in place — this is normal. Changed scary warning to info message.
Also skip dry-run entirely if the function isn't available.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Expand port range from 49152-65535 to 1024-65535 (Roblox uses ports from 1024)
- Remove --filter-l7=unknown (not equivalent to nfqws --dpi-desync-any-protocol=1)
- Remove --payload=all filter that blocked game packets from processing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Expand port range from 49152-65535 to 1024-65535 (Roblox uses ports from 1024)
- Remove --filter-l7=unknown (not equivalent to nfqws --dpi-desync-any-protocol=1)
- Remove --payload=all filter that blocked game packets from processing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DPI bypass doesn't work for Telegram — IPs are deeply blocked,
not just DPI-filtered. Removed the TG_DPI_BYPASS nfqws2 profile.
Transparent proxy performance optimizations:
- TCP_NODELAY on both client and WS connections (disable Nagle)
- 128KB buffered reader coalesces small TCP segments into larger
WS frames (was: each tiny segment = separate WS frame = slow)
- 128KB buffered writer for WS→client direction
- 128KB WebSocket read/write buffers (was: default 4KB)
- Per-message deflate compression on WebSocket
- ReadLimit increased to 2MB for media transfers
- Keepalive interval 50s (was 60s, CF timeout is 100s)
Menu simplified: one mode (transparent proxy), enable/disable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The WS proxy approach (transparent.go) routes ALL Telegram traffic
through Cloudflare WebSocket — every byte goes TCP→WS→TLS→CF→DC.
This causes ~3x latency overhead and barely works.
New approach: use nfqws2 desync on TLS ClientHello to Telegram DC IPs,
same proven technique as YouTube/RKN. Only the handshake is modified,
all data goes directly to Telegram DC at full speed.
Changes:
- Add files/lists/telegram_ips.txt — Telegram DC IP ranges (AS62041)
including IPv6 (2001:b28:f23d::/48, 2001:67c:4e8::/48)
- config_official.sh: new TG_DPI_BYPASS profile with 6 autocircular
strategies (fake+split variants proven against TSPU)
- menu.sh [T]: redesigned with two modes:
[1] DPI bypass (recommended) — fast, direct connection
[2] WS proxy (fallback) — for deep IP blocking
[3] Disable DPI bypass
[4] Disable WS proxy
- install.sh: copy telegram_ips.txt alongside roblox_ips.txt
The WS proxy remains available as fallback for cases where Telegram
DC IPs are completely blocked (not just DPI-filtered).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
КРИТИЧЕСКИЕ ИСПРАВЛЕНИЯ:
- Fix concurrent WebSocket writes (gorilla/websocket thread safety)
via wsWriter mutex serialization
- Fix mipsel64 arch mapping mismatch between z2k.sh and utils.sh
- Sync Z2K_VERSION to 2.0.1 across all files
- Handle aes.NewCipher errors instead of discarding them
- Fix goroutine leaks: context.Context cancellation in all relay paths
- Replace all `eval "$(grep...)"` with safe_config_read() to prevent
command injection via config files
БЕЗОПАСНОСТЬ:
- Add safe_config_read() — shell-injection-safe config parser
- Add download_file_verified() with SHA256 checksum verification
- Add curl timeouts (--connect-timeout 10 --max-time 120) everywhere
- Add connection rate limiting (--max-conns semaphore) in mtproxy
- Add ws.SetReadLimit(1MB) to prevent memory exhaustion
- Use /dev/urandom seeding for Lua PRNG instead of os.time()
GO (mtproxy-client):
- Graceful shutdown via signal.NotifyContext (SIGINT/SIGTERM)
- Connection deadlines and idle timeout (--timeout flag)
- Safe port parsing via net.SplitHostPort
- Type-safe conn.(*net.TCPConn) assertion
- Remove dead code: splitter.go (MsgSplitter never used)
- Remove unused math/rand and math/big imports
- Add unit tests: handshake, relay init, DC lookup, secret parsing
- DNS cache rewritten with sync.Map (no race conditions)
SHELL:
- Fix cd /opt/lib in subshell to prevent working directory corruption
- Add trap cleanup for /tmp/zapret2_build on EXIT
- Add sync comment for duplicated map_arch_to_bin_arch
НОВАЯ ФУНКЦИОНАЛЬНОСТЬ:
- Rollback mechanism: snapshot/restore configuration with auto-timer
- Health check system (z2k-healthcheck.sh): cron-compatible service
availability monitoring with autocircular state reset on failure
- Config validator (z2k-config-validator.sh): validates NFQWS2_OPT
syntax, hostlist paths, blob references before applying
- Auto list updater (z2k-update-lists.sh): cron-based domain list
updates with change detection and automatic service restart
- Custom strategies plugin system (custom_strategies.d/ drop-in)
- Menu entries: [B] Rollback, [H] Health check, [V] Validate config
- CLI commands: rollback, snapshot, healthcheck, validate
CI/CD:
- GitHub Actions workflow: shellcheck, go build/test/vet, luacheck
- Cross-compilation for 6 architectures in CI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Expand port range from 49152-65535 to 1024-65535 (Roblox uses ports from 1024)
- Remove --filter-l7=unknown (not equivalent to nfqws --dpi-desync-any-protocol=1)
- Remove --payload=all filter that blocked game packets from processing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Roblox блокируется по IP на UDP портах 49152-65535 (кастомный протокол).
Новый профиль nfqws2: fake-пакеты (quic_initial blob, repeats=12)
с фильтрацией по ipset Roblox CIDR (AS22697).
- Меню [G] вкл/выкл (opt-in, по умолчанию выключен)
- roblox_ips.txt с CIDR диапазонами (автоперечитывается nfqws2)
- Условное расширение NFQWS2_PORTS_UDP при включении
- ROBLOX_UDP_BYPASS сохраняется при переустановке
Сайт/API Roblox работают через РКН TCP список.
Чат и голосовой чат не поддерживаются.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
create_official_config() перезаписывал конфиг целиком, затирая
пользовательские настройки. Теперь сохраняет значения DROP_DPI_RST
и RKN_SILENT_FALLBACK из старого конфига перед перезаписью.
Меню [F] больше не вызывает create_official_config — достаточно
создать флаг-файл и рестартнуть сервис.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
silent fallback (failure_detection) уже включает --in-range=-s5556
и payload layout, поэтому manual_layout не нужен поверх.
Раньше при RKN_SILENT_FALLBACK=1 оба применялись, удваивая --in-range.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
При удалении failure_detector из всех профилей (e1628dd, false positives
на YouTube) РКН circular потерял единственный способ детектить блокировку.
ТСПУ шлёт TLS alert при блокировке — без детектора circular не видит
failure и не ротирует.
Возвращаем z2k_tls_alert_fatal ТОЛЬКО для rkn_tcp (для YouTube он
не нужен — там работает retrans + silent fallback).
Порядок: failure_detector → manual_layout (--in-range) → silent fallback.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Добавлен пункт меню [F] для включения/выключения детектора
«тихих чёрных дыр» на РКН-профиле. По умолчанию выключен.
Механизм: если circular видит повторные ClientHello без ответа
(2+ за 120 сек) — принудительно ротирует стратегию. Работает
через флаг-файл rkn_silent_fallback.flag, который Lua проверяет
каждые 5 секунд.
Предупреждение в меню: возможны ложные срабатывания на медленных
сайтах из РКН-списка.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MODE_FILTER переключён с autohostlist на hostlist.
Удалён catch-all профиль с --hostlist-auto.
Удалена ссылка на zapret-hosts-auto.txt из RKN-профиля.
Убраны все AUTOHOSTLIST_* переменные из конфига.
Домены теперь контролируются только через явные hostlist-файлы.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keep autohostlist restoration and z2k_cleanup.sh fixes.
TCP circular stays in blind mode (rotation by timeout only).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add z2k_success_no_reset Lua function: detects success but does NOT
reset domain failure counter, so TV/PS5 failures accumulate
independently of PC successes on the same domain
- Add ensure_circular_rst_detection transform for TCP profiles:
--payload=tls_client_hello,empty + --in-range=-s5556 before circular
(sees RST from DPI), fails=5/time=300, restores --in-range=x after
- Restore autohostlist: catch-all profile now has --hostlist-auto with
all tuning params, RKN profile includes autohostlist file
- Fix z2k_cleanup.sh: delete init scripts and netfilter hooks BEFORE
killing processes/iptables (prevents NDM re-triggering), fix grep
substring matching with awk exact match
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove ensure_circular_failure_detector, ensure_circular_payload_empty,
and ensure_circular_in_range transforms for TCP profiles. These caused
aggressive false failure detection that rotated working strategies,
breaking sites that were previously functional.
TCP circular returns to timeout-only rotation (no --in-range, no
failure_detector, no ,empty payload). HTTP RKN profile retains its
own inline failure detection. QUIC failure_detector also removed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous fix added --in-range=-s5556 but --payload=tls_client_hello,empty
was still placed BEFORE circular, restricting it to only those payload types.
Per nfqws2 manual, circular needs --payload=all (default) to see incoming
tls_server_hello (success detection) and RST/FIN (failure detection).
The manual's canonical pattern:
--in-range=-s5556 --lua-desync=circular
--in-range=x --payload=tls_client_hello
--lua-desync=fake:strategy=1
Now ensure_circular_in_range() moves --payload= from before circular to
after it (between --in-range=x and strategies), so circular operates with
the default --payload=all and sees all incoming packet types.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TCP circular profiles had no --in-range= set (default: 'x' = never),
so incoming RST/TLS alerts never reached circular(). The failure
detector never fired, strategies never rotated, and all TCP hosts
stayed on strategy=1 forever.
Confirmed via debug log: only outgoing tls_client_hello packets
reached circular(), zero incoming packets — failure=0 always.
Fix: ensure_circular_in_range() inserts --in-range=-s5556 before
--lua-desync=circular and --in-range=x after the last strategy.
Applied to rkn_tcp, youtube_tcp, youtube_gv_tcp. Skips profiles
that already have --in-range (HTTP RKN, QUIC).
This matches the upstream example from nfqws2 manual (section
"Typical instance invocation scheme within a profile").
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adding tls_server_hello to --payload= caused incoming ServerHello packets
to enter the entire lua-desync pipeline, likely causing unexpected
interactions with circular() rotation logic. Persistence via
outgoing_initial path is sufficient.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Policy layer was overriding persisted working strategies with exploratory
picks on every new connection (15% random + UCB pressure). Now respects
strategies with >50% success rate — only 3% exploration chance when current
strategy is working, and skips override entirely when no telemetry exists
yet (lets new strategies accumulate data first).
Add tls_server_hello to circular payload filter so success_detector fires
on incoming ServerHello — telemetry now records SUCCESS events, feeding
accurate data back into UCB policy decisions.
Increase stop_daemon grace period from 1s to 3s before SIGKILL to ensure
pending state.tsv writes (rate-limited to 2s) flush before process death.
Remove dead code: quic_custom_udp (defined but never added to output),
custom_tcp (defined but never used), ensure_tcp_gap_primitives (only
called on empty discord_tcp_block string).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ip_ttl=0 kills fake packets at the first hop, but if the DPI sits
further downstream the fake never reaches it and bypass fails.
badsum+badseq alone are sufficient: the server drops fakes due to
bad checksum, while DPI still sees them. Keep 2nd fake (zero_256)
for extra DPI confusion but without TTL trick.
Tested: vchera variant without ip_ttl=0 worked on AppleTV YouTube.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UDP has a checksum too — badsum corrupts it so the fake packet
gets dropped by the server. Was in original Zapret1 but omitted.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
--any-protocol is a Zapret1/nfqws1 flag, does not exist in nfqws2
(nfqws2 uses payload=all by default). tls_mod=none is not a valid
tls_mod value — just omit tls_mod to skip blob modification.
Kept badseq as it's used in working strats_new2.txt strategies.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zapret1 original had three parameters we dropped during conversion:
- ip_ttl=0: fake packets must die at first hop (without it they
reach the server and break the connection)
- --any-protocol: process unrecognized protocols too
- TLS 443 had TWO fakes: first zero_256 with tls_mod=none, then
google_hello with tls_mod=sni — we only kept the second one
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drop TCP RST packets injected by TSPU/DPI with IP ID 0x0000-0x000F.
Controlled by DROP_DPI_RST=1 in config, menu toggle at [R].
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove prepend_user_strategy and all strategy=0/1 injections from
autocirculars (broke circular rotation)
- Restore HTTP autocircular to original 7 blockcheck strategies (1-7)
- Replace ALL TCP-443 mode with "Austerus mode" — fixed Zapret1
strategies without hostlists, applied to all traffic:
HTTP: fake(zero_256,badsum,badseq) + multisplit
TLS: fake(google_hello,badsum,badseq,tls_mod) + multidisorder
QUIC: fake(zero_256)
- When enabled, completely replaces z2k autocircular profiles
- Menu [A] simplified: just on/off toggle, no strategy number
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace inline blob=0x00000000 (4 bytes) with blob=zero_256 (256 bytes)
in user-contributed strategy=1 only — matches original Zapret1 config
which used zero_256.bin. Add zero_256 blob loading to S99zapret2.new.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
strategy=0 is invalid in nfqws2 circular — Lua validation requires
strategies starting from 1 with no gaps. The prepend function now
increments all existing strategy numbers before inserting the new
strategy as strategy=1. HTTP inline autocircular also renumbered 1-8.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Convert known-working Zapret1 config to nfqws2 format and add as
strategy=0 (first tried by circular) to all autocircular profiles:
HTTP: fake(zero,badsum,badseq) + multisplit
TLS: fake(zero,badsum,badseq) + fake(google_hello,tls_mod) + multidisorder(method+2,midsld,5)
QUIC: fake(zero) — badsum/badseq omitted (TCP-only)
Applied to: rkn_tcp, youtube_tcp_tcp, youtube_gv_tcp, quic_udp, http_rkn.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>