diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..0deb6b6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# Force LF line endings for all shell scripts and text files deployed to Linux/router +*.sh text eol=lf +*.lua text eol=lf +*.txt text eol=lf +*.ini text eol=lf +*.conf text eol=lf +*.md text eol=lf diff --git a/files/000-zapret2.sh b/files/000-zapret2.sh index 90fa175..bc1f948 100644 --- a/files/000-zapret2.sh +++ b/files/000-zapret2.sh @@ -33,7 +33,7 @@ is_nfqws2_running() { fi # Fallback: check common pidfile locations (our init uses nfqws2_*.pid). - for pidfile in /opt/var/run/nfqws2_*.pid /opt/var/run/nfqws2.pid; do + for pidfile in /var/run/nfqws2_*.pid /var/run/nfqws2.pid; do [ -f "$pidfile" ] || continue pid="$(cat "$pidfile" 2>/dev/null)" [ -n "$pid" ] || continue diff --git a/files/S99zapret2.new b/files/S99zapret2.new index 11df2a4..1176f0a 100644 --- a/files/S99zapret2.new +++ b/files/S99zapret2.new @@ -193,16 +193,20 @@ ensure_autocircular_files() { local base="${EXTRA_STRATS_DIR:-$ZAPRET_BASE/extra_strats}/cache/autocircular" mkdir -p "$base" || return 1 - chmod 777 "$base" 2>/dev/null || true + chmod 755 "$base" 2>/dev/null || true + chown nobody "$base" 2>/dev/null || true [ -f "$base/state.tsv" ] || : > "$base/state.tsv" - chmod 666 "$base/state.tsv" 2>/dev/null || true + chmod 644 "$base/state.tsv" 2>/dev/null || true + chown nobody "$base/state.tsv" 2>/dev/null || true [ -f "$base/debug.log" ] || : > "$base/debug.log" - chmod 666 "$base/debug.log" 2>/dev/null || true + chmod 644 "$base/debug.log" 2>/dev/null || true + chown nobody "$base/debug.log" 2>/dev/null || true # Optional debug toggle file; keep if present and readable. - [ -f "$base/debug.flag" ] && chmod 666 "$base/debug.flag" 2>/dev/null || true + [ -f "$base/debug.flag" ] && chmod 644 "$base/debug.flag" 2>/dev/null || true + [ -f "$base/debug.flag" ] && chown nobody "$base/debug.flag" 2>/dev/null || true } # ------------------------------------------------------------------------------ @@ -216,16 +220,20 @@ ensure_traffic_debug_files() { local base="${EXTRA_STRATS_DIR:-$ZAPRET_BASE/extra_strats}/cache/traffic" mkdir -p "$base" || return 1 - chmod 777 "$base" 2>/dev/null || true + chmod 755 "$base" 2>/dev/null || true + chown nobody "$base" 2>/dev/null || true [ -f "$base/nfqws2.debug.log" ] || : > "$base/nfqws2.debug.log" - chmod 666 "$base/nfqws2.debug.log" 2>/dev/null || true + chmod 644 "$base/nfqws2.debug.log" 2>/dev/null || true + chown nobody "$base/nfqws2.debug.log" 2>/dev/null || true [ -f "$base/tcpdump.err.log" ] || : > "$base/tcpdump.err.log" - chmod 666 "$base/tcpdump.err.log" 2>/dev/null || true + chmod 644 "$base/tcpdump.err.log" 2>/dev/null || true + chown nobody "$base/tcpdump.err.log" 2>/dev/null || true # Optional toggle file; keep if present and readable. - [ -f "$base/debug.flag" ] && chmod 666 "$base/debug.flag" 2>/dev/null || true + [ -f "$base/debug.flag" ] && chmod 644 "$base/debug.flag" 2>/dev/null || true + [ -f "$base/debug.flag" ] && chown nobody "$base/debug.flag" 2>/dev/null || true } traffic_debug_prepare() @@ -373,7 +381,7 @@ traffic_debug_tcpdump_start() tcpdump -i any -nn -s 0 -U -w "$pcap" -C 5 -W 10 "$filter" >/dev/null 2>>"$err" & local pid=$! echo "$pid" > "$Z2K_TRAFFIC_DEBUG_PIDFILE" - chmod 666 "$Z2K_TRAFFIC_DEBUG_PIDFILE" 2>/dev/null || true + chmod 644 "$Z2K_TRAFFIC_DEBUG_PIDFILE" 2>/dev/null || true echo "traffic debug: tcpdump filter: $filter" echo "traffic debug: tcpdump started (PID $pid)" } @@ -463,6 +471,9 @@ QUIC1_BLOB="$ZAPRET_BASE/files/fake/quic_1.bin" QUIC_TEST_BLOB="$ZAPRET_BASE/files/fake/quic_test_00.bin" [ -s "$QUIC_TEST_BLOB" ] && NFQWS2_OPT_BASE="$NFQWS2_OPT_BASE --blob=quic_test:@$QUIC_TEST_BLOB" +QUIC_RUTRACKER_BLOB="$ZAPRET_BASE/files/fake/quic_initial_rutracker_org.bin" +[ -s "$QUIC_RUTRACKER_BLOB" ] && NFQWS2_OPT_BASE="$NFQWS2_OPT_BASE --blob=quic_rutracker:@$QUIC_RUTRACKER_BLOB" + TLS_ONETRUST_BLOB="$ZAPRET_BASE/files/fake/tls_clienthello_www_onetrust_com.bin" [ -s "$TLS_ONETRUST_BLOB" ] && NFQWS2_OPT_BASE="$NFQWS2_OPT_BASE --blob=tls_clienthello_www_onetrust_com:@$TLS_ONETRUST_BLOB" diff --git a/files/lua/z2k-autocircular.lua b/files/lua/z2k-autocircular.lua index d0fd507..bfc73e9 100644 --- a/files/lua/z2k-autocircular.lua +++ b/files/lua/z2k-autocircular.lua @@ -212,6 +212,90 @@ local function load_state() f:close() end +local MAX_ENTRIES_PER_KEY = 500 + +local function evict_state_entries(merged) + for askey, hosts in pairs(merged) do + local count = 0 + for _ in pairs(hosts) do count = count + 1 end + if count > MAX_ENTRIES_PER_KEY then + -- Collect entries with timestamps, sort by ts ascending, remove oldest + local entries = {} + for hostn, rec in pairs(hosts) do + table.insert(entries, { hostn = hostn, ts = (rec and rec.ts) or 0 }) + end + table.sort(entries, function(a, b) return a.ts < b.ts end) + local to_remove = count - MAX_ENTRIES_PER_KEY + for i = 1, to_remove do + hosts[entries[i].hostn] = nil + end + end + end +end + +local function evict_telemetry_entries(merged) + for askey, hosts in pairs(merged) do + local count = 0 + for _ in pairs(hosts) do count = count + 1 end + if count > MAX_ENTRIES_PER_KEY then + -- Collect entries with total attempts, sort by att ascending, remove lowest + local entries = {} + for hostn, strats in pairs(hosts) do + local att = 0 + if type(strats) == "table" then + for _, rec in pairs(strats) do + if rec then + att = att + (tonumber(rec.ok) or 0) + (tonumber(rec.fail) or 0) + end + end + end + table.insert(entries, { hostn = hostn, att = att }) + end + table.sort(entries, function(a, b) return a.att < b.att end) + local to_remove = count - MAX_ENTRIES_PER_KEY + for i = 1, to_remove do + hosts[entries[i].hostn] = nil + end + end + end +end + +local function acquire_lock(path) + local lockfile = path .. ".lock" + -- Check for stale lock (older than 10 seconds) + local lf_ts = io.open(lockfile, "r") + if lf_ts then + local content = lf_ts:read("*a") + lf_ts:close() + local lock_time = tonumber(content) + if lock_time and ((os.time() or 0) - lock_time) > 10 then + os.remove(lockfile) + else + return nil, lockfile -- lock is fresh, another process holds it + end + end + -- Try exclusive create: "wx" works in Lua 5.3+/glibc; fallback to "w" with + -- prior existence check (not perfectly atomic but good enough for our use case). + local lf = io.open(lockfile, "wx") + if not lf then + -- "wx" not supported or file appeared between check and open + local recheck = io.open(lockfile, "r") + if recheck then + recheck:close() + return nil, lockfile -- another process created it + end + lf = io.open(lockfile, "w") + end + if not lf then return nil, lockfile end + lf:write(tostring(os.time() or 0)) + lf:close() + return true, lockfile +end + +local function release_lock(lockfile) + if lockfile then os.remove(lockfile) end +end + local function write_state() local now = os.time() or 0 if now ~= 0 and (now - last_write) < write_interval then @@ -223,6 +307,11 @@ local function write_state() local path = choose_state_file_for_write() if not path then return end + + -- Acquire lock to prevent concurrent writes + local locked, lockfile = acquire_lock(path) + if not locked then return end -- another process is writing, skip this cycle + local tmp = path .. ".tmp" -- Read existing file to merge state (prevents split-brain across processes) @@ -253,8 +342,14 @@ local function write_state() end end + -- Evict oldest entries if any key exceeds MAX_ENTRIES_PER_KEY + evict_state_entries(merged_state) + local f = io.open(tmp, "w") - if not f then return end + if not f then + release_lock(lockfile) + return + end f:write("# z2k autocircular state (persisted circular nstrategy)\n") f:write("# key\thost\tstrategy\tts\n") @@ -268,7 +363,12 @@ local function write_state() end f:close() - os.rename(tmp, path) + local ok, err = os.rename(tmp, path) + if not ok then + DLOG("ERROR: rename %s -> %s failed: %s\n", tmp, path, tostring(err)) + os.remove(tmp) + end + release_lock(lockfile) end local function telemetry_host(askey, hostn, create) @@ -340,13 +440,63 @@ local function write_telemetry() local path = choose_telemetry_file_for_write() if not path then return end + + -- Acquire lock to prevent concurrent writes + local locked, lockfile = acquire_lock(path) + if not locked then return end + local tmp = path .. ".tmp" + + -- Read existing file to merge telemetry (prevents split-brain across processes) + local merged = {} + local f_in = io.open(path, "r") + if f_in then + for line in f_in:lines() do + if line ~= "" and not line:match("^%s*#") then + local askey, hostn, strat, okv, failv, latv, tsv, cdv = + line:match("^([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]*)\t?([^\t]*)") + local s = tonumber(strat) + if askey and hostn and s and s >= 1 then + if not merged[askey] then merged[askey] = {} end + if not merged[askey][hostn] then merged[askey][hostn] = {} end + merged[askey][hostn][s] = { + ok = tonumber(okv) or 0, + fail = tonumber(failv) or 0, + lat = tonumber(latv) or 0, + ts = tonumber(tsv) or 0, + cooldown_until = tonumber(cdv) or 0, + } + end + end + end + f_in:close() + end + + -- Apply our in-memory telemetry over the merged data + for askey, hosts in pairs(telemetry) do + if not merged[askey] then merged[askey] = {} end + for hostn, strats in pairs(hosts) do + if not merged[askey][hostn] then merged[askey][hostn] = {} end + for s, rec in pairs(strats) do + if rec then + merged[askey][hostn][s] = rec + end + end + end + end + + -- Evict entries with lowest total attempts if any key exceeds MAX_ENTRIES_PER_KEY + evict_telemetry_entries(merged) + local f = io.open(tmp, "w") - if not f then return end + if not f then + release_lock(lockfile) + return + end f:write("# z2k autocircular telemetry\n") f:write("# key\thost\tstrategy\tok\tfail\tlat\tts\tcooldown_until\n") - for askey, hosts in pairs(telemetry) do + for askey, hosts in pairs(merged) do for hostn, strats in pairs(hosts) do for s, rec in pairs(strats) do if rec then @@ -365,7 +515,12 @@ local function write_telemetry() end end f:close() - os.rename(tmp, path) + local ok, err = os.rename(tmp, path) + if not ok then + DLOG("ERROR: rename %s -> %s failed: %s\n", tmp, path, tostring(err)) + os.remove(tmp) + end + release_lock(lockfile) end local function telemetry_total_attempts(h) @@ -623,7 +778,10 @@ local function policy_seed_strategy(desync, askey, hostn, hrec) end end else - -- No telemetry for current strategy yet: let it accumulate data + -- No telemetry for current strategy yet: let it accumulate data. + -- This is critical for TCP profiles where success telemetry is never + -- recorded (incoming packets don't reach circular). Without this, + -- UCB would override persisted working strategies on every connection. if st then st.policy_seeded = true end return nil, nil end diff --git a/files/z2k-blocked-monitor.sh b/files/z2k-blocked-monitor.sh index 5f609a3..38260ab 100644 --- a/files/z2k-blocked-monitor.sh +++ b/files/z2k-blocked-monitor.sh @@ -73,17 +73,17 @@ choose_capture_iface() { ensure_dirs() { mkdir -p "$CACHE_DIR" || return 1 - chmod 777 "$CACHE_DIR" 2>/dev/null || true + chmod 755 "$CACHE_DIR" 2>/dev/null || true } init_output_files() { - [ -f "$ALL_TSV" ] || echo "# ts\thost\tip\tproto\tport\treason\tdetails" > "$ALL_TSV" - [ -f "$TCP_TSV" ] || echo "# ts\thost\tip\tproto\tport\treason\tdetails" > "$TCP_TSV" - [ -f "$UDP_TSV" ] || echo "# ts\thost\tip\tproto\tport\treason\tdetails" > "$UDP_TSV" - [ -f "$IPMAP_TSV" ] || echo "# ts\tip\thost" > "$IPMAP_TSV" + [ -f "$ALL_TSV" ] || printf '# ts\thost\tip\tproto\tport\treason\tdetails\n' > "$ALL_TSV" + [ -f "$TCP_TSV" ] || printf '# ts\thost\tip\tproto\tport\treason\tdetails\n' > "$TCP_TSV" + [ -f "$UDP_TSV" ] || printf '# ts\thost\tip\tproto\tport\treason\tdetails\n' > "$UDP_TSV" + [ -f "$IPMAP_TSV" ] || printf '# ts\tip\thost\n' > "$IPMAP_TSV" [ -f "$ERR_LOG" ] || : > "$ERR_LOG" [ -f "$PARSER_ERR_LOG" ] || : > "$PARSER_ERR_LOG" - chmod 666 "$ALL_TSV" "$TCP_TSV" "$UDP_TSV" "$IPMAP_TSV" "$ERR_LOG" "$PARSER_ERR_LOG" 2>/dev/null || true + chmod 644 "$ALL_TSV" "$TCP_TSV" "$UDP_TSV" "$IPMAP_TSV" "$ERR_LOG" "$PARSER_ERR_LOG" 2>/dev/null || true } collect_ports() { @@ -484,7 +484,7 @@ start_monitor() { echo "# iface: $iface" >> "$ALL_TSV" echo "# filter: $filter" >> "$ALL_TSV" - "$tcpdump_bin" -i "$iface" -nn -l -tt "$filter" 2>>"$ERR_LOG" | \ + ( "$tcpdump_bin" -i "$iface" -nn -l -tt "$filter" 2>>"$ERR_LOG" | \ awk \ -v all_out="$ALL_TSV" \ -v tcp_out="$TCP_TSV" \ @@ -498,10 +498,10 @@ start_monitor() { -v udp_min_out="4" \ -v udp_max_in="1" \ -v dedupe_sec="60" \ - -f "$AWK_FILE" 2>>"$PARSER_ERR_LOG" & + -f "$AWK_FILE" 2>>"$PARSER_ERR_LOG" ) & echo "$!" > "$PID_FILE" - chmod 666 "$PID_FILE" 2>/dev/null || true + chmod 644 "$PID_FILE" 2>/dev/null || true sleep 1 if ! running_pid >/dev/null; then @@ -524,9 +524,9 @@ stop_monitor() { return 0 fi - kill "$pid" 2>/dev/null || true + kill -- -"$pid" 2>/dev/null || kill "$pid" 2>/dev/null || true sleep 1 - kill -0 "$pid" 2>/dev/null && kill -9 "$pid" 2>/dev/null || true + kill -0 "$pid" 2>/dev/null && { kill -9 -- -"$pid" 2>/dev/null || kill -9 "$pid" 2>/dev/null || true; } rm -f "$PID_FILE" 2>/dev/null || true echo "blocked monitor stopped" } diff --git a/lib/config.sh b/lib/config.sh index 1ab25b3..ab053a4 100644 --- a/lib/config.sh +++ b/lib/config.sh @@ -315,7 +315,7 @@ add_custom_domain() { fi # Проверить, не существует ли уже - if grep -qx "$domain" "$custom_list" 2>/dev/null; then + if grep -qxF "$domain" "$custom_list" 2>/dev/null; then print_warning "Домен уже в списке: $domain" return 0 fi @@ -343,8 +343,8 @@ remove_custom_domain() { fi # Удалить домен - if grep -qx "$domain" "$custom_list"; then - grep -vx "$domain" "$custom_list" > "${custom_list}.tmp" + if grep -qxF "$domain" "$custom_list"; then + grep -vxF "$domain" "$custom_list" > "${custom_list}.tmp" mv "${custom_list}.tmp" "$custom_list" print_success "Удален домен: $domain" else @@ -720,24 +720,23 @@ show_current_config() { print_separator # Списки доменов - if [ -d "$LISTS_DIR" ]; then - print_info "Списки доменов:" - for list in discord.txt youtube.txt rkn.txt custom.txt; do - if [ -f "${LISTS_DIR}/${list}" ]; then - local count - count=$(wc -l < "${LISTS_DIR}/${list}" 2>/dev/null || echo "0") - printf " %-20s: %s доменов\n" "$list" "$count" - fi - done - local yt_quic_list="${ZAPRET2_DIR}/extra_strats/UDP/YT/List.txt" - if [ -f "$yt_quic_list" ]; then - local yt_quic_count - yt_quic_count=$(wc -l < "$yt_quic_list" 2>/dev/null || echo "0") - printf " %-20s: %s доменов\n" "extra_strats/UDP/YT/List.txt" "$yt_quic_count" + print_info "Списки доменов:" + local _list_path _list_label _list_count + for _list_label in "RKN TCP:${ZAPRET2_DIR}/extra_strats/TCP/RKN/List.txt" \ + "YouTube TCP:${ZAPRET2_DIR}/extra_strats/TCP/YT/List.txt" \ + "YouTube GV:--hostlist-domains" \ + "QUIC YouTube:${ZAPRET2_DIR}/extra_strats/UDP/YT/List.txt" \ + "Discord TCP:${ZAPRET2_DIR}/extra_strats/TCP_Discord.txt" \ + "Custom:${LISTS_DIR}/custom.txt"; do + _list_path="${_list_label#*:}" + _list_label="${_list_label%%:*}" + if [ "$_list_path" = "--hostlist-domains" ]; then + printf " %-25s: googlevideo.com\n" "$_list_label" + elif [ -f "$_list_path" ]; then + _list_count=$(wc -l < "$_list_path" 2>/dev/null || echo "0") + printf " %-25s: %s доменов\n" "$_list_label" "$_list_count" fi - else - print_info "Списки доменов: не установлены" - fi + done print_separator } @@ -858,10 +857,25 @@ restore_config() { [Yy]|[Yy][Ee][Ss]) print_info "Восстановление..." - # Извлечь backup - tar -xzf "$latest_backup" -C "$CONFIG_DIR" 2>/dev/null + # Extract to a temp dir first, then move files to their correct locations. + # The tar archive contains files from both $CONFIG_DIR and $LISTS_DIR, + # but with different -C bases, so we cannot extract directly to one dir. + local tmpdir="${CONFIG_DIR}/backups/.restore_tmp" + rm -rf "$tmpdir" + mkdir -p "$tmpdir" + tar -xzf "$latest_backup" -C "$tmpdir" 2>/dev/null if [ $? -eq 0 ]; then + # Move config files to CONFIG_DIR + for f in strategies.conf current_strategy; do + [ -f "${tmpdir}/${f}" ] && mv -f "${tmpdir}/${f}" "${CONFIG_DIR}/${f}" + done + # Move list files to LISTS_DIR + mkdir -p "$LISTS_DIR" + for f in custom.txt; do + [ -f "${tmpdir}/${f}" ] && mv -f "${tmpdir}/${f}" "${LISTS_DIR}/${f}" + done + rm -rf "$tmpdir" print_success "Конфигурация восстановлена" # Предложить перезапуск diff --git a/lib/config_official.sh b/lib/config_official.sh index 6d212b2..b876412 100644 --- a/lib/config_official.sh +++ b/lib/config_official.sh @@ -9,6 +9,9 @@ generate_nfqws2_opt_from_strategies() { # Генерирует NFQWS2_OPT для config файла на основе текущих стратегий + # Intentionally hardcoded: this function may be called before utils.sh sets + # the global CONFIG_DIR / ZAPRET2_DIR / LISTS_DIR variables, so we use + # local copies with known absolute paths. local config_dir="/opt/etc/zapret2" local extra_strats_dir="/opt/zapret2/extra_strats" local lists_dir="/opt/zapret2/lists" @@ -32,15 +35,14 @@ AUSTERUS_OPT fi # Загрузить текущие стратегии из категорий - local youtube_tcp_tcp="" + local youtube_tcp="" local youtube_gv_tcp="" local rkn_tcp="" local quic_udp="" - local discord_tcp="" local discord_udp="" # Прочитать стратегии из файлов категорий if [ -f "${extra_strats_dir}/TCP/YT/Strategy.txt" ]; then - youtube_tcp_tcp=$(cat "${extra_strats_dir}/TCP/YT/Strategy.txt") + youtube_tcp=$(cat "${extra_strats_dir}/TCP/YT/Strategy.txt") fi if [ -f "${extra_strats_dir}/TCP/YT_GV/Strategy.txt" ]; then @@ -69,7 +71,7 @@ AUSTERUS_OPT local default_strategy="--filter-tcp=443,2053,2083,2087,2096,8443 --filter-l7=tls --payload=tls_client_hello,http_req,http_reply,unknown,tls_server_hello --out-range=-s34228 --lua-desync=fake:blob=fake_default_tls:repeats=6" # Использовать дефолт если стратегия пустая - [ -z "$youtube_tcp_tcp" ] && youtube_tcp_tcp="$default_strategy" + [ -z "$youtube_tcp" ] && youtube_tcp="$default_strategy" [ -z "$youtube_gv_tcp" ] && youtube_gv_tcp="$default_strategy" [ -z "$rkn_tcp" ] && rkn_tcp="$default_strategy" @@ -111,7 +113,7 @@ AUSTERUS_OPT printf '%s' "$out" } - youtube_tcp_tcp=$(ensure_circular_nld2 "$youtube_tcp_tcp") + youtube_tcp=$(ensure_circular_nld2 "$youtube_tcp") youtube_gv_tcp=$(ensure_circular_nld2 "$youtube_gv_tcp") rkn_tcp=$(ensure_circular_nld2 "$rkn_tcp") quic_udp=$(ensure_circular_nld2 "$quic_udp") @@ -138,7 +140,7 @@ AUSTERUS_OPT printf '%s' "$out" } - youtube_tcp_tcp=$(ensure_circular_failure_detector "$youtube_tcp_tcp") + youtube_tcp=$(ensure_circular_failure_detector "$youtube_tcp") youtube_gv_tcp=$(ensure_circular_failure_detector "$youtube_gv_tcp") rkn_tcp=$(ensure_circular_failure_detector "$rkn_tcp") quic_udp=$(ensure_circular_failure_detector "$quic_udp") @@ -197,7 +199,7 @@ AUSTERUS_OPT printf '%s' "$out" } - youtube_tcp_tcp=$(ensure_circular_payload_empty "$youtube_tcp_tcp") + youtube_tcp=$(ensure_circular_payload_empty "$youtube_tcp") youtube_gv_tcp=$(ensure_circular_payload_empty "$youtube_gv_tcp") rkn_tcp=$(ensure_circular_payload_empty "$rkn_tcp") @@ -212,6 +214,7 @@ AUSTERUS_OPT nfqws2_opt_lines="$nfqws2_opt_lines$*\\n" else echo "WARN: hostlist file missing or empty: $list_path (skip profile)" 1>&2 + print_warning "Hostlist missing or empty: $list_path — profile skipped" fi } @@ -221,7 +224,7 @@ AUSTERUS_OPT add_hostlist_line "${extra_strats_dir}/TCP/RKN/List.txt" "--hostlist-exclude=${lists_dir}/whitelist.txt $rkn_hostlists $rkn_tcp --new" # YouTube TCP - add_hostlist_line "${extra_strats_dir}/TCP/YT/List.txt" "--hostlist-exclude=${lists_dir}/whitelist.txt --hostlist=${extra_strats_dir}/TCP/YT/List.txt $youtube_tcp_tcp --new" + add_hostlist_line "${extra_strats_dir}/TCP/YT/List.txt" "--hostlist-exclude=${lists_dir}/whitelist.txt --hostlist=${extra_strats_dir}/TCP/YT/List.txt $youtube_tcp --new" # YouTube GV (список доменов статичен) nfqws2_opt_lines="$nfqws2_opt_lines--hostlist-exclude=${lists_dir}/whitelist.txt --hostlist-domains=googlevideo.com $youtube_gv_tcp --new\\n" @@ -248,7 +251,7 @@ AUSTERUS_OPT # Strategy 5: fakedsplit at method+2 with badsum # Strategy 6: z4r original (fake 0x0E + tcp_md5 + multisplit host+1) # Strategy 7: fake badsum + multisplit method+2 - add_hostlist_line "${extra_strats_dir}/TCP/RKN/List.txt" "--filter-tcp=80 --hostlist-exclude=${lists_dir}/whitelist.txt --hostlist=${extra_strats_dir}/TCP/RKN/List.txt --in-range=-s5556 --payload=http_req,empty --lua-desync=circular:fails=2:time=60:reset:key=http_rkn:nld=2 --lua-desync=http_methodeol:payload=http_req:dir=out:strategy=1 --lua-desync=syndata:payload=http_req:dir=out:strategy=2 --lua-desync=multisplit:payload=http_req:dir=out:strategy=2 --lua-desync=hostfakesplit:payload=http_req:dir=out:ip_ttl=2:repeats=1:strategy=3 --lua-desync=fake:payload=http_req:dir=out:blob=fake_default_http:badsum:repeats=1:strategy=4 --lua-desync=fakedsplit:payload=http_req:dir=out:pos=method+2:badsum:strategy=5 --lua-desync=fake:payload=http_req:dir=out:blob=0x0E0E0F0E:tcp_md5:strategy=6 --lua-desync=multisplit:payload=http_req:dir=out:pos=host+1:seqovl=2:strategy=6 --lua-desync=fake:payload=http_req:dir=out:blob=fake_default_http:badsum:repeats=1:strategy=7 --lua-desync=multisplit:payload=http_req:dir=out:pos=method+2:strategy=7 --in-range=x --new" + add_hostlist_line "${extra_strats_dir}/TCP/RKN/List.txt" "--filter-tcp=80 --hostlist-exclude=${lists_dir}/whitelist.txt --hostlist=${extra_strats_dir}/TCP/RKN/List.txt --in-range=-s5556 --payload=http_req,empty --lua-desync=circular:fails=2:time=60:reset:key=http_rkn:nld=2:failure_detector=z2k_tls_alert_fatal --lua-desync=http_methodeol:payload=http_req:dir=out:strategy=1 --lua-desync=syndata:payload=http_req:dir=out:strategy=2 --lua-desync=multisplit:payload=http_req:dir=out:strategy=2 --lua-desync=hostfakesplit:payload=http_req:dir=out:ip_ttl=2:repeats=1:strategy=3 --lua-desync=fake:payload=http_req:dir=out:blob=fake_default_http:badsum:repeats=1:strategy=4 --lua-desync=fakedsplit:payload=http_req:dir=out:pos=method+2:badsum:strategy=5 --lua-desync=fake:payload=http_req:dir=out:blob=0x0E0E0F0E:tcp_md5:strategy=6 --lua-desync=multisplit:payload=http_req:dir=out:pos=host+1:seqovl=2:strategy=6 --lua-desync=fake:payload=http_req:dir=out:blob=fake_default_http:badsum:repeats=1:strategy=7 --lua-desync=multisplit:payload=http_req:dir=out:pos=method+2:strategy=7 --in-range=x --new" # Catch-all TCP profile for autohostlist failure tracking # Upstream zapret appends --hostlist-auto to the very end of NFQWS2_OPT, @@ -412,7 +415,7 @@ NFQWS2_UDP_PKT_IN="3" # ============================================================================== # This section is auto-generated from z2k strategy database # Each --new separator creates independent profile with own filters and strategy -# Order: CF TCP → RKN TCP → YouTube TCP → YouTube GV → QUIC YT → QUIC Cloudflare → QUIC Custom → Discord TCP → Discord UDP → Custom +# Order: RKN TCP → YouTube TCP → YouTube GV → QUIC YT → Discord UDP → HTTP RKN → Catch-all TCP # Profiles use explicit hostlists from z2k list files without placeholder expansion. # This avoids mixing with global hostlists from MODE_FILTER. CONFIG diff --git a/lib/install.sh b/lib/install.sh index 9927c21..665a6a7 100644 --- a/lib/install.sh +++ b/lib/install.sh @@ -113,15 +113,18 @@ step_update_packages() { printf "\n" # 1. Проверка архитектуры системы - local sys_arch=$(uname -m) + local sys_arch + sys_arch=$(uname -m) print_info "Архитектура системы: $sys_arch" # 2. Проверка архитектуры Entware if [ -f "/opt/etc/opkg.conf" ]; then - local entware_arch=$(grep -m1 "^arch" /opt/etc/opkg.conf | awk '{print $2}') + local entware_arch + entware_arch=$(grep -m1 "^arch" /opt/etc/opkg.conf | awk '{print $2}') print_info "Архитектура Entware: ${entware_arch:-не определена}" - local repo_url=$(grep -m1 "^src" /opt/etc/opkg.conf | awk '{print $3}') + local repo_url + repo_url=$(grep -m1 "^src" /opt/etc/opkg.conf | awk '{print $3}') print_info "Репозиторий: $repo_url" # 3. Проверка доступности репозитория @@ -141,7 +144,8 @@ step_update_packages() { print_error "[FAIL] opkg --version падает (Illegal instruction)" print_warning "ПРИЧИНА: opkg установлен для неправильной архитектуры CPU!" elif opkg --version >/dev/null 2>&1; then - local opkg_version=$(opkg --version 2>&1 | head -1) + local opkg_version + opkg_version=$(opkg --version 2>&1 | head -1) print_success "[OK] opkg бинарник запускается: $opkg_version" print_warning "Но 'opkg update' падает - возможно проблема в зависимости или скрипте" else @@ -151,7 +155,8 @@ step_update_packages() { # 5. Проверка файла opkg if command -v file >/dev/null 2>&1; then if [ -f "/opt/bin/opkg" ]; then - local opkg_file_info=$(file /opt/bin/opkg 2>&1 | head -1) + local opkg_file_info + opkg_file_info=$(file /opt/bin/opkg 2>&1 | head -1) print_info "Бинарник opkg: $opkg_file_info" fi fi @@ -445,7 +450,7 @@ unzip # Проверить busybox gzip if command -v gzip >/dev/null 2>&1; then - if readlink "$(which gzip)" 2>/dev/null | grep -q busybox; then + if readlink "$(command -v gzip)" 2>/dev/null | grep -q busybox; then print_info "Обнаружен busybox gzip (медленный, ~3x медленнее GNU)" printf "Установить GNU gzip для ускорения обработки списков? [y/N]: " read -r answer /dev/null 2>&1; then - if readlink "$(which sort)" 2>/dev/null | grep -q busybox; then + if readlink "$(command -v sort)" 2>/dev/null | grep -q busybox; then print_info "Обнаружен busybox sort (медленный, использует много RAM)" printf "Установить GNU sort для ускорения? [y/N]: " read -r answer &1 | head -5 || true else - local version=$(./nfq2/nfqws2 --version 2>&1 | head -1) + local version + version=$(./nfq2/nfqws2 --version 2>&1 | head -1) print_success "nfqws2 работает: $version" fi @@ -689,7 +695,7 @@ step_build_zapret2() { print_info "Установка в $ZAPRET2_DIR..." cd "$build_dir" || return 1 - mv "$release_dir" "$ZAPRET2_DIR" || return 1 + cp -a "$release_dir" "$ZAPRET2_DIR" && rm -rf "$release_dir" || return 1 # ВАЖНО: Обновить ZAPRET_BASE на финальный путь (был /tmp/zapret2_build/...) export ZAPRET_BASE="$ZAPRET2_DIR" @@ -735,6 +741,8 @@ step_build_zapret2() { print_info "Copying snapshot domain lists..." mkdir -p "${ZAPRET2_DIR}/files/lists" cp -Rf "${WORK_DIR}/files/lists/"* "${ZAPRET2_DIR}/files/lists/" 2>/dev/null || true + # Strip CRLF from list files + find "${ZAPRET2_DIR}" -name "*.txt" -path "*/extra_strats/*" -exec sed -i 's/\r$//' {} + 2>/dev/null || true fi # Decompress lua.gz files (if any are shipped by embedded builds) if [ -d "${ZAPRET2_DIR}/lua" ]; then @@ -764,13 +772,16 @@ step_build_zapret2() { mkdir -p "${ZAPRET2_DIR}/lua" mkdir -p "${ZAPRET2_DIR}/extra_strats/cache/orchestra" mkdir -p "${ZAPRET2_DIR}/extra_strats/cache/autocircular" - chmod 777 "${ZAPRET2_DIR}/extra_strats/cache/autocircular" 2>/dev/null || true + chmod 755 "${ZAPRET2_DIR}/extra_strats/cache/autocircular" 2>/dev/null || true + chown nobody "${ZAPRET2_DIR}/extra_strats/cache/autocircular" 2>/dev/null || true : > "${ZAPRET2_DIR}/extra_strats/cache/autocircular/state.tsv" 2>/dev/null || true - chmod 666 "${ZAPRET2_DIR}/extra_strats/cache/autocircular/state.tsv" 2>/dev/null || true + chmod 644 "${ZAPRET2_DIR}/extra_strats/cache/autocircular/state.tsv" 2>/dev/null || true + chown nobody "${ZAPRET2_DIR}/extra_strats/cache/autocircular/state.tsv" 2>/dev/null || true # Debug is opt-in. Keep log file prepared, but do not enable verbose logging by default. rm -f "${ZAPRET2_DIR}/extra_strats/cache/autocircular/debug.flag" 2>/dev/null || true : > "${ZAPRET2_DIR}/extra_strats/cache/autocircular/debug.log" 2>/dev/null || true - chmod 666 "${ZAPRET2_DIR}/extra_strats/cache/autocircular/debug.log" 2>/dev/null || true + chmod 644 "${ZAPRET2_DIR}/extra_strats/cache/autocircular/debug.log" 2>/dev/null || true + chown nobody "${ZAPRET2_DIR}/extra_strats/cache/autocircular/debug.log" 2>/dev/null || true if curl -fsSL "https://raw.githubusercontent.com/AloofLibra/zapret4rocket/z2r/orchestra/locked.lua" \ -o "${ZAPRET2_DIR}/lua/locked.lua"; then @@ -834,7 +845,7 @@ step_build_zapret2() { } # ============================================================================== -# ШАГ 5: ПРОВЕРКА УСТАНОВКИ +# ШАГ 6: ПРОВЕРКА УСТАНОВКИ # ============================================================================== step_verify_installation() { @@ -1044,7 +1055,7 @@ step_download_domain_lists() { } # ============================================================================== -# ШАГ 7: ОТКЛЮЧЕНИЕ HARDWARE NAT +# ШАГ 9: ОТКЛЮЧЕНИЕ HARDWARE NAT # ============================================================================== step_disable_hwnat_and_offload() { @@ -1133,7 +1144,13 @@ step_configure_tmpdir() { # Получить объём RAM local ram_mb if [ -f "${ZAPRET2_DIR}/common/base.sh" ]; then + # Save overrides before re-sourcing + _saved_linux_ipt_avail="$(type linux_ipt_avail 2>/dev/null)" . "${ZAPRET2_DIR}/common/base.sh" + # Restore override if it was set + if [ -n "$_saved_linux_ipt_avail" ]; then + linux_ipt_avail() { true; } + fi ram_mb=$(get_ram_mb) else # Fallback: определить RAM вручную @@ -1265,7 +1282,7 @@ step_create_config_and_init() { } # ============================================================================== -# ШАГ 9: УСТАНОВКА NETFILTER ХУКА +# ШАГ 11: УСТАНОВКА NETFILTER ХУКА # ============================================================================== step_install_netfilter_hook() { @@ -1357,7 +1374,7 @@ HOOK } # ============================================================================== -# ШАГ 10: ФИНАЛИЗАЦИЯ +# ШАГ 12: ФИНАЛИЗАЦИЯ # ============================================================================== step_finalize() { @@ -1496,7 +1513,7 @@ step_finalize() { printf " %-25s: %s\n" "Конфигурация" "$CONFIG_DIR" printf " %-25s: %s\n" "Списки доменов" "$LISTS_DIR" printf " %-25s: %s\n" "Стратегии" "$STRATEGIES_CONF" - printf " %-25s: %s\n" "Tools" "$tools_dir" + printf " %-25s: %s\n" "Tools" "${ZAPRET2_DIR}/ip2net, ${ZAPRET2_DIR}/mdig" # Save local z2k entrypoint for future runs without curl. local local_z2k_script="${ZAPRET2_DIR}/z2k.sh" diff --git a/lib/menu.sh b/lib/menu.sh index 16c3eaf..2852224 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -428,74 +428,6 @@ SUBMENU pause } -# ============================================================================== -# ПОДМЕНЮ: ПРОСМОТР СТРАТЕГИИ -# ============================================================================== - -menu_view_strategy() { - clear_screen - print_header "[5] Текущие стратегии" - - if ! is_zapret2_installed; then - print_error "zapret2 не установлен" - pause - return - fi - - # Проверить наличие файла с категориями - if [ -f "$CATEGORY_STRATEGIES_CONF" ]; then - print_info "Стратегии по категориям:" - print_separator - - # Прочитать и показать стратегии для каждой категории - while IFS=':' read -r category strategy score; do - [ -z "$category" ] && continue - - local params - local type - params=$(get_strategy "$strategy" 2>/dev/null) - type=$(get_strategy_type "$strategy" 2>/dev/null) - - printf "\n[%s]\n" "$(echo "$category" | tr '[:lower:]' '[:upper:]')" - printf " Стратегия: #%s (оценка: %s/5)\n" "$strategy" "$score" - printf " Тип: %s\n" "$type" - done < "$CATEGORY_STRATEGIES_CONF" - - print_separator - else - # Старый режим - одна стратегия - local current - current=$(get_current_strategy) - - if [ "$current" = "не задана" ] || [ -z "$current" ]; then - print_warning "Стратегия не выбрана" - print_info "Используется стратегия по умолчанию из init скрипта" - else - print_info "Текущая стратегия: #$current" - print_separator - - local params - params=$(get_strategy "$current") - local type - type=$(get_strategy_type "$current") - - printf "Тип: %s\n\n" "$type" - printf "Параметры:\n%s\n" "$params" - print_separator - fi - fi - - # Показать статус сервиса - printf "\nСтатус сервиса: %s\n" "$(get_service_status)" - - if is_zapret2_running; then - printf "\nПроцессы nfqws2:\n" - pgrep -af "nfqws2" 2>/dev/null || print_info "Процессы не найдены" - fi - - pause -} - # ============================================================================== # ПОДМЕНЮ: ОБНОВЛЕНИЕ СПИСКОВ # ============================================================================== @@ -561,6 +493,8 @@ SUBMENU restore_config ;; 3) + print_warning "Это сбросит всю конфигурацию к значениям по умолчанию!" + confirm "Вы уверены?" "N" || { pause; return; } reset_config ;; [Bb]) @@ -1065,6 +999,7 @@ EOF print_success "Файл whitelist создан: $whitelist_file" fi + while true; do print_separator cat <<'INFO' @@ -1125,14 +1060,14 @@ INFO if ! echo "$new_domain" | grep -qE '^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'; then print_error "Неверный формат домена: $new_domain" pause - return 1 + continue fi # Проверить дубликаты - if grep -qx "$new_domain" "$whitelist_file"; then + if grep -qxF "$new_domain" "$whitelist_file"; then print_warning "Домен $new_domain уже в whitelist" pause - return 0 + continue fi # Добавить домен @@ -1155,14 +1090,14 @@ INFO read_input del_domain # Проверить наличие - if ! grep -qx "$del_domain" "$whitelist_file"; then + if ! grep -qxF "$del_domain" "$whitelist_file"; then print_error "Домен $del_domain не найден в whitelist" pause - return 1 + continue fi # Удалить домен - sed -i "/^${del_domain}$/d" "$whitelist_file" + grep -vxF "$del_domain" "$whitelist_file" > "${whitelist_file}.tmp" && mv "${whitelist_file}.tmp" "$whitelist_file" print_success "Домен $del_domain удален из whitelist" print_separator @@ -1184,6 +1119,7 @@ INFO pause ;; esac + done } # ============================================================================== diff --git a/lib/strategies.sh b/lib/strategies.sh index 4df5372..ed46f81 100644 --- a/lib/strategies.sh +++ b/lib/strategies.sh @@ -3,19 +3,6 @@ # Парсинг, тестирование, применение стратегий из strats_new2.txt # QUIC/UDP стратегии берутся из quic_strats.ini -# ============================================================================== -# КОНСТАНТЫ ДЛЯ СТРАТЕГИЙ -# ============================================================================== - -# Домены для тестирования стратегий -TEST_DOMAINS=" -http://rutracker.org -https://rutracker.org -https://www.youtube.com -https://discord.com -https://googlevideo.com -" - # ============================================================================== # РАБОТА С ФАЙЛАМИ СТРАТЕГИЙ ПО КАТЕГОРИЯМ (CONFIG-DRIVEN АРХИТЕКТУРА) # ============================================================================== @@ -446,11 +433,7 @@ apply_strategy() { # Построить полные TCP параметры local tcp_params - if [ "$type" = "http" ]; then - tcp_params=$(build_http_profile_params "$params") - else - tcp_params=$(build_tls_profile_params "$params") - fi + tcp_params=$(build_tls_profile_params "$params") # Получить текущие QUIC параметры local udp_params @@ -723,6 +706,7 @@ EOF local args="" while IFS= read -r line; do + line=$(printf '%s' "$line" | sed 's/\r$//') line=$(echo "$line" | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//') [ -z "$line" ] && continue case "$line" in @@ -1232,148 +1216,6 @@ test_strategy_range() { fi } -# ============================================================================== -# ПРИМЕНЕНИЕ СТРАТЕГИЙ ПО КАТЕГОРИЯМ -# ============================================================================== - -# Применить разные стратегии для разных категорий -# Параметр: строка вида "youtube:4:5 discord:7:4 custom:11:3" -apply_category_strategies() { - local category_strategies=$1 - local init_script="${INIT_SCRIPT:-/opt/etc/init.d/S99zapret2}" - - if [ -z "$category_strategies" ]; then - print_error "Не указаны стратегии для категорий" - return 1 - fi - - if [ ! -f "$init_script" ]; then - print_error "Init скрипт не найден: $init_script" - return 1 - fi - - print_info "Применение стратегий по категориям..." - - # Обработать каждую категорию - for entry in $category_strategies; do - local category=$(echo "$entry" | cut -d: -f1) - local strategy_num=$(echo "$entry" | cut -d: -f2) - local score=$(echo "$entry" | cut -d: -f3) - - print_info " $category -> стратегия #$strategy_num (оценка: $score/5)" - - # Получить параметры стратегии - local params - params=$(get_strategy "$strategy_num") - - if [ -z "$params" ]; then - print_warning "Стратегия #$strategy_num не найдена, пропускаем $category" - continue - fi - - # Конвертировать в TCP/UDP профили - local tcp_params - local udp_params - - # Определить тип стратегии - local type - type=$(get_strategy_type "$strategy_num") - - if [ "$type" = "https" ]; then - tcp_params="--filter-tcp=443 --filter-l7=tls --payload=tls_client_hello ${params}" - udp_params="" - else - tcp_params="--filter-tcp=80,443 --filter-l7=http ${params}" - udp_params="" - fi - - # Обновить маркеры в init скрипте - case "$category" in - youtube) - update_init_section "YOUTUBE" "$tcp_params" "$udp_params" "$init_script" - ;; - discord) - update_init_section "DISCORD" "$tcp_params" "$udp_params" "$init_script" - ;; - custom) - update_init_section "CUSTOM" "$tcp_params" "$udp_params" "$init_script" - ;; - esac - done - - print_success "Стратегии применены к init скрипту" - - # Перезапустить сервис - print_info "Перезапуск сервиса..." - "$init_script" restart >/dev/null 2>&1 - - sleep 2 - - if is_zapret2_running; then - print_success "Сервис перезапущен с новыми стратегиями" - return 0 - else - print_warning "Сервис не запустился, проверьте логи" - return 1 - fi -} - -# Обновить секцию в init скрипте для конкретной категории -update_init_section() { - local marker=$1 - local tcp_params=$2 - local udp_params=$3 - local init_script=$4 - - local start_marker="${marker}_MARKER_START" - local end_marker="${marker}_MARKER_END" - - # Создать временный файл - local temp_file="${init_script}.tmp" - - # Флаг - внутри ли мы секции для замены - local inside_section=0 - local found_section=0 - - while IFS= read -r line; do - if echo "$line" | grep -q "# ${start_marker}"; then - # Начало секции - записать маркер и новые параметры - echo "$line" - echo "${marker}_TCP=\"${tcp_params}\"" - echo "${marker}_UDP=\"${udp_params}\"" - inside_section=1 - found_section=1 - elif echo "$line" | grep -q "# ${end_marker}"; then - # Конец секции - записать маркер и выйти из режима - echo "$line" - inside_section=0 - elif [ "$inside_section" -eq 0 ]; then - # Вне секции - просто копировать - echo "$line" - fi - # Внутри секции - пропускать старые строки (кроме маркеров) - done < "$init_script" > "$temp_file" - - # Если секции не было в файле - добавить в конец - if [ "$found_section" -eq 0 ]; then - { - echo "" - echo "# ${start_marker}" - echo "${marker}_TCP=\"${tcp_params}\"" - echo "${marker}_UDP=\"${udp_params}\"" - echo "# ${end_marker}" - } >> "$temp_file" - fi - - # Заменить init скрипт - mv "$temp_file" "$init_script" || { - print_error "Не удалось обновить init скрипт" - return 1 - } - - chmod +x "$init_script" -} - # ============================================================================== # АВТОТЕСТ QUIC СТРАТЕГИЙ # ============================================================================== @@ -2188,33 +2030,6 @@ run_blockcheck_http() { return 0 } -get_init_tcp_params() { - local marker=$1 - local init_script=$2 - - if [ ! -f "$init_script" ]; then - return 1 - fi - - local line - line=$(grep "^${marker}_TCP=" "$init_script" 2>/dev/null | head -n 1) - echo "$line" | sed "s/^${marker}_TCP=\"//" | sed 's/\"$//' -} - -# Получить текущие UDP параметры из init скрипта для секции -get_init_udp_params() { - local marker=$1 - local init_script=$2 - - if [ ! -f "$init_script" ]; then - return 1 - fi - - local line - line=$(grep "^${marker}_UDP=" "$init_script" 2>/dev/null | head -n 1) - echo "$line" | sed "s/^${marker}_UDP=\"//" | sed 's/\"$//' -} - # Применить разные стратегии для YouTube TCP, YouTube GV, RKN (Z4R метод) # Параметры: номера стратегий для каждой категории apply_category_strategies_v2() { diff --git a/lib/system_init.sh b/lib/system_init.sh index 6c283f1..3407806 100644 --- a/lib/system_init.sh +++ b/lib/system_init.sh @@ -70,59 +70,3 @@ init_system_vars() { return 0 } - -# ============================================================================== -# ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ -# ============================================================================== - -# Определить является ли система Keenetic -is_keenetic() { - # Проверка наличия Keenetic-специфичных файлов - [ -f /opt/etc/init.d/rc.func ] && return 0 - - # Проверка на NDM (Keenetic firmware) - [ -d /opt/etc/ndm ] && return 0 - - return 1 -} - -# Получить версию Keenetic firmware (если доступно) -get_keenetic_version() { - if [ -f /etc/os-release ]; then - grep VERSION_ID /etc/os-release | cut -d'=' -f2 | tr -d '"' - elif command -v ndmc >/dev/null 2>&1; then - ndmc -c "show version" 2>/dev/null | grep "release:" | awk '{print $2}' - else - echo "unknown" - fi -} - -# ============================================================================== -# KEENETIC СПЕЦИФИЧНЫЕ ПРОВЕРКИ -# ============================================================================== - -check_keenetic_specifics() { - if is_keenetic; then - print_info "Обнаружен роутер Keenetic" - - local fw_version - fw_version=$(get_keenetic_version) - [ "$fw_version" != "unknown" ] && print_info "Firmware версия: $fw_version" - - # Проверить наличие NDM hooks - if [ -d /opt/etc/ndm ]; then - print_info "NDM hooks доступны" - fi - - # Проверить fastnat - if [ -f /sys/kernel/fastnat/mode ]; then - local fastnat_mode - fastnat_mode=$(cat /sys/kernel/fastnat/mode 2>/dev/null || echo "unknown") - print_info "Fastnat mode: $fastnat_mode" - fi - - return 0 - fi - - return 1 -} diff --git a/lib/utils.sh b/lib/utils.sh index c0f5bf5..b12f30d 100644 --- a/lib/utils.sh +++ b/lib/utils.sh @@ -40,7 +40,6 @@ Z2R_BASE_URL="https://raw.githubusercontent.com/AloofLibra/zapret4rocket/z2r" # Файлы конфигурации STRATEGIES_CONF="${CONFIG_DIR}/strategies.conf" -HTTP_STRATEGIES_CONF="${CONFIG_DIR}/http_strategies.conf" CURRENT_STRATEGY_FILE="${CONFIG_DIR}/current_strategy" QUIC_STRATEGIES_CONF="${CONFIG_DIR}/quic_strategies.conf" QUIC_STRATEGY_FILE="${CONFIG_DIR}/quic_strategy.conf" @@ -387,7 +386,7 @@ verify_binary() { check_kernel_module() { local module=$1 - if lsmod | grep -q "^${module}"; then + if lsmod | grep -q "^${module} "; then return 0 else return 1 diff --git a/z2k.sh b/z2k.sh index 54c4f0a..9ccf99d 100644 --- a/z2k.sh +++ b/z2k.sh @@ -243,7 +243,7 @@ quic_5.bin quic_test_00.bin " - echo "$files" | while read -r file; do + while read -r file; do [ -z "$file" ] && continue local url="${GITHUB_RAW}/files/fake/${file}" local output="${fake_dir}/${file}" @@ -252,7 +252,9 @@ quic_test_00.bin else die "Ошибка загрузки files/fake/${file}" fi - done + done <